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