1 | /* |
2 | * Copyright © 2007,2008,2009,2010 Red Hat, Inc. |
3 | * Copyright © 2012 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Red Hat Author(s): Behdad Esfahbod |
26 | * Google Author(s): Behdad Esfahbod |
27 | */ |
28 | |
29 | #ifndef HB_OPEN_TYPE_HH |
30 | #define HB_OPEN_TYPE_HH |
31 | |
32 | #include "hb.hh" |
33 | #include "hb-blob.hh" |
34 | #include "hb-face.hh" |
35 | #include "hb-machinery.hh" |
36 | #include "hb-subset.hh" |
37 | |
38 | |
39 | namespace OT { |
40 | |
41 | |
42 | /* |
43 | * |
44 | * The OpenType Font File: Data Types |
45 | */ |
46 | |
47 | |
48 | /* "The following data types are used in the OpenType font file. |
49 | * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ |
50 | |
51 | /* |
52 | * Int types |
53 | */ |
54 | |
55 | /* Integer types in big-endian order and no alignment requirement */ |
56 | template <typename Type, unsigned int Size> |
57 | struct IntType |
58 | { |
59 | typedef Type type; |
60 | typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type; |
61 | |
62 | IntType& operator = (wide_type i) { v = i; return *this; } |
63 | operator wide_type () const { return v; } |
64 | bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } |
65 | bool operator != (const IntType &o) const { return !(*this == o); } |
66 | |
67 | IntType& operator += (unsigned count) { *this = *this + count; return *this; } |
68 | IntType& operator -= (unsigned count) { *this = *this - count; return *this; } |
69 | IntType& operator ++ () { *this += 1; return *this; } |
70 | IntType& operator -- () { *this -= 1; return *this; } |
71 | IntType operator ++ (int) { IntType c (*this); ++*this; return c; } |
72 | IntType operator -- (int) { IntType c (*this); --*this; return c; } |
73 | |
74 | HB_INTERNAL static int cmp (const IntType *a, const IntType *b) |
75 | { return b->cmp (*a); } |
76 | template <typename Type2> |
77 | int cmp (Type2 a) const |
78 | { |
79 | Type b = v; |
80 | if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) |
81 | return (int) a - (int) b; |
82 | else |
83 | return a < b ? -1 : a == b ? 0 : +1; |
84 | } |
85 | bool sanitize (hb_sanitize_context_t *c) const |
86 | { |
87 | TRACE_SANITIZE (this); |
88 | return_trace (likely (c->check_struct (this))); |
89 | } |
90 | protected: |
91 | BEInt<Type, Size> v; |
92 | public: |
93 | DEFINE_SIZE_STATIC (Size); |
94 | }; |
95 | |
96 | typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */ |
97 | typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */ |
98 | typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */ |
99 | typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */ |
100 | typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */ |
101 | typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */ |
102 | /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. |
103 | * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ |
104 | typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ |
105 | |
106 | /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ |
107 | typedef HBINT16 FWORD; |
108 | |
109 | /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ |
110 | typedef HBINT32 FWORD32; |
111 | |
112 | /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ |
113 | typedef HBUINT16 UFWORD; |
114 | |
115 | /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ |
116 | struct F2DOT14 : HBINT16 |
117 | { |
118 | F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } |
119 | // 16384 means 1<<14 |
120 | float to_float () const { return ((int32_t) v) / 16384.f; } |
121 | void set_float (float f) { v = roundf (f * 16384.f); } |
122 | public: |
123 | DEFINE_SIZE_STATIC (2); |
124 | }; |
125 | |
126 | /* 32-bit signed fixed-point number (16.16). */ |
127 | struct HBFixed : HBINT32 |
128 | { |
129 | HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } |
130 | // 65536 means 1<<16 |
131 | float to_float () const { return ((int32_t) v) / 65536.f; } |
132 | void set_float (float f) { v = roundf (f * 65536.f); } |
133 | public: |
134 | DEFINE_SIZE_STATIC (4); |
135 | }; |
136 | |
137 | /* Date represented in number of seconds since 12:00 midnight, January 1, |
138 | * 1904. The value is represented as a signed 64-bit integer. */ |
139 | struct LONGDATETIME |
140 | { |
141 | bool sanitize (hb_sanitize_context_t *c) const |
142 | { |
143 | TRACE_SANITIZE (this); |
144 | return_trace (likely (c->check_struct (this))); |
145 | } |
146 | protected: |
147 | HBINT32 major; |
148 | HBUINT32 minor; |
149 | public: |
150 | DEFINE_SIZE_STATIC (8); |
151 | }; |
152 | |
153 | /* Array of four uint8s (length = 32 bits) used to identify a script, language |
154 | * system, feature, or baseline */ |
155 | struct Tag : HBUINT32 |
156 | { |
157 | Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } |
158 | /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ |
159 | operator const char* () const { return reinterpret_cast<const char *> (&this->v); } |
160 | operator char* () { return reinterpret_cast<char *> (&this->v); } |
161 | public: |
162 | DEFINE_SIZE_STATIC (4); |
163 | }; |
164 | |
165 | /* Glyph index number, same as uint16 (length = 16 bits) */ |
166 | struct HBGlyphID : HBUINT16 |
167 | { |
168 | HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } |
169 | }; |
170 | |
171 | /* Script/language-system/feature index */ |
172 | struct Index : HBUINT16 { |
173 | static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; |
174 | Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } |
175 | }; |
176 | DECLARE_NULL_NAMESPACE_BYTES (OT, Index); |
177 | |
178 | typedef Index NameID; |
179 | |
180 | /* Offset, Null offset = 0 */ |
181 | template <typename Type, bool has_null=true> |
182 | struct Offset : Type |
183 | { |
184 | Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } |
185 | |
186 | typedef Type type; |
187 | |
188 | bool is_null () const { return has_null && 0 == *this; } |
189 | |
190 | void *serialize (hb_serialize_context_t *c, const void *base) |
191 | { |
192 | void *t = c->start_embed<void> (); |
193 | c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); |
194 | return t; |
195 | } |
196 | |
197 | public: |
198 | DEFINE_SIZE_STATIC (sizeof (Type)); |
199 | }; |
200 | |
201 | typedef Offset<HBUINT16> Offset16; |
202 | typedef Offset<HBUINT32> Offset32; |
203 | |
204 | |
205 | /* CheckSum */ |
206 | struct CheckSum : HBUINT32 |
207 | { |
208 | CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } |
209 | |
210 | /* This is reference implementation from the spec. */ |
211 | static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) |
212 | { |
213 | uint32_t Sum = 0L; |
214 | assert (0 == (Length & 3)); |
215 | const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; |
216 | |
217 | while (Table < EndPtr) |
218 | Sum += *Table++; |
219 | return Sum; |
220 | } |
221 | |
222 | /* Note: data should be 4byte aligned and have 4byte padding at the end. */ |
223 | void set_for_data (const void *data, unsigned int length) |
224 | { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } |
225 | |
226 | public: |
227 | DEFINE_SIZE_STATIC (4); |
228 | }; |
229 | |
230 | |
231 | /* |
232 | * Version Numbers |
233 | */ |
234 | |
235 | template <typename FixedType=HBUINT16> |
236 | struct FixedVersion |
237 | { |
238 | uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } |
239 | |
240 | bool sanitize (hb_sanitize_context_t *c) const |
241 | { |
242 | TRACE_SANITIZE (this); |
243 | return_trace (c->check_struct (this)); |
244 | } |
245 | |
246 | FixedType major; |
247 | FixedType minor; |
248 | public: |
249 | DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); |
250 | }; |
251 | |
252 | |
253 | /* |
254 | * Template subclasses of Offset that do the dereferencing. |
255 | * Use: (base+offset) |
256 | */ |
257 | |
258 | template <typename Type, bool has_null> |
259 | struct _hb_has_null |
260 | { |
261 | static const Type *get_null () { return nullptr; } |
262 | static Type *get_crap () { return nullptr; } |
263 | }; |
264 | template <typename Type> |
265 | struct _hb_has_null<Type, true> |
266 | { |
267 | static const Type *get_null () { return &Null (Type); } |
268 | static Type *get_crap () { return &Crap (Type); } |
269 | }; |
270 | |
271 | template <typename Type, typename OffsetType=HBUINT16, bool has_null=true> |
272 | struct OffsetTo : Offset<OffsetType, has_null> |
273 | { |
274 | HB_DELETE_COPY_ASSIGN (OffsetTo); |
275 | OffsetTo () = default; |
276 | |
277 | OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } |
278 | |
279 | const Type& operator () (const void *base) const |
280 | { |
281 | if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); |
282 | return StructAtOffset<const Type> (base, *this); |
283 | } |
284 | Type& operator () (void *base) const |
285 | { |
286 | if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); |
287 | return StructAtOffset<Type> (base, *this); |
288 | } |
289 | |
290 | template <typename Base, |
291 | hb_enable_if (hb_is_convertible (const Base, const void *))> |
292 | friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } |
293 | template <typename Base, |
294 | hb_enable_if (hb_is_convertible (const Base, const void *))> |
295 | friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } |
296 | template <typename Base, |
297 | hb_enable_if (hb_is_convertible (Base, void *))> |
298 | friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } |
299 | template <typename Base, |
300 | hb_enable_if (hb_is_convertible (Base, void *))> |
301 | friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } |
302 | |
303 | Type& serialize (hb_serialize_context_t *c, const void *base) |
304 | { |
305 | return * (Type *) Offset<OffsetType>::serialize (c, base); |
306 | } |
307 | |
308 | template <typename ...Ts> |
309 | bool serialize_subset (hb_subset_context_t *c, |
310 | const OffsetTo& src, |
311 | const void *src_base, |
312 | const void *dst_base, |
313 | Ts&&... ds) |
314 | { |
315 | *this = 0; |
316 | if (src.is_null ()) |
317 | return false; |
318 | |
319 | auto *s = c->serializer; |
320 | |
321 | s->push (); |
322 | |
323 | bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...); |
324 | |
325 | if (ret || !has_null) |
326 | s->add_link (*this, s->pop_pack (), dst_base); |
327 | else |
328 | s->pop_discard (); |
329 | |
330 | return ret; |
331 | } |
332 | |
333 | /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ |
334 | template <typename ...Ts> |
335 | bool serialize_copy (hb_serialize_context_t *c, |
336 | const OffsetTo& src, |
337 | const void *src_base, |
338 | const void *dst_base, |
339 | Ts&&... ds) |
340 | { |
341 | *this = 0; |
342 | if (src.is_null ()) |
343 | return false; |
344 | |
345 | c->push (); |
346 | |
347 | bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...); |
348 | |
349 | c->add_link (*this, c->pop_pack (), dst_base); |
350 | |
351 | return ret; |
352 | } |
353 | |
354 | bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const |
355 | { |
356 | TRACE_SANITIZE (this); |
357 | if (unlikely (!c->check_struct (this))) return_trace (false); |
358 | if (unlikely (this->is_null ())) return_trace (true); |
359 | if (unlikely (!c->check_range (base, *this))) return_trace (false); |
360 | return_trace (true); |
361 | } |
362 | |
363 | template <typename ...Ts> |
364 | bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const |
365 | { |
366 | TRACE_SANITIZE (this); |
367 | return_trace (sanitize_shallow (c, base) && |
368 | (this->is_null () || |
369 | c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) || |
370 | neuter (c))); |
371 | } |
372 | |
373 | /* Set the offset to Null */ |
374 | bool neuter (hb_sanitize_context_t *c) const |
375 | { |
376 | if (!has_null) return false; |
377 | return c->try_set (this, 0); |
378 | } |
379 | DEFINE_SIZE_STATIC (sizeof (OffsetType)); |
380 | }; |
381 | /* Partial specializations. */ |
382 | template <typename Type, bool has_null=true> |
383 | using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>; |
384 | template <typename Type, typename OffsetType=HBUINT16> |
385 | using NNOffsetTo = OffsetTo<Type, OffsetType, false>; |
386 | template <typename Type> |
387 | using LNNOffsetTo = LOffsetTo<Type, false>; |
388 | |
389 | |
390 | /* |
391 | * Array Types |
392 | */ |
393 | |
394 | template <typename Type> |
395 | struct UnsizedArrayOf |
396 | { |
397 | typedef Type item_t; |
398 | static constexpr unsigned item_size = hb_static_size (Type); |
399 | |
400 | HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); |
401 | |
402 | const Type& operator [] (int i_) const |
403 | { |
404 | unsigned int i = (unsigned int) i_; |
405 | const Type *p = &arrayZ[i]; |
406 | if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ |
407 | return *p; |
408 | } |
409 | Type& operator [] (int i_) |
410 | { |
411 | unsigned int i = (unsigned int) i_; |
412 | Type *p = &arrayZ[i]; |
413 | if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ |
414 | return *p; |
415 | } |
416 | |
417 | unsigned int get_size (unsigned int len) const |
418 | { return len * Type::static_size; } |
419 | |
420 | template <typename T> operator T * () { return arrayZ; } |
421 | template <typename T> operator const T * () const { return arrayZ; } |
422 | hb_array_t<Type> as_array (unsigned int len) |
423 | { return hb_array (arrayZ, len); } |
424 | hb_array_t<const Type> as_array (unsigned int len) const |
425 | { return hb_array (arrayZ, len); } |
426 | operator hb_array_t< Type> () { return as_array (); } |
427 | operator hb_array_t<const Type> () const { return as_array (); } |
428 | |
429 | template <typename T> |
430 | Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) |
431 | { return *as_array (len).lsearch (x, ¬_found); } |
432 | template <typename T> |
433 | const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const |
434 | { return *as_array (len).lsearch (x, ¬_found); } |
435 | |
436 | void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) |
437 | { as_array (len).qsort (start, end); } |
438 | |
439 | bool serialize (hb_serialize_context_t *c, unsigned int items_len) |
440 | { |
441 | TRACE_SERIALIZE (this); |
442 | if (unlikely (!c->extend (*this, items_len))) return_trace (false); |
443 | return_trace (true); |
444 | } |
445 | template <typename Iterator, |
446 | hb_requires (hb_is_source_of (Iterator, Type))> |
447 | bool serialize (hb_serialize_context_t *c, Iterator items) |
448 | { |
449 | TRACE_SERIALIZE (this); |
450 | unsigned count = items.len (); |
451 | if (unlikely (!serialize (c, count))) return_trace (false); |
452 | /* TODO Umm. Just exhaust the iterator instead? Being extra |
453 | * cautious right now.. */ |
454 | for (unsigned i = 0; i < count; i++, ++items) |
455 | arrayZ[i] = *items; |
456 | return_trace (true); |
457 | } |
458 | |
459 | UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const |
460 | { |
461 | TRACE_SERIALIZE (this); |
462 | auto *out = c->start_embed (this); |
463 | if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); |
464 | return_trace (out); |
465 | } |
466 | |
467 | template <typename ...Ts> |
468 | bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const |
469 | { |
470 | TRACE_SANITIZE (this); |
471 | if (unlikely (!sanitize_shallow (c, count))) return_trace (false); |
472 | if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); |
473 | for (unsigned int i = 0; i < count; i++) |
474 | if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) |
475 | return_trace (false); |
476 | return_trace (true); |
477 | } |
478 | |
479 | bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const |
480 | { |
481 | TRACE_SANITIZE (this); |
482 | return_trace (c->check_array (arrayZ, count)); |
483 | } |
484 | |
485 | public: |
486 | Type arrayZ[HB_VAR_ARRAY]; |
487 | public: |
488 | DEFINE_SIZE_UNBOUNDED (0); |
489 | }; |
490 | |
491 | /* Unsized array of offset's */ |
492 | template <typename Type, typename OffsetType, bool has_null=true> |
493 | using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; |
494 | |
495 | /* Unsized array of offsets relative to the beginning of the array itself. */ |
496 | template <typename Type, typename OffsetType, bool has_null=true> |
497 | struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> |
498 | { |
499 | const Type& operator [] (int i_) const |
500 | { |
501 | unsigned int i = (unsigned int) i_; |
502 | const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; |
503 | if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ |
504 | return this+*p; |
505 | } |
506 | Type& operator [] (int i_) |
507 | { |
508 | unsigned int i = (unsigned int) i_; |
509 | const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; |
510 | if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ |
511 | return this+*p; |
512 | } |
513 | |
514 | template <typename ...Ts> |
515 | bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const |
516 | { |
517 | TRACE_SANITIZE (this); |
518 | return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null> |
519 | ::sanitize (c, count, this, hb_forward<Ts> (ds)...))); |
520 | } |
521 | }; |
522 | |
523 | /* An array with sorted elements. Supports binary searching. */ |
524 | template <typename Type> |
525 | struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> |
526 | { |
527 | hb_sorted_array_t<Type> as_array (unsigned int len) |
528 | { return hb_sorted_array (this->arrayZ, len); } |
529 | hb_sorted_array_t<const Type> as_array (unsigned int len) const |
530 | { return hb_sorted_array (this->arrayZ, len); } |
531 | operator hb_sorted_array_t<Type> () { return as_array (); } |
532 | operator hb_sorted_array_t<const Type> () const { return as_array (); } |
533 | |
534 | template <typename T> |
535 | Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) |
536 | { return *as_array (len).bsearch (x, ¬_found); } |
537 | template <typename T> |
538 | const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const |
539 | { return *as_array (len).bsearch (x, ¬_found); } |
540 | template <typename T> |
541 | bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, |
542 | hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, |
543 | unsigned int to_store = (unsigned int) -1) const |
544 | { return as_array (len).bfind (x, i, not_found, to_store); } |
545 | }; |
546 | |
547 | |
548 | /* An array with a number of elements. */ |
549 | template <typename Type, typename LenType=HBUINT16> |
550 | struct ArrayOf |
551 | { |
552 | typedef Type item_t; |
553 | static constexpr unsigned item_size = hb_static_size (Type); |
554 | |
555 | HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); |
556 | |
557 | const Type& operator [] (int i_) const |
558 | { |
559 | unsigned int i = (unsigned int) i_; |
560 | if (unlikely (i >= len)) return Null (Type); |
561 | return arrayZ[i]; |
562 | } |
563 | Type& operator [] (int i_) |
564 | { |
565 | unsigned int i = (unsigned int) i_; |
566 | if (unlikely (i >= len)) return Crap (Type); |
567 | return arrayZ[i]; |
568 | } |
569 | |
570 | unsigned int get_size () const |
571 | { return len.static_size + len * Type::static_size; } |
572 | |
573 | explicit operator bool () const { return len; } |
574 | |
575 | void pop () { len--; } |
576 | |
577 | hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } |
578 | hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } |
579 | |
580 | /* Iterator. */ |
581 | typedef hb_array_t<const Type> iter_t; |
582 | typedef hb_array_t< Type> writer_t; |
583 | iter_t iter () const { return as_array (); } |
584 | writer_t writer () { return as_array (); } |
585 | operator iter_t () const { return iter (); } |
586 | operator writer_t () { return writer (); } |
587 | |
588 | hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const |
589 | { return as_array ().sub_array (start_offset, count); } |
590 | hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const |
591 | { return as_array ().sub_array (start_offset, count); } |
592 | hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) |
593 | { return as_array ().sub_array (start_offset, count); } |
594 | hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) |
595 | { return as_array ().sub_array (start_offset, count); } |
596 | |
597 | bool serialize (hb_serialize_context_t *c, unsigned int items_len) |
598 | { |
599 | TRACE_SERIALIZE (this); |
600 | if (unlikely (!c->extend_min (*this))) return_trace (false); |
601 | c->check_assign (len, items_len); |
602 | if (unlikely (!c->extend (*this))) return_trace (false); |
603 | return_trace (true); |
604 | } |
605 | template <typename Iterator, |
606 | hb_requires (hb_is_source_of (Iterator, Type))> |
607 | bool serialize (hb_serialize_context_t *c, Iterator items) |
608 | { |
609 | TRACE_SERIALIZE (this); |
610 | unsigned count = items.len (); |
611 | if (unlikely (!serialize (c, count))) return_trace (false); |
612 | /* TODO Umm. Just exhaust the iterator instead? Being extra |
613 | * cautious right now.. */ |
614 | for (unsigned i = 0; i < count; i++, ++items) |
615 | arrayZ[i] = *items; |
616 | return_trace (true); |
617 | } |
618 | |
619 | Type* serialize_append (hb_serialize_context_t *c) |
620 | { |
621 | TRACE_SERIALIZE (this); |
622 | len++; |
623 | if (unlikely (!len || !c->extend (*this))) |
624 | { |
625 | len--; |
626 | return_trace (nullptr); |
627 | } |
628 | return_trace (&arrayZ[len - 1]); |
629 | } |
630 | |
631 | ArrayOf* copy (hb_serialize_context_t *c) const |
632 | { |
633 | TRACE_SERIALIZE (this); |
634 | auto *out = c->start_embed (this); |
635 | if (unlikely (!c->extend_min (out))) return_trace (nullptr); |
636 | c->check_assign (out->len, len); |
637 | if (unlikely (!as_array ().copy (c))) return_trace (nullptr); |
638 | return_trace (out); |
639 | } |
640 | |
641 | template <typename ...Ts> |
642 | bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const |
643 | { |
644 | TRACE_SANITIZE (this); |
645 | if (unlikely (!sanitize_shallow (c))) return_trace (false); |
646 | if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); |
647 | unsigned int count = len; |
648 | for (unsigned int i = 0; i < count; i++) |
649 | if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) |
650 | return_trace (false); |
651 | return_trace (true); |
652 | } |
653 | |
654 | template <typename T> |
655 | Type &lsearch (const T &x, Type ¬_found = Crap (Type)) |
656 | { return *as_array ().lsearch (x, ¬_found); } |
657 | template <typename T> |
658 | const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const |
659 | { return *as_array ().lsearch (x, ¬_found); } |
660 | |
661 | void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) |
662 | { as_array ().qsort (start, end); } |
663 | |
664 | bool sanitize_shallow (hb_sanitize_context_t *c) const |
665 | { |
666 | TRACE_SANITIZE (this); |
667 | return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); |
668 | } |
669 | |
670 | public: |
671 | LenType len; |
672 | Type arrayZ[HB_VAR_ARRAY]; |
673 | public: |
674 | DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); |
675 | }; |
676 | template <typename Type> |
677 | using LArrayOf = ArrayOf<Type, HBUINT32>; |
678 | using PString = ArrayOf<HBUINT8, HBUINT8>; |
679 | |
680 | /* Array of Offset's */ |
681 | template <typename Type> |
682 | using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>; |
683 | template <typename Type> |
684 | using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>; |
685 | template <typename Type> |
686 | using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; |
687 | |
688 | /* Array of offsets relative to the beginning of the array itself. */ |
689 | template <typename Type> |
690 | struct OffsetListOf : OffsetArrayOf<Type> |
691 | { |
692 | const Type& operator [] (int i_) const |
693 | { |
694 | unsigned int i = (unsigned int) i_; |
695 | if (unlikely (i >= this->len)) return Null (Type); |
696 | return this+this->arrayZ[i]; |
697 | } |
698 | const Type& operator [] (int i_) |
699 | { |
700 | unsigned int i = (unsigned int) i_; |
701 | if (unlikely (i >= this->len)) return Crap (Type); |
702 | return this+this->arrayZ[i]; |
703 | } |
704 | |
705 | bool subset (hb_subset_context_t *c) const |
706 | { |
707 | TRACE_SUBSET (this); |
708 | struct OffsetListOf<Type> *out = c->serializer->embed (*this); |
709 | if (unlikely (!out)) return_trace (false); |
710 | unsigned int count = this->len; |
711 | for (unsigned int i = 0; i < count; i++) |
712 | out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); |
713 | return_trace (true); |
714 | } |
715 | |
716 | template <typename ...Ts> |
717 | bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const |
718 | { |
719 | TRACE_SANITIZE (this); |
720 | return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...)); |
721 | } |
722 | }; |
723 | |
724 | /* An array starting at second element. */ |
725 | template <typename Type, typename LenType=HBUINT16> |
726 | struct HeadlessArrayOf |
727 | { |
728 | static constexpr unsigned item_size = Type::static_size; |
729 | |
730 | HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); |
731 | |
732 | const Type& operator [] (int i_) const |
733 | { |
734 | unsigned int i = (unsigned int) i_; |
735 | if (unlikely (i >= lenP1 || !i)) return Null (Type); |
736 | return arrayZ[i-1]; |
737 | } |
738 | Type& operator [] (int i_) |
739 | { |
740 | unsigned int i = (unsigned int) i_; |
741 | if (unlikely (i >= lenP1 || !i)) return Crap (Type); |
742 | return arrayZ[i-1]; |
743 | } |
744 | unsigned int get_size () const |
745 | { return lenP1.static_size + get_length () * Type::static_size; } |
746 | |
747 | unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } |
748 | |
749 | hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } |
750 | hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } |
751 | |
752 | /* Iterator. */ |
753 | typedef hb_array_t<const Type> iter_t; |
754 | typedef hb_array_t< Type> writer_t; |
755 | iter_t iter () const { return as_array (); } |
756 | writer_t writer () { return as_array (); } |
757 | operator iter_t () const { return iter (); } |
758 | operator writer_t () { return writer (); } |
759 | |
760 | bool serialize (hb_serialize_context_t *c, unsigned int items_len) |
761 | { |
762 | TRACE_SERIALIZE (this); |
763 | if (unlikely (!c->extend_min (*this))) return_trace (false); |
764 | c->check_assign (lenP1, items_len + 1); |
765 | if (unlikely (!c->extend (*this))) return_trace (false); |
766 | return_trace (true); |
767 | } |
768 | template <typename Iterator, |
769 | hb_requires (hb_is_source_of (Iterator, Type))> |
770 | bool serialize (hb_serialize_context_t *c, Iterator items) |
771 | { |
772 | TRACE_SERIALIZE (this); |
773 | unsigned count = items.len (); |
774 | if (unlikely (!serialize (c, count))) return_trace (false); |
775 | /* TODO Umm. Just exhaust the iterator instead? Being extra |
776 | * cautious right now.. */ |
777 | for (unsigned i = 0; i < count; i++, ++items) |
778 | arrayZ[i] = *items; |
779 | return_trace (true); |
780 | } |
781 | |
782 | template <typename ...Ts> |
783 | bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const |
784 | { |
785 | TRACE_SANITIZE (this); |
786 | if (unlikely (!sanitize_shallow (c))) return_trace (false); |
787 | if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); |
788 | unsigned int count = get_length (); |
789 | for (unsigned int i = 0; i < count; i++) |
790 | if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) |
791 | return_trace (false); |
792 | return_trace (true); |
793 | } |
794 | |
795 | private: |
796 | bool sanitize_shallow (hb_sanitize_context_t *c) const |
797 | { |
798 | TRACE_SANITIZE (this); |
799 | return_trace (lenP1.sanitize (c) && |
800 | (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); |
801 | } |
802 | |
803 | public: |
804 | LenType lenP1; |
805 | Type arrayZ[HB_VAR_ARRAY]; |
806 | public: |
807 | DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); |
808 | }; |
809 | |
810 | /* An array storing length-1. */ |
811 | template <typename Type, typename LenType=HBUINT16> |
812 | struct ArrayOfM1 |
813 | { |
814 | HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); |
815 | |
816 | const Type& operator [] (int i_) const |
817 | { |
818 | unsigned int i = (unsigned int) i_; |
819 | if (unlikely (i > lenM1)) return Null (Type); |
820 | return arrayZ[i]; |
821 | } |
822 | Type& operator [] (int i_) |
823 | { |
824 | unsigned int i = (unsigned int) i_; |
825 | if (unlikely (i > lenM1)) return Crap (Type); |
826 | return arrayZ[i]; |
827 | } |
828 | unsigned int get_size () const |
829 | { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } |
830 | |
831 | template <typename ...Ts> |
832 | bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const |
833 | { |
834 | TRACE_SANITIZE (this); |
835 | if (unlikely (!sanitize_shallow (c))) return_trace (false); |
836 | unsigned int count = lenM1 + 1; |
837 | for (unsigned int i = 0; i < count; i++) |
838 | if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) |
839 | return_trace (false); |
840 | return_trace (true); |
841 | } |
842 | |
843 | private: |
844 | bool sanitize_shallow (hb_sanitize_context_t *c) const |
845 | { |
846 | TRACE_SANITIZE (this); |
847 | return_trace (lenM1.sanitize (c) && |
848 | (c->check_array (arrayZ, lenM1 + 1))); |
849 | } |
850 | |
851 | public: |
852 | LenType lenM1; |
853 | Type arrayZ[HB_VAR_ARRAY]; |
854 | public: |
855 | DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); |
856 | }; |
857 | |
858 | /* An array with sorted elements. Supports binary searching. */ |
859 | template <typename Type, typename LenType=HBUINT16> |
860 | struct SortedArrayOf : ArrayOf<Type, LenType> |
861 | { |
862 | hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } |
863 | hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } |
864 | |
865 | /* Iterator. */ |
866 | typedef hb_sorted_array_t<const Type> iter_t; |
867 | typedef hb_sorted_array_t< Type> writer_t; |
868 | iter_t iter () const { return as_array (); } |
869 | writer_t writer () { return as_array (); } |
870 | operator iter_t () const { return iter (); } |
871 | operator writer_t () { return writer (); } |
872 | |
873 | hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const |
874 | { return as_array ().sub_array (start_offset, count); } |
875 | hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const |
876 | { return as_array ().sub_array (start_offset, count); } |
877 | hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) |
878 | { return as_array ().sub_array (start_offset, count); } |
879 | hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) |
880 | { return as_array ().sub_array (start_offset, count); } |
881 | |
882 | bool serialize (hb_serialize_context_t *c, unsigned int items_len) |
883 | { |
884 | TRACE_SERIALIZE (this); |
885 | bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); |
886 | return_trace (ret); |
887 | } |
888 | template <typename Iterator, |
889 | hb_requires (hb_is_sorted_source_of (Iterator, Type))> |
890 | bool serialize (hb_serialize_context_t *c, Iterator items) |
891 | { |
892 | TRACE_SERIALIZE (this); |
893 | bool ret = ArrayOf<Type, LenType>::serialize (c, items); |
894 | return_trace (ret); |
895 | } |
896 | |
897 | template <typename T> |
898 | Type &bsearch (const T &x, Type ¬_found = Crap (Type)) |
899 | { return *as_array ().bsearch (x, ¬_found); } |
900 | template <typename T> |
901 | const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const |
902 | { return *as_array ().bsearch (x, ¬_found); } |
903 | template <typename T> |
904 | bool bfind (const T &x, unsigned int *i = nullptr, |
905 | hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, |
906 | unsigned int to_store = (unsigned int) -1) const |
907 | { return as_array ().bfind (x, i, not_found, to_store); } |
908 | }; |
909 | |
910 | /* |
911 | * Binary-search arrays |
912 | */ |
913 | |
914 | template <typename LenType=HBUINT16> |
915 | struct |
916 | { |
917 | () const { return len; } |
918 | |
919 | bool (hb_sanitize_context_t *c) const |
920 | { |
921 | TRACE_SANITIZE (this); |
922 | return_trace (c->check_struct (this)); |
923 | } |
924 | |
925 | BinSearchHeader& (unsigned int v) |
926 | { |
927 | len = v; |
928 | assert (len == v); |
929 | entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; |
930 | searchRange = 16 * (1u << entrySelector); |
931 | rangeShift = v * 16 > searchRange |
932 | ? 16 * v - searchRange |
933 | : 0; |
934 | return *this; |
935 | } |
936 | |
937 | protected: |
938 | LenType ; |
939 | LenType ; |
940 | LenType ; |
941 | LenType ; |
942 | |
943 | public: |
944 | DEFINE_SIZE_STATIC (8); |
945 | }; |
946 | |
947 | template <typename Type, typename LenType=HBUINT16> |
948 | using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; |
949 | |
950 | |
951 | struct |
952 | { |
953 | |
954 | bool (hb_sanitize_context_t *c) const |
955 | { |
956 | TRACE_SANITIZE (this); |
957 | return_trace (c->check_struct (this)); |
958 | } |
959 | |
960 | HBUINT16 ; /* Size of a lookup unit for this search in bytes. */ |
961 | HBUINT16 ; /* Number of units of the preceding size to be searched. */ |
962 | HBUINT16 ; /* The value of unitSize times the largest power of 2 |
963 | * that is less than or equal to the value of nUnits. */ |
964 | HBUINT16 ; /* The log base 2 of the largest power of 2 less than |
965 | * or equal to the value of nUnits. */ |
966 | HBUINT16 ; /* The value of unitSize times the difference of the |
967 | * value of nUnits minus the largest power of 2 less |
968 | * than or equal to the value of nUnits. */ |
969 | public: |
970 | DEFINE_SIZE_STATIC (10); |
971 | }; |
972 | |
973 | template <typename Type> |
974 | struct VarSizedBinSearchArrayOf |
975 | { |
976 | static constexpr unsigned item_size = Type::static_size; |
977 | |
978 | HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); |
979 | |
980 | bool last_is_terminator () const |
981 | { |
982 | if (unlikely (!header.nUnits)) return false; |
983 | |
984 | /* Gah. |
985 | * |
986 | * "The number of termination values that need to be included is table-specific. |
987 | * The value that indicates binary search termination is 0xFFFF." */ |
988 | const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); |
989 | unsigned int count = Type::TerminationWordCount; |
990 | for (unsigned int i = 0; i < count; i++) |
991 | if (words[i] != 0xFFFFu) |
992 | return false; |
993 | return true; |
994 | } |
995 | |
996 | const Type& operator [] (int i_) const |
997 | { |
998 | unsigned int i = (unsigned int) i_; |
999 | if (unlikely (i >= get_length ())) return Null (Type); |
1000 | return StructAtOffset<Type> (&bytesZ, i * header.unitSize); |
1001 | } |
1002 | Type& operator [] (int i_) |
1003 | { |
1004 | unsigned int i = (unsigned int) i_; |
1005 | if (unlikely (i >= get_length ())) return Crap (Type); |
1006 | return StructAtOffset<Type> (&bytesZ, i * header.unitSize); |
1007 | } |
1008 | unsigned int get_length () const |
1009 | { return header.nUnits - last_is_terminator (); } |
1010 | unsigned int get_size () const |
1011 | { return header.static_size + header.nUnits * header.unitSize; } |
1012 | |
1013 | template <typename ...Ts> |
1014 | bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const |
1015 | { |
1016 | TRACE_SANITIZE (this); |
1017 | if (unlikely (!sanitize_shallow (c))) return_trace (false); |
1018 | if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); |
1019 | unsigned int count = get_length (); |
1020 | for (unsigned int i = 0; i < count; i++) |
1021 | if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...))) |
1022 | return_trace (false); |
1023 | return_trace (true); |
1024 | } |
1025 | |
1026 | template <typename T> |
1027 | const Type *bsearch (const T &key) const |
1028 | { |
1029 | unsigned int size = header.unitSize; |
1030 | int min = 0, max = (int) get_length () - 1; |
1031 | while (min <= max) |
1032 | { |
1033 | int mid = ((unsigned int) min + (unsigned int) max) / 2; |
1034 | const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); |
1035 | int c = p->cmp (key); |
1036 | if (c < 0) max = mid - 1; |
1037 | else if (c > 0) min = mid + 1; |
1038 | else return p; |
1039 | } |
1040 | return nullptr; |
1041 | } |
1042 | |
1043 | private: |
1044 | bool sanitize_shallow (hb_sanitize_context_t *c) const |
1045 | { |
1046 | TRACE_SANITIZE (this); |
1047 | return_trace (header.sanitize (c) && |
1048 | Type::static_size <= header.unitSize && |
1049 | c->check_range (bytesZ.arrayZ, |
1050 | header.nUnits, |
1051 | header.unitSize)); |
1052 | } |
1053 | |
1054 | protected: |
1055 | VarSizedBinSearchHeader ; |
1056 | UnsizedArrayOf<HBUINT8> bytesZ; |
1057 | public: |
1058 | DEFINE_SIZE_ARRAY (10, bytesZ); |
1059 | }; |
1060 | |
1061 | |
1062 | } /* namespace OT */ |
1063 | |
1064 | |
1065 | #endif /* HB_OPEN_TYPE_HH */ |
1066 | |