• 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<Type, Size>& 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<Type,Size> &o) const { return (Type) v == (Type) o.v; }
operator !=OT::IntType65   bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
cmpOT::IntType66   HB_INTERNAL static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b)
67   { return b->cmp (*a); }
68   template <typename Type2>
cmpOT::IntType69   int cmp (Type2 a) const
70   {
71     Type b = v;
72     if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
73       return (int) a - (int) b;
74     else
75       return a < b ? -1 : a == b ? 0 : +1;
76   }
sanitizeOT::IntType77   bool sanitize (hb_sanitize_context_t *c) const
78   {
79     TRACE_SANITIZE (this);
80     return_trace (likely (c->check_struct (this)));
81   }
82   protected:
83   BEInt<Type, Size> v;
84   public:
85   DEFINE_SIZE_STATIC (Size);
86 };
87 
88 typedef IntType<uint8_t,  1> HBUINT8;	/* 8-bit unsigned integer. */
89 typedef IntType<int8_t,   1> HBINT8;	/* 8-bit signed integer. */
90 typedef IntType<uint16_t, 2> HBUINT16;	/* 16-bit unsigned integer. */
91 typedef IntType<int16_t,  2> HBINT16;	/* 16-bit signed integer. */
92 typedef IntType<uint32_t, 4> HBUINT32;	/* 32-bit unsigned integer. */
93 typedef IntType<int32_t,  4> HBINT32;	/* 32-bit signed integer. */
94 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
95  * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
96 typedef IntType<uint32_t, 3> HBUINT24;	/* 24-bit unsigned integer. */
97 
98 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
99 typedef HBINT16 FWORD;
100 
101 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
102 typedef HBINT32 FWORD32;
103 
104 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
105 typedef HBUINT16 UFWORD;
106 
107 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
108 struct F2DOT14 : HBINT16
109 {
operator =OT::F2DOT14110   F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
111   // 16384 means 1<<14
to_floatOT::F2DOT14112   float to_float () const  { return ((int32_t) v) / 16384.f; }
set_floatOT::F2DOT14113   void set_float (float f) { v = roundf (f * 16384.f); }
114   public:
115   DEFINE_SIZE_STATIC (2);
116 };
117 
118 /* 32-bit signed fixed-point number (16.16). */
119 struct Fixed : HBINT32
120 {
operator =OT::Fixed121   Fixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
122   // 65536 means 1<<16
to_floatOT::Fixed123   float to_float () const  { return ((int32_t) v) / 65536.f; }
set_floatOT::Fixed124   void set_float (float f) { v = roundf (f * 65536.f); }
125   public:
126   DEFINE_SIZE_STATIC (4);
127 };
128 
129 /* Date represented in number of seconds since 12:00 midnight, January 1,
130  * 1904. The value is represented as a signed 64-bit integer. */
131 struct LONGDATETIME
132 {
sanitizeOT::LONGDATETIME133   bool sanitize (hb_sanitize_context_t *c) const
134   {
135     TRACE_SANITIZE (this);
136     return_trace (likely (c->check_struct (this)));
137   }
138   protected:
139   HBINT32 major;
140   HBUINT32 minor;
141   public:
142   DEFINE_SIZE_STATIC (8);
143 };
144 
145 /* Array of four uint8s (length = 32 bits) used to identify a script, language
146  * system, feature, or baseline */
147 struct Tag : HBUINT32
148 {
operator =OT::Tag149   Tag& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
150   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
operator const char*OT::Tag151   operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
operator char*OT::Tag152   operator char* ()             { return reinterpret_cast<char *> (&this->v); }
153   public:
154   DEFINE_SIZE_STATIC (4);
155 };
156 
157 /* Glyph index number, same as uint16 (length = 16 bits) */
158 struct GlyphID : HBUINT16
159 {
operator =OT::GlyphID160   GlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
161 };
162 
163 /* Script/language-system/feature index */
164 struct Index : HBUINT16 {
165   static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
operator =OT::Index166   Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
167 };
168 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
169 
170 typedef Index NameID;
171 
172 /* Offset, Null offset = 0 */
173 template <typename Type, bool has_null=true>
174 struct Offset : Type
175 {
operator =OT::Offset176   Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
177 
178   typedef Type type;
179 
is_nullOT::Offset180   bool is_null () const { return has_null && 0 == *this; }
181 
serializeOT::Offset182   void *serialize (hb_serialize_context_t *c, const void *base)
183   {
184     void *t = c->start_embed<void> ();
185     c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
186     return t;
187   }
188 
189   public:
190   DEFINE_SIZE_STATIC (sizeof (Type));
191 };
192 
193 typedef Offset<HBUINT16> Offset16;
194 typedef Offset<HBUINT32> Offset32;
195 
196 
197 /* CheckSum */
198 struct CheckSum : HBUINT32
199 {
operator =OT::CheckSum200   CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
201 
202   /* This is reference implementation from the spec. */
CalcTableChecksumOT::CheckSum203   static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
204   {
205     uint32_t Sum = 0L;
206     assert (0 == (Length & 3));
207     const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
208 
209     while (Table < EndPtr)
210       Sum += *Table++;
211     return Sum;
212   }
213 
214   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
set_for_dataOT::CheckSum215   void set_for_data (const void *data, unsigned int length)
216   { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
217 
218   public:
219   DEFINE_SIZE_STATIC (4);
220 };
221 
222 
223 /*
224  * Version Numbers
225  */
226 
227 template <typename FixedType=HBUINT16>
228 struct FixedVersion
229 {
to_intOT::FixedVersion230   uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
231 
sanitizeOT::FixedVersion232   bool sanitize (hb_sanitize_context_t *c) const
233   {
234     TRACE_SANITIZE (this);
235     return_trace (c->check_struct (this));
236   }
237 
238   FixedType major;
239   FixedType minor;
240   public:
241   DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
242 };
243 
244 
245 /*
246  * Template subclasses of Offset that do the dereferencing.
247  * Use: (base+offset)
248  */
249 
250 template <typename Type, bool has_null>
251 struct _hb_has_null
252 {
get_nullOT::_hb_has_null253   static const Type *get_null () { return nullptr; }
get_crapOT::_hb_has_null254   static Type *get_crap ()       { return nullptr; }
255 };
256 template <typename Type>
257 struct _hb_has_null<Type, true>
258 {
get_nullOT::_hb_has_null259   static const Type *get_null () { return &Null(Type); }
get_crapOT::_hb_has_null260   static Type *get_crap ()       { return &Crap(Type); }
261 };
262 
263 template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
264 struct OffsetTo : Offset<OffsetType, has_null>
265 {
266   HB_DELETE_COPY_ASSIGN (OffsetTo);
267   OffsetTo () = default;
268 
operator =OT::OffsetTo269   OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
270 
operator ()OT::OffsetTo271   const Type& operator () (const void *base) const
272   {
273     if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
274     return StructAtOffset<const Type> (base, *this);
275   }
operator ()OT::OffsetTo276   Type& operator () (void *base) const
277   {
278     if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
279     return StructAtOffset<Type> (base, *this);
280   }
281 
282   template <typename Base,
283 	    hb_enable_if (hb_is_convertible (const Base, const void *))>
operator +(const Base & base,const OffsetTo & offset)284   friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
285   template <typename Base,
286 	    hb_enable_if (hb_is_convertible (const Base, const void *))>
operator +(const OffsetTo & offset,const Base & base)287   friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
288   template <typename Base,
289 	    hb_enable_if (hb_is_convertible (Base, void *))>
operator +(Base && base,OffsetTo & offset)290   friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
291   template <typename Base,
292 	    hb_enable_if (hb_is_convertible (Base, void *))>
operator +(OffsetTo & offset,Base && base)293   friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
294 
serializeOT::OffsetTo295   Type& serialize (hb_serialize_context_t *c, const void *base)
296   {
297     return * (Type *) Offset<OffsetType>::serialize (c, base);
298   }
299 
300   template <typename ...Ts>
serialize_subsetOT::OffsetTo301   bool serialize_subset (hb_subset_context_t *c,
302 			 const OffsetTo& src,
303 			 const void *src_base,
304 			 const void *dst_base,
305 			 Ts&&... ds)
306   {
307     *this = 0;
308     if (src.is_null ())
309       return false;
310 
311     auto *s = c->serializer;
312 
313     s->push ();
314 
315     bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
316 
317     if (ret || !has_null)
318       s->add_link (*this, s->pop_pack (), dst_base);
319     else
320       s->pop_discard ();
321 
322     return ret;
323   }
324 
325   /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
326   template <typename ...Ts>
serialize_copyOT::OffsetTo327   bool serialize_copy (hb_serialize_context_t *c,
328 		       const OffsetTo& src,
329 		       const void *src_base,
330 		       const void *dst_base,
331 		       Ts&&... ds)
332   {
333     *this = 0;
334     if (src.is_null ())
335       return false;
336 
337     c->push ();
338 
339     bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
340 
341     c->add_link (*this, c->pop_pack (), dst_base);
342 
343     return ret;
344   }
345 
sanitize_shallowOT::OffsetTo346   bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
347   {
348     TRACE_SANITIZE (this);
349     if (unlikely (!c->check_struct (this))) return_trace (false);
350     if (unlikely (this->is_null ())) return_trace (true);
351     if (unlikely (!c->check_range (base, *this))) return_trace (false);
352     return_trace (true);
353   }
354 
355   template <typename ...Ts>
sanitizeOT::OffsetTo356   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
357   {
358     TRACE_SANITIZE (this);
359     return_trace (sanitize_shallow (c, base) &&
360 		  (this->is_null () ||
361 		   c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
362 		   neuter (c)));
363   }
364 
365   /* Set the offset to Null */
neuterOT::OffsetTo366   bool neuter (hb_sanitize_context_t *c) const
367   {
368     if (!has_null) return false;
369     return c->try_set (this, 0);
370   }
371   DEFINE_SIZE_STATIC (sizeof (OffsetType));
372 };
373 /* Partial specializations. */
374 template <typename Type, bool has_null=true>
375 using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
376 template <typename Type, typename OffsetType=HBUINT16>
377 using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
378 template <typename Type>
379 using LNNOffsetTo = LOffsetTo<Type, false>;
380 
381 
382 /*
383  * Array Types
384  */
385 
386 template <typename Type>
387 struct UnsizedArrayOf
388 {
389   typedef Type item_t;
390   static constexpr unsigned item_size = hb_static_size (Type);
391 
392   HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
393 
operator []OT::UnsizedArrayOf394   const Type& operator [] (int i_) const
395   {
396     unsigned int i = (unsigned int) i_;
397     const Type *p = &arrayZ[i];
398     if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
399     return *p;
400   }
operator []OT::UnsizedArrayOf401   Type& operator [] (int i_)
402   {
403     unsigned int i = (unsigned int) i_;
404     Type *p = &arrayZ[i];
405     if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
406     return *p;
407   }
408 
get_sizeOT::UnsizedArrayOf409   unsigned int get_size (unsigned int len) const
410   { return len * Type::static_size; }
411 
operator T*OT::UnsizedArrayOf412   template <typename T> operator T * () { return arrayZ; }
operator const T*OT::UnsizedArrayOf413   template <typename T> operator const T * () const { return arrayZ; }
as_arrayOT::UnsizedArrayOf414   hb_array_t<Type> as_array (unsigned int len)
415   { return hb_array (arrayZ, len); }
as_arrayOT::UnsizedArrayOf416   hb_array_t<const Type> as_array (unsigned int len) const
417   { return hb_array (arrayZ, len); }
operator hb_array_t<Type>OT::UnsizedArrayOf418   operator hb_array_t<Type> ()             { return as_array (); }
operator hb_array_t<const Type>OT::UnsizedArrayOf419   operator hb_array_t<const Type> () const { return as_array (); }
420 
421   template <typename T>
lsearchOT::UnsizedArrayOf422   Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
423   { return *as_array (len).lsearch (x, &not_found); }
424   template <typename T>
lsearchOT::UnsizedArrayOf425   const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
426   { return *as_array (len).lsearch (x, &not_found); }
427 
qsortOT::UnsizedArrayOf428   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
429   { as_array (len).qsort (start, end); }
430 
serializeOT::UnsizedArrayOf431   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
432   {
433     TRACE_SERIALIZE (this);
434     if (unlikely (!c->extend (*this, items_len))) return_trace (false);
435     return_trace (true);
436   }
437   template <typename Iterator,
438 	    hb_requires (hb_is_source_of (Iterator, Type))>
serializeOT::UnsizedArrayOf439   bool serialize (hb_serialize_context_t *c, Iterator items)
440   {
441     TRACE_SERIALIZE (this);
442     unsigned count = items.len ();
443     if (unlikely (!serialize (c, count))) return_trace (false);
444     /* TODO Umm. Just exhaust the iterator instead?  Being extra
445      * cautious right now.. */
446     for (unsigned i = 0; i < count; i++, ++items)
447       arrayZ[i] = *items;
448     return_trace (true);
449   }
450 
copyOT::UnsizedArrayOf451   UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
452   {
453     TRACE_SERIALIZE (this);
454     auto *out = c->start_embed (this);
455     if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
456     return_trace (out);
457   }
458 
459   template <typename ...Ts>
sanitizeOT::UnsizedArrayOf460   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
461   {
462     TRACE_SANITIZE (this);
463     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
464     if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
465     for (unsigned int i = 0; i < count; i++)
466       if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
467 	return_trace (false);
468     return_trace (true);
469   }
470 
sanitize_shallowOT::UnsizedArrayOf471   bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
472   {
473     TRACE_SANITIZE (this);
474     return_trace (c->check_array (arrayZ, count));
475   }
476 
477   public:
478   Type		arrayZ[VAR];
479   public:
480   DEFINE_SIZE_UNBOUNDED (0);
481 };
482 
483 /* Unsized array of offset's */
484 template <typename Type, typename OffsetType, bool has_null=true>
485 using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
486 
487 /* Unsized array of offsets relative to the beginning of the array itself. */
488 template <typename Type, typename OffsetType, bool has_null=true>
489 struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
490 {
operator []OT::UnsizedOffsetListOf491   const Type& operator [] (int i_) const
492   {
493     unsigned int i = (unsigned int) i_;
494     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
495     if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
496     return this+*p;
497   }
operator []OT::UnsizedOffsetListOf498   Type& operator [] (int i_)
499   {
500     unsigned int i = (unsigned int) i_;
501     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
502     if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
503     return this+*p;
504   }
505 
506   template <typename ...Ts>
sanitizeOT::UnsizedOffsetListOf507   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
508   {
509     TRACE_SANITIZE (this);
510     return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
511 		   ::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
512   }
513 };
514 
515 /* An array with sorted elements.  Supports binary searching. */
516 template <typename Type>
517 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
518 {
as_arrayOT::SortedUnsizedArrayOf519   hb_sorted_array_t<Type> as_array (unsigned int len)
520   { return hb_sorted_array (this->arrayZ, len); }
as_arrayOT::SortedUnsizedArrayOf521   hb_sorted_array_t<const Type> as_array (unsigned int len) const
522   { return hb_sorted_array (this->arrayZ, len); }
operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf523   operator hb_sorted_array_t<Type> ()             { return as_array (); }
operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf524   operator hb_sorted_array_t<const Type> () const { return as_array (); }
525 
526   template <typename T>
bsearchOT::SortedUnsizedArrayOf527   Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
528   { return *as_array (len).bsearch (x, &not_found); }
529   template <typename T>
bsearchOT::SortedUnsizedArrayOf530   const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
531   { return *as_array (len).bsearch (x, &not_found); }
532   template <typename T>
bfindOT::SortedUnsizedArrayOf533   bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
534 		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
535 		     unsigned int to_store = (unsigned int) -1) const
536   { return as_array (len).bfind (x, i, not_found, to_store); }
537 };
538 
539 
540 /* An array with a number of elements. */
541 template <typename Type, typename LenType=HBUINT16>
542 struct ArrayOf
543 {
544   typedef Type item_t;
545   static constexpr unsigned item_size = hb_static_size (Type);
546 
547   HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
548 
operator []OT::ArrayOf549   const Type& operator [] (int i_) const
550   {
551     unsigned int i = (unsigned int) i_;
552     if (unlikely (i >= len)) return Null (Type);
553     return arrayZ[i];
554   }
operator []OT::ArrayOf555   Type& operator [] (int i_)
556   {
557     unsigned int i = (unsigned int) i_;
558     if (unlikely (i >= len)) return Crap (Type);
559     return arrayZ[i];
560   }
561 
get_sizeOT::ArrayOf562   unsigned int get_size () const
563   { return len.static_size + len * Type::static_size; }
564 
operator boolOT::ArrayOf565   explicit operator bool () const { return len; }
566 
as_arrayOT::ArrayOf567   hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, len); }
as_arrayOT::ArrayOf568   hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
569 
570   /* Iterator. */
571   typedef hb_array_t<const Type>   iter_t;
572   typedef hb_array_t<      Type> writer_t;
iterOT::ArrayOf573     iter_t   iter () const { return as_array (); }
writerOT::ArrayOf574   writer_t writer ()       { return as_array (); }
operator iter_tOT::ArrayOf575   operator   iter_t () const { return   iter (); }
operator writer_tOT::ArrayOf576   operator writer_t ()       { return writer (); }
577 
sub_arrayOT::ArrayOf578   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
579   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::ArrayOf580   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
581   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::ArrayOf582   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
583   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::ArrayOf584   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
585   { return as_array ().sub_array (start_offset, count);}
586 
serializeOT::ArrayOf587   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
588   {
589     TRACE_SERIALIZE (this);
590     if (unlikely (!c->extend_min (*this))) return_trace (false);
591     c->check_assign (len, items_len);
592     if (unlikely (!c->extend (*this))) return_trace (false);
593     return_trace (true);
594   }
595   template <typename Iterator,
596 	    hb_requires (hb_is_source_of (Iterator, Type))>
serializeOT::ArrayOf597   bool serialize (hb_serialize_context_t *c, Iterator items)
598   {
599     TRACE_SERIALIZE (this);
600     unsigned count = items.len ();
601     if (unlikely (!serialize (c, count))) return_trace (false);
602     /* TODO Umm. Just exhaust the iterator instead?  Being extra
603      * cautious right now.. */
604     for (unsigned i = 0; i < count; i++, ++items)
605       arrayZ[i] = *items;
606     return_trace (true);
607   }
608 
copyOT::ArrayOf609   ArrayOf* copy (hb_serialize_context_t *c) const
610   {
611     TRACE_SERIALIZE (this);
612     auto *out = c->start_embed (this);
613     if (unlikely (!c->extend_min (out))) return_trace (nullptr);
614     c->check_assign (out->len, len);
615     if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
616     return_trace (out);
617   }
618 
619   template <typename ...Ts>
sanitizeOT::ArrayOf620   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
621   {
622     TRACE_SANITIZE (this);
623     if (unlikely (!sanitize_shallow (c))) return_trace (false);
624     if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
625     unsigned int count = len;
626     for (unsigned int i = 0; i < count; i++)
627       if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
628 	return_trace (false);
629     return_trace (true);
630   }
631 
632   template <typename T>
lsearchOT::ArrayOf633   Type &lsearch (const T &x, Type &not_found = Crap (Type))
634   { return *as_array ().lsearch (x, &not_found); }
635   template <typename T>
lsearchOT::ArrayOf636   const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
637   { return *as_array ().lsearch (x, &not_found); }
638 
qsortOT::ArrayOf639   void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
640   { as_array ().qsort (start, end); }
641 
sanitize_shallowOT::ArrayOf642   bool sanitize_shallow (hb_sanitize_context_t *c) const
643   {
644     TRACE_SANITIZE (this);
645     return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
646   }
647 
648   public:
649   LenType	len;
650   Type		arrayZ[VAR];
651   public:
652   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
653 };
654 template <typename Type>
655 using LArrayOf = ArrayOf<Type, HBUINT32>;
656 using PString = ArrayOf<HBUINT8, HBUINT8>;
657 
658 /* Array of Offset's */
659 template <typename Type>
660 using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
661 template <typename Type>
662 using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
663 template <typename Type>
664 using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
665 
666 /* Array of offsets relative to the beginning of the array itself. */
667 template <typename Type>
668 struct OffsetListOf : OffsetArrayOf<Type>
669 {
operator []OT::OffsetListOf670   const Type& operator [] (int i_) const
671   {
672     unsigned int i = (unsigned int) i_;
673     if (unlikely (i >= this->len)) return Null (Type);
674     return this+this->arrayZ[i];
675   }
operator []OT::OffsetListOf676   const Type& operator [] (int i_)
677   {
678     unsigned int i = (unsigned int) i_;
679     if (unlikely (i >= this->len)) return Crap (Type);
680     return this+this->arrayZ[i];
681   }
682 
subsetOT::OffsetListOf683   bool subset (hb_subset_context_t *c) const
684   {
685     TRACE_SUBSET (this);
686     struct OffsetListOf<Type> *out = c->serializer->embed (*this);
687     if (unlikely (!out)) return_trace (false);
688     unsigned int count = this->len;
689     for (unsigned int i = 0; i < count; i++)
690       out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
691     return_trace (true);
692   }
693 
694   template <typename ...Ts>
sanitizeOT::OffsetListOf695   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
696   {
697     TRACE_SANITIZE (this);
698     return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
699   }
700 };
701 
702 /* An array starting at second element. */
703 template <typename Type, typename LenType=HBUINT16>
704 struct HeadlessArrayOf
705 {
706   static constexpr unsigned item_size = Type::static_size;
707 
708   HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
709 
operator []OT::HeadlessArrayOf710   const Type& operator [] (int i_) const
711   {
712     unsigned int i = (unsigned int) i_;
713     if (unlikely (i >= lenP1 || !i)) return Null (Type);
714     return arrayZ[i-1];
715   }
operator []OT::HeadlessArrayOf716   Type& operator [] (int i_)
717   {
718     unsigned int i = (unsigned int) i_;
719     if (unlikely (i >= lenP1 || !i)) return Crap (Type);
720     return arrayZ[i-1];
721   }
get_sizeOT::HeadlessArrayOf722   unsigned int get_size () const
723   { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
724 
serializeOT::HeadlessArrayOf725   bool serialize (hb_serialize_context_t *c,
726 		  hb_array_t<const Type> items)
727   {
728     TRACE_SERIALIZE (this);
729     if (unlikely (!c->extend_min (*this))) return_trace (false);
730     c->check_assign (lenP1, items.length + 1);
731     if (unlikely (!c->extend (*this))) return_trace (false);
732     for (unsigned int i = 0; i < items.length; i++)
733       arrayZ[i] = items[i];
734     return_trace (true);
735   }
736 
737   template <typename ...Ts>
sanitizeOT::HeadlessArrayOf738   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
739   {
740     TRACE_SANITIZE (this);
741     if (unlikely (!sanitize_shallow (c))) return_trace (false);
742     if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
743     unsigned int count = lenP1 ? lenP1 - 1 : 0;
744     for (unsigned int i = 0; i < count; i++)
745       if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
746 	return_trace (false);
747     return_trace (true);
748   }
749 
750   private:
sanitize_shallowOT::HeadlessArrayOf751   bool sanitize_shallow (hb_sanitize_context_t *c) const
752   {
753     TRACE_SANITIZE (this);
754     return_trace (lenP1.sanitize (c) &&
755 		  (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
756   }
757 
758   public:
759   LenType	lenP1;
760   Type		arrayZ[VAR];
761   public:
762   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
763 };
764 
765 /* An array storing length-1. */
766 template <typename Type, typename LenType=HBUINT16>
767 struct ArrayOfM1
768 {
769   HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
770 
operator []OT::ArrayOfM1771   const Type& operator [] (int i_) const
772   {
773     unsigned int i = (unsigned int) i_;
774     if (unlikely (i > lenM1)) return Null (Type);
775     return arrayZ[i];
776   }
operator []OT::ArrayOfM1777   Type& operator [] (int i_)
778   {
779     unsigned int i = (unsigned int) i_;
780     if (unlikely (i > lenM1)) return Crap (Type);
781     return arrayZ[i];
782   }
get_sizeOT::ArrayOfM1783   unsigned int get_size () const
784   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
785 
786   template <typename ...Ts>
sanitizeOT::ArrayOfM1787   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
788   {
789     TRACE_SANITIZE (this);
790     if (unlikely (!sanitize_shallow (c))) return_trace (false);
791     unsigned int count = lenM1 + 1;
792     for (unsigned int i = 0; i < count; i++)
793       if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
794 	return_trace (false);
795     return_trace (true);
796   }
797 
798   private:
sanitize_shallowOT::ArrayOfM1799   bool sanitize_shallow (hb_sanitize_context_t *c) const
800   {
801     TRACE_SANITIZE (this);
802     return_trace (lenM1.sanitize (c) &&
803 		  (c->check_array (arrayZ, lenM1 + 1)));
804   }
805 
806   public:
807   LenType	lenM1;
808   Type		arrayZ[VAR];
809   public:
810   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
811 };
812 
813 /* An array with sorted elements.  Supports binary searching. */
814 template <typename Type, typename LenType=HBUINT16>
815 struct SortedArrayOf : ArrayOf<Type, LenType>
816 {
as_arrayOT::SortedArrayOf817   hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
as_arrayOT::SortedArrayOf818   hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
819 
820   /* Iterator. */
821   typedef hb_sorted_array_t<const Type>   iter_t;
822   typedef hb_sorted_array_t<      Type> writer_t;
iterOT::SortedArrayOf823     iter_t   iter () const { return as_array (); }
writerOT::SortedArrayOf824   writer_t writer ()       { return as_array (); }
operator iter_tOT::SortedArrayOf825   operator   iter_t () const { return   iter (); }
operator writer_tOT::SortedArrayOf826   operator writer_t ()       { return writer (); }
827 
sub_arrayOT::SortedArrayOf828   hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
829   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::SortedArrayOf830   hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
831   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::SortedArrayOf832   hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
833   { return as_array ().sub_array (start_offset, count);}
sub_arrayOT::SortedArrayOf834   hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
835   { return as_array ().sub_array (start_offset, count);}
836 
serializeOT::SortedArrayOf837   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
838   {
839     TRACE_SERIALIZE (this);
840     bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
841     return_trace (ret);
842   }
843   template <typename Iterator,
844 	    hb_requires (hb_is_sorted_source_of (Iterator, Type))>
serializeOT::SortedArrayOf845   bool serialize (hb_serialize_context_t *c, Iterator items)
846   {
847     TRACE_SERIALIZE (this);
848     bool ret = ArrayOf<Type, LenType>::serialize (c, items);
849     return_trace (ret);
850   }
851 
852   template <typename T>
bsearchOT::SortedArrayOf853   Type &bsearch (const T &x, Type &not_found = Crap (Type))
854   { return *as_array ().bsearch (x, &not_found); }
855   template <typename T>
bsearchOT::SortedArrayOf856   const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
857   { return *as_array ().bsearch (x, &not_found); }
858   template <typename T>
bfindOT::SortedArrayOf859   bool bfind (const T &x, unsigned int *i = nullptr,
860 		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
861 		     unsigned int to_store = (unsigned int) -1) const
862   { return as_array ().bfind (x, i, not_found, to_store); }
863 };
864 
865 /*
866  * Binary-search arrays
867  */
868 
869 template <typename LenType=HBUINT16>
870 struct BinSearchHeader
871 {
operator uint32_tOT::BinSearchHeader872   operator uint32_t () const { return len; }
873 
sanitizeOT::BinSearchHeader874   bool sanitize (hb_sanitize_context_t *c) const
875   {
876     TRACE_SANITIZE (this);
877     return_trace (c->check_struct (this));
878   }
879 
operator =OT::BinSearchHeader880   BinSearchHeader& operator = (unsigned int v)
881   {
882     len = v;
883     assert (len == v);
884     entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
885     searchRange = 16 * (1u << entrySelector);
886     rangeShift = v * 16 > searchRange
887 		 ? 16 * v - searchRange
888 		 : 0;
889     return *this;
890   }
891 
892   protected:
893   LenType	len;
894   LenType	searchRange;
895   LenType	entrySelector;
896   LenType	rangeShift;
897 
898   public:
899   DEFINE_SIZE_STATIC (8);
900 };
901 
902 template <typename Type, typename LenType=HBUINT16>
903 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
904 
905 
906 struct VarSizedBinSearchHeader
907 {
908 
sanitizeOT::VarSizedBinSearchHeader909   bool sanitize (hb_sanitize_context_t *c) const
910   {
911     TRACE_SANITIZE (this);
912     return_trace (c->check_struct (this));
913   }
914 
915   HBUINT16	unitSize;	/* Size of a lookup unit for this search in bytes. */
916   HBUINT16	nUnits;		/* Number of units of the preceding size to be searched. */
917   HBUINT16	searchRange;	/* The value of unitSize times the largest power of 2
918 				 * that is less than or equal to the value of nUnits. */
919   HBUINT16	entrySelector;	/* The log base 2 of the largest power of 2 less than
920 				 * or equal to the value of nUnits. */
921   HBUINT16	rangeShift;	/* The value of unitSize times the difference of the
922 				 * value of nUnits minus the largest power of 2 less
923 				 * than or equal to the value of nUnits. */
924   public:
925   DEFINE_SIZE_STATIC (10);
926 };
927 
928 template <typename Type>
929 struct VarSizedBinSearchArrayOf
930 {
931   static constexpr unsigned item_size = Type::static_size;
932 
933   HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
934 
last_is_terminatorOT::VarSizedBinSearchArrayOf935   bool last_is_terminator () const
936   {
937     if (unlikely (!header.nUnits)) return false;
938 
939     /* Gah.
940      *
941      * "The number of termination values that need to be included is table-specific.
942      * The value that indicates binary search termination is 0xFFFF." */
943     const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
944     unsigned int count = Type::TerminationWordCount;
945     for (unsigned int i = 0; i < count; i++)
946       if (words[i] != 0xFFFFu)
947         return false;
948     return true;
949   }
950 
operator []OT::VarSizedBinSearchArrayOf951   const Type& operator [] (int i_) const
952   {
953     unsigned int i = (unsigned int) i_;
954     if (unlikely (i >= get_length ())) return Null (Type);
955     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
956   }
operator []OT::VarSizedBinSearchArrayOf957   Type& operator [] (int i_)
958   {
959     unsigned int i = (unsigned int) i_;
960     if (unlikely (i >= get_length ())) return Crap (Type);
961     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
962   }
get_lengthOT::VarSizedBinSearchArrayOf963   unsigned int get_length () const
964   { return header.nUnits - last_is_terminator (); }
get_sizeOT::VarSizedBinSearchArrayOf965   unsigned int get_size () const
966   { return header.static_size + header.nUnits * header.unitSize; }
967 
968   template <typename ...Ts>
sanitizeOT::VarSizedBinSearchArrayOf969   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
970   {
971     TRACE_SANITIZE (this);
972     if (unlikely (!sanitize_shallow (c))) return_trace (false);
973     if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
974     unsigned int count = get_length ();
975     for (unsigned int i = 0; i < count; i++)
976       if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
977 	return_trace (false);
978     return_trace (true);
979   }
980 
981   template <typename T>
bsearchOT::VarSizedBinSearchArrayOf982   const Type *bsearch (const T &key) const
983   {
984     unsigned int size = header.unitSize;
985     int min = 0, max = (int) get_length () - 1;
986     while (min <= max)
987     {
988       int mid = ((unsigned int) min + (unsigned int) max) / 2;
989       const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
990       int c = p->cmp (key);
991       if (c < 0) max = mid - 1;
992       else if (c > 0) min = mid + 1;
993       else return p;
994     }
995     return nullptr;
996   }
997 
998   private:
sanitize_shallowOT::VarSizedBinSearchArrayOf999   bool sanitize_shallow (hb_sanitize_context_t *c) const
1000   {
1001     TRACE_SANITIZE (this);
1002     return_trace (header.sanitize (c) &&
1003 		  Type::static_size <= header.unitSize &&
1004 		  c->check_range (bytesZ.arrayZ,
1005 				  header.nUnits,
1006 				  header.unitSize));
1007   }
1008 
1009   protected:
1010   VarSizedBinSearchHeader	header;
1011   UnsizedArrayOf<HBUINT8>	bytesZ;
1012   public:
1013   DEFINE_SIZE_ARRAY (10, bytesZ);
1014 };
1015 
1016 
1017 } /* namespace OT */
1018 
1019 
1020 #endif /* HB_OPEN_TYPE_HH */
1021