• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
operator =OT::IntType62   IntType& operator = (wide_type i) { v = i; return *this; }
operator wide_typeOT::IntType63   operator wide_type () const { return v; }
operator ==OT::IntType64   bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
operator !=OT::IntType65   bool operator != (const IntType &o) const { return !(*this == o); }
66 
operator +=OT::IntType67   IntType& operator += (unsigned count) { *this = *this + count; return *this; }
operator -=OT::IntType68   IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
operator ++OT::IntType69   IntType& operator ++ () { *this += 1; return *this; }
operator --OT::IntType70   IntType& operator -- () { *this -= 1; return *this; }
operator ++OT::IntType71   IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
operator --OT::IntType72   IntType operator -- (int) { IntType c (*this); --*this; return c; }
73 
cmpOT::IntType74   HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
75   { return b->cmp (*a); }
76   template <typename Type2>
cmpOT::IntType77   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   }
sanitizeOT::IntType85   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 {
operator =OT::F2DOT14118   F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
119   // 16384 means 1<<14
to_floatOT::F2DOT14120   float to_float () const  { return ((int32_t) v) / 16384.f; }
set_floatOT::F2DOT14121   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 {
operator =OT::HBFixed129   HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
130   // 65536 means 1<<16
to_floatOT::HBFixed131   float to_float () const  { return ((int32_t) v) / 65536.f; }
set_floatOT::HBFixed132   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 {
sanitizeOT::LONGDATETIME141   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 {
operator =OT::Tag157   Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
158   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
operator const char*OT::Tag159   operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
operator char*OT::Tag160   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 {
operator =OT::HBGlyphID168   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;
operator =OT::Index174   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 {
operator =OT::Offset184   Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
185 
186   typedef Type type;
187 
is_nullOT::Offset188   bool is_null () const { return has_null && 0 == *this; }
189 
serializeOT::Offset190   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 {
operator =OT::CheckSum208   CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
209 
210   /* This is reference implementation from the spec. */
CalcTableChecksumOT::CheckSum211   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. */
set_for_dataOT::CheckSum223   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 {
to_intOT::FixedVersion238   uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
239 
sanitizeOT::FixedVersion240   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 {
get_nullOT::_hb_has_null261   static const Type *get_null () { return nullptr; }
get_crapOT::_hb_has_null262   static Type *get_crap ()       { return nullptr; }
263 };
264 template <typename Type>
265 struct _hb_has_null<Type, true>
266 {
get_nullOT::_hb_has_null267   static const Type *get_null () { return &Null (Type); }
get_crapOT::_hb_has_null268   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 
operator =OT::OffsetTo277   OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
278 
operator ()OT::OffsetTo279   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   }
operator ()OT::OffsetTo284   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 *))>
operator +(const Base & base,const OffsetTo & offset)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 *))>
operator +(const OffsetTo & offset,const Base & base)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 *))>
operator +(Base && base,OffsetTo & offset)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 *))>
operator +(OffsetTo & offset,Base && base)301   friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
302 
serializeOT::OffsetTo303   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>
serialize_subsetOT::OffsetTo309   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>
serialize_copyOT::OffsetTo335   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 
sanitize_shallowOT::OffsetTo354   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>
sanitizeOT::OffsetTo364   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 */
neuterOT::OffsetTo374   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 
operator []OT::UnsizedArrayOf402   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   }
operator []OT::UnsizedArrayOf409   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 
get_sizeOT::UnsizedArrayOf417   unsigned int get_size (unsigned int len) const
418   { return len * Type::static_size; }
419 
operator T*OT::UnsizedArrayOf420   template <typename T> operator T * () { return arrayZ; }
operator const T*OT::UnsizedArrayOf421   template <typename T> operator const T * () const { return arrayZ; }
as_arrayOT::UnsizedArrayOf422   hb_array_t<Type> as_array (unsigned int len)
423   { return hb_array (arrayZ, len); }
as_arrayOT::UnsizedArrayOf424   hb_array_t<const Type> as_array (unsigned int len) const
425   { return hb_array (arrayZ, len); }
operator hb_array_t<Type>OT::UnsizedArrayOf426   operator hb_array_t<      Type> ()       { return as_array (); }
operator hb_array_t<const Type>OT::UnsizedArrayOf427   operator hb_array_t<const Type> () const { return as_array (); }
428 
429   template <typename T>
lsearchOT::UnsizedArrayOf430   Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
431   { return *as_array (len).lsearch (x, &not_found); }
432   template <typename T>
lsearchOT::UnsizedArrayOf433   const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
434   { return *as_array (len).lsearch (x, &not_found); }
435 
qsortOT::UnsizedArrayOf436   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
437   { as_array (len).qsort (start, end); }
438 
serializeOT::UnsizedArrayOf439   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))>
serializeOT::UnsizedArrayOf447   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 
copyOT::UnsizedArrayOf459   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>
sanitizeOT::UnsizedArrayOf468   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 
sanitize_shallowOT::UnsizedArrayOf479   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 {
operator []OT::UnsizedOffsetListOf499   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   }
operator []OT::UnsizedOffsetListOf506   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>
sanitizeOT::UnsizedOffsetListOf515   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 {
as_arrayOT::SortedUnsizedArrayOf527   hb_sorted_array_t<Type> as_array (unsigned int len)
528   { return hb_sorted_array (this->arrayZ, len); }
as_arrayOT::SortedUnsizedArrayOf529   hb_sorted_array_t<const Type> as_array (unsigned int len) const
530   { return hb_sorted_array (this->arrayZ, len); }
operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf531   operator hb_sorted_array_t<Type> ()             { return as_array (); }
operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf532   operator hb_sorted_array_t<const Type> () const { return as_array (); }
533 
534   template <typename T>
bsearchOT::SortedUnsizedArrayOf535   Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
536   { return *as_array (len).bsearch (x, &not_found); }
537   template <typename T>
bsearchOT::SortedUnsizedArrayOf538   const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
539   { return *as_array (len).bsearch (x, &not_found); }
540   template <typename T>
bfindOT::SortedUnsizedArrayOf541   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 
operator []OT::ArrayOf557   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   }
operator []OT::ArrayOf563   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 
get_sizeOT::ArrayOf570   unsigned int get_size () const
571   { return len.static_size + len * Type::static_size; }
572 
operator boolOT::ArrayOf573   explicit operator bool () const { return len; }
574 
popOT::ArrayOf575   void pop () { len--; }
576 
as_arrayOT::ArrayOf577   hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, len); }
as_arrayOT::ArrayOf578   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;
iterOT::ArrayOf583     iter_t   iter () const { return as_array (); }
writerOT::ArrayOf584   writer_t writer ()       { return as_array (); }
operator iter_tOT::ArrayOf585   operator   iter_t () const { return   iter (); }
operator writer_tOT::ArrayOf586   operator writer_t ()       { return writer (); }
587 
sub_arrayOT::ArrayOf588   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
589   { return as_array ().sub_array (start_offset, count); }
sub_arrayOT::ArrayOf590   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); }
sub_arrayOT::ArrayOf592   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
593   { return as_array ().sub_array (start_offset, count); }
sub_arrayOT::ArrayOf594   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 
serializeOT::ArrayOf597   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))>
serializeOT::ArrayOf607   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 
serialize_appendOT::ArrayOf619   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 
copyOT::ArrayOf631   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>
sanitizeOT::ArrayOf642   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>
lsearchOT::ArrayOf655   Type &lsearch (const T &x, Type &not_found = Crap (Type))
656   { return *as_array ().lsearch (x, &not_found); }
657   template <typename T>
lsearchOT::ArrayOf658   const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
659   { return *as_array ().lsearch (x, &not_found); }
660 
qsortOT::ArrayOf661   void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
662   { as_array ().qsort (start, end); }
663 
sanitize_shallowOT::ArrayOf664   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 {
operator []OT::OffsetListOf692   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   }
operator []OT::OffsetListOf698   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 
subsetOT::OffsetListOf705   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>
sanitizeOT::OffsetListOf717   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 
operator []OT::HeadlessArrayOf732   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   }
operator []OT::HeadlessArrayOf738   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   }
get_sizeOT::HeadlessArrayOf744   unsigned int get_size () const
745   { return lenP1.static_size + get_length () * Type::static_size; }
746 
get_lengthOT::HeadlessArrayOf747   unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
748 
as_arrayOT::HeadlessArrayOf749   hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, get_length ()); }
as_arrayOT::HeadlessArrayOf750   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;
iterOT::HeadlessArrayOf755     iter_t   iter () const { return as_array (); }
writerOT::HeadlessArrayOf756   writer_t writer ()       { return as_array (); }
operator iter_tOT::HeadlessArrayOf757   operator   iter_t () const { return   iter (); }
operator writer_tOT::HeadlessArrayOf758   operator writer_t ()       { return writer (); }
759 
serializeOT::HeadlessArrayOf760   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))>
serializeOT::HeadlessArrayOf770   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>
sanitizeOT::HeadlessArrayOf783   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:
sanitize_shallowOT::HeadlessArrayOf796   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 
operator []OT::ArrayOfM1816   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   }
operator []OT::ArrayOfM1822   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   }
get_sizeOT::ArrayOfM1828   unsigned int get_size () const
829   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
830 
831   template <typename ...Ts>
sanitizeOT::ArrayOfM1832   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:
sanitize_shallowOT::ArrayOfM1844   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 {
as_arrayOT::SortedArrayOf862   hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
as_arrayOT::SortedArrayOf863   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;
iterOT::SortedArrayOf868     iter_t   iter () const { return as_array (); }
writerOT::SortedArrayOf869   writer_t writer ()       { return as_array (); }
operator iter_tOT::SortedArrayOf870   operator   iter_t () const { return   iter (); }
operator writer_tOT::SortedArrayOf871   operator writer_t ()       { return writer (); }
872 
sub_arrayOT::SortedArrayOf873   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); }
sub_arrayOT::SortedArrayOf875   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); }
sub_arrayOT::SortedArrayOf877   hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
878   { return as_array ().sub_array (start_offset, count); }
sub_arrayOT::SortedArrayOf879   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 
serializeOT::SortedArrayOf882   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))>
serializeOT::SortedArrayOf890   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>
bsearchOT::SortedArrayOf898   Type &bsearch (const T &x, Type &not_found = Crap (Type))
899   { return *as_array ().bsearch (x, &not_found); }
900   template <typename T>
bsearchOT::SortedArrayOf901   const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
902   { return *as_array ().bsearch (x, &not_found); }
903   template <typename T>
bfindOT::SortedArrayOf904   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 BinSearchHeader
916 {
operator uint32_tOT::BinSearchHeader917   operator uint32_t () const { return len; }
918 
sanitizeOT::BinSearchHeader919   bool sanitize (hb_sanitize_context_t *c) const
920   {
921     TRACE_SANITIZE (this);
922     return_trace (c->check_struct (this));
923   }
924 
operator =OT::BinSearchHeader925   BinSearchHeader& operator = (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	len;
939   LenType	searchRange;
940   LenType	entrySelector;
941   LenType	rangeShift;
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 VarSizedBinSearchHeader
952 {
953 
sanitizeOT::VarSizedBinSearchHeader954   bool sanitize (hb_sanitize_context_t *c) const
955   {
956     TRACE_SANITIZE (this);
957     return_trace (c->check_struct (this));
958   }
959 
960   HBUINT16	unitSize;	/* Size of a lookup unit for this search in bytes. */
961   HBUINT16	nUnits;		/* Number of units of the preceding size to be searched. */
962   HBUINT16	searchRange;	/* The value of unitSize times the largest power of 2
963 				 * that is less than or equal to the value of nUnits. */
964   HBUINT16	entrySelector;	/* The log base 2 of the largest power of 2 less than
965 				 * or equal to the value of nUnits. */
966   HBUINT16	rangeShift;	/* 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 
last_is_terminatorOT::VarSizedBinSearchArrayOf980   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 
operator []OT::VarSizedBinSearchArrayOf996   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   }
operator []OT::VarSizedBinSearchArrayOf1002   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   }
get_lengthOT::VarSizedBinSearchArrayOf1008   unsigned int get_length () const
1009   { return header.nUnits - last_is_terminator (); }
get_sizeOT::VarSizedBinSearchArrayOf1010   unsigned int get_size () const
1011   { return header.static_size + header.nUnits * header.unitSize; }
1012 
1013   template <typename ...Ts>
sanitizeOT::VarSizedBinSearchArrayOf1014   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>
bsearchOT::VarSizedBinSearchArrayOf1027   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:
sanitize_shallowOT::VarSizedBinSearchArrayOf1044   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	header;
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