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, 57 unsigned int Size = sizeof (Type)> 58 struct IntType 59 { 60 typedef Type type; 61 62 IntType () = default; IntTypeOT::IntType63 explicit constexpr IntType (Type V) : v {V} {} operator =OT::IntType64 IntType& operator = (Type i) { v = i; return *this; } 65 /* For reason we define cast out operator for signed/unsigned, instead of Type, see: 66 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ operator hb_conditional<hb_is_signed(Type),signed,unsigned>OT::IntType67 operator hb_conditional<hb_is_signed (Type), signed, unsigned> () const { return v; } 68 operator ==OT::IntType69 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } operator !=OT::IntType70 bool operator != (const IntType &o) const { return !(*this == o); } 71 operator +=OT::IntType72 IntType& operator += (unsigned count) { *this = *this + count; return *this; } operator -=OT::IntType73 IntType& operator -= (unsigned count) { *this = *this - count; return *this; } operator ++OT::IntType74 IntType& operator ++ () { *this += 1; return *this; } operator --OT::IntType75 IntType& operator -- () { *this -= 1; return *this; } operator ++OT::IntType76 IntType operator ++ (int) { IntType c (*this); ++*this; return c; } operator --OT::IntType77 IntType operator -- (int) { IntType c (*this); --*this; return c; } 78 cmpOT::IntType79 HB_INTERNAL static int cmp (const IntType *a, const IntType *b) 80 { return b->cmp (*a); } cmpOT::IntType81 HB_INTERNAL static int cmp (const void *a, const void *b) 82 { 83 IntType *pa = (IntType *) a; 84 IntType *pb = (IntType *) b; 85 86 return pb->cmp (*pa); 87 } 88 template <typename Type2, 89 hb_enable_if (hb_is_integral (Type2) && 90 sizeof (Type2) < sizeof (int) && 91 sizeof (Type) < sizeof (int))> cmpOT::IntType92 int cmp (Type2 a) const 93 { 94 Type b = v; 95 return (int) a - (int) b; 96 } 97 template <typename Type2, 98 hb_enable_if (hb_is_convertible (Type2, Type))> cmpOT::IntType99 int cmp (Type2 a) const 100 { 101 Type b = v; 102 return a < b ? -1 : a == b ? 0 : +1; 103 } sanitizeOT::IntType104 bool sanitize (hb_sanitize_context_t *c) const 105 { 106 TRACE_SANITIZE (this); 107 return_trace (likely (c->check_struct (this))); 108 } 109 protected: 110 BEInt<Type, Size> v; 111 public: 112 DEFINE_SIZE_STATIC (Size); 113 }; 114 115 typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */ 116 typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */ 117 typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */ 118 typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */ 119 typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */ 120 typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */ 121 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. 122 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ 123 typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ 124 125 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ 126 typedef HBINT16 FWORD; 127 128 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ 129 typedef HBINT32 FWORD32; 130 131 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ 132 typedef HBUINT16 UFWORD; 133 134 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ 135 struct F2DOT14 : HBINT16 136 { operator =OT::F2DOT14137 F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } 138 // 16384 means 1<<14 to_floatOT::F2DOT14139 float to_float () const { return ((int32_t) v) / 16384.f; } set_floatOT::F2DOT14140 void set_float (float f) { v = roundf (f * 16384.f); } 141 public: 142 DEFINE_SIZE_STATIC (2); 143 }; 144 145 /* 32-bit signed fixed-point number (16.16). */ 146 struct HBFixed : HBINT32 147 { operator =OT::HBFixed148 HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } 149 // 65536 means 1<<16 to_floatOT::HBFixed150 float to_float () const { return ((int32_t) v) / 65536.f; } set_floatOT::HBFixed151 void set_float (float f) { v = roundf (f * 65536.f); } 152 public: 153 DEFINE_SIZE_STATIC (4); 154 }; 155 156 /* Date represented in number of seconds since 12:00 midnight, January 1, 157 * 1904. The value is represented as a signed 64-bit integer. */ 158 struct LONGDATETIME 159 { sanitizeOT::LONGDATETIME160 bool sanitize (hb_sanitize_context_t *c) const 161 { 162 TRACE_SANITIZE (this); 163 return_trace (likely (c->check_struct (this))); 164 } 165 protected: 166 HBINT32 major; 167 HBUINT32 minor; 168 public: 169 DEFINE_SIZE_STATIC (8); 170 }; 171 172 /* Array of four uint8s (length = 32 bits) used to identify a script, language 173 * system, feature, or baseline */ 174 struct Tag : HBUINT32 175 { operator =OT::Tag176 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } 177 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char*OT::Tag178 operator const char* () const { return reinterpret_cast<const char *> (this); } operator char*OT::Tag179 operator char* () { return reinterpret_cast<char *> (this); } 180 public: 181 DEFINE_SIZE_STATIC (4); 182 }; 183 184 /* Glyph index number, same as uint16 (length = 16 bits) */ 185 struct HBGlyphID : HBUINT16 186 { operator =OT::HBGlyphID187 HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 188 }; 189 190 /* Script/language-system/feature index */ 191 struct Index : HBUINT16 { 192 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; operator =OT::Index193 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 194 }; 195 DECLARE_NULL_NAMESPACE_BYTES (OT, Index); 196 197 typedef Index NameID; 198 199 struct VarIdx : HBUINT32 { 200 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; operator =OT::VarIdx201 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 202 }; 203 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); 204 205 /* Offset, Null offset = 0 */ 206 template <typename Type, bool has_null=true> 207 struct Offset : Type 208 { operator =OT::Offset209 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } 210 211 typedef Type type; 212 is_nullOT::Offset213 bool is_null () const { return has_null && 0 == *this; } 214 serializeOT::Offset215 void *serialize (hb_serialize_context_t *c, const void *base) 216 { 217 void *t = c->start_embed<void> (); 218 c->check_assign (*this, 219 (unsigned) ((char *) t - (char *) base), 220 HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); 221 return t; 222 } 223 224 public: 225 DEFINE_SIZE_STATIC (sizeof (Type)); 226 }; 227 228 typedef Offset<HBUINT16> Offset16; 229 typedef Offset<HBUINT24> Offset24; 230 typedef Offset<HBUINT32> Offset32; 231 232 233 /* CheckSum */ 234 struct CheckSum : HBUINT32 235 { operator =OT::CheckSum236 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 237 238 /* This is reference implementation from the spec. */ CalcTableChecksumOT::CheckSum239 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) 240 { 241 uint32_t Sum = 0L; 242 assert (0 == (Length & 3)); 243 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; 244 245 while (Table < EndPtr) 246 Sum += *Table++; 247 return Sum; 248 } 249 250 /* Note: data should be 4byte aligned and have 4byte padding at the end. */ set_for_dataOT::CheckSum251 void set_for_data (const void *data, unsigned int length) 252 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } 253 254 public: 255 DEFINE_SIZE_STATIC (4); 256 }; 257 258 259 /* 260 * Version Numbers 261 */ 262 263 template <typename FixedType=HBUINT16> 264 struct FixedVersion 265 { to_intOT::FixedVersion266 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } 267 sanitizeOT::FixedVersion268 bool sanitize (hb_sanitize_context_t *c) const 269 { 270 TRACE_SANITIZE (this); 271 return_trace (c->check_struct (this)); 272 } 273 274 FixedType major; 275 FixedType minor; 276 public: 277 DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); 278 }; 279 280 281 /* 282 * Template subclasses of Offset that do the dereferencing. 283 * Use: (base+offset) 284 */ 285 286 template <typename Type, bool has_null> 287 struct _hb_has_null 288 { get_nullOT::_hb_has_null289 static const Type *get_null () { return nullptr; } get_crapOT::_hb_has_null290 static Type *get_crap () { return nullptr; } 291 }; 292 template <typename Type> 293 struct _hb_has_null<Type, true> 294 { get_nullOT::_hb_has_null295 static const Type *get_null () { return &Null (Type); } get_crapOT::_hb_has_null296 static Type *get_crap () { return &Crap (Type); } 297 }; 298 299 template <typename Type, typename OffsetType, bool has_null=true> 300 struct OffsetTo : Offset<OffsetType, has_null> 301 { 302 HB_DELETE_COPY_ASSIGN (OffsetTo); 303 OffsetTo () = default; 304 operator =OT::OffsetTo305 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } 306 operator ()OT::OffsetTo307 const Type& operator () (const void *base) const 308 { 309 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); 310 return StructAtOffset<const Type> (base, *this); 311 } operator ()OT::OffsetTo312 Type& operator () (void *base) const 313 { 314 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); 315 return StructAtOffset<Type> (base, *this); 316 } 317 318 template <typename Base, 319 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const Base & base,const OffsetTo & offset)320 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } 321 template <typename Base, 322 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const OffsetTo & offset,const Base & base)323 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } 324 template <typename Base, 325 hb_enable_if (hb_is_convertible (Base, void *))> operator +(Base && base,OffsetTo & offset)326 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } 327 template <typename Base, 328 hb_enable_if (hb_is_convertible (Base, void *))> operator +(OffsetTo & offset,Base && base)329 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } 330 serializeOT::OffsetTo331 Type& serialize (hb_serialize_context_t *c, const void *base) 332 { 333 return * (Type *) Offset<OffsetType>::serialize (c, base); 334 } 335 336 template <typename ...Ts> serialize_subsetOT::OffsetTo337 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, 338 const void *src_base, Ts&&... ds) 339 { 340 *this = 0; 341 if (src.is_null ()) 342 return false; 343 344 auto *s = c->serializer; 345 346 s->push (); 347 348 bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...); 349 350 if (ret || !has_null) 351 s->add_link (*this, s->pop_pack ()); 352 else 353 s->pop_discard (); 354 355 return ret; 356 } 357 358 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ 359 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 360 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... 361 */ 362 template <typename ...Ts> serialize_copyOT::OffsetTo363 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 364 const void *src_base, unsigned dst_bias, 365 hb_serialize_context_t::whence_t whence, 366 Ts&&... ds) 367 { 368 *this = 0; 369 if (src.is_null ()) 370 return false; 371 372 c->push (); 373 374 bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...); 375 376 c->add_link (*this, c->pop_pack (), whence, dst_bias); 377 378 return ret; 379 } 380 serialize_copyOT::OffsetTo381 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 382 const void *src_base, unsigned dst_bias = 0) 383 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } 384 sanitize_shallowOT::OffsetTo385 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const 386 { 387 TRACE_SANITIZE (this); 388 if (unlikely (!c->check_struct (this))) return_trace (false); 389 if (unlikely (this->is_null ())) return_trace (true); 390 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); 391 return_trace (true); 392 } 393 394 template <typename ...Ts> sanitizeOT::OffsetTo395 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 396 { 397 TRACE_SANITIZE (this); 398 return_trace (sanitize_shallow (c, base) && 399 (this->is_null () || 400 c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) || 401 neuter (c))); 402 } 403 404 /* Set the offset to Null */ neuterOT::OffsetTo405 bool neuter (hb_sanitize_context_t *c) const 406 { 407 if (!has_null) return false; 408 return c->try_set (this, 0); 409 } 410 DEFINE_SIZE_STATIC (sizeof (OffsetType)); 411 }; 412 /* Partial specializations. */ 413 template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>; 414 template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>; 415 template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>; 416 417 template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>; 418 template <typename Type> using NNOffset16To = Offset16To<Type, false>; 419 template <typename Type> using NNOffset24To = Offset24To<Type, false>; 420 template <typename Type> using NNOffset32To = Offset32To<Type, false>; 421 422 423 /* 424 * Array Types 425 */ 426 427 template <typename Type> 428 struct UnsizedArrayOf 429 { 430 typedef Type item_t; 431 static constexpr unsigned item_size = hb_static_size (Type); 432 433 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); 434 operator []OT::UnsizedArrayOf435 const Type& operator [] (int i_) const 436 { 437 unsigned int i = (unsigned int) i_; 438 const Type *p = &arrayZ[i]; 439 if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ 440 return *p; 441 } operator []OT::UnsizedArrayOf442 Type& operator [] (int i_) 443 { 444 unsigned int i = (unsigned int) i_; 445 Type *p = &arrayZ[i]; 446 if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ 447 return *p; 448 } 449 get_sizeOT::UnsizedArrayOf450 unsigned int get_size (unsigned int len) const 451 { return len * Type::static_size; } 452 operator T*OT::UnsizedArrayOf453 template <typename T> operator T * () { return arrayZ; } operator const T*OT::UnsizedArrayOf454 template <typename T> operator const T * () const { return arrayZ; } as_arrayOT::UnsizedArrayOf455 hb_array_t<Type> as_array (unsigned int len) 456 { return hb_array (arrayZ, len); } as_arrayOT::UnsizedArrayOf457 hb_array_t<const Type> as_array (unsigned int len) const 458 { return hb_array (arrayZ, len); } 459 460 template <typename T> lsearchOT::UnsizedArrayOf461 Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 462 { return *as_array (len).lsearch (x, ¬_found); } 463 template <typename T> lsearchOT::UnsizedArrayOf464 const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 465 { return *as_array (len).lsearch (x, ¬_found); } 466 template <typename T> lfindOT::UnsizedArrayOf467 bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const 468 { return as_array (len).lfind (x, pos); } 469 qsortOT::UnsizedArrayOf470 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) 471 { as_array (len).qsort (start, end); } 472 serializeOT::UnsizedArrayOf473 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 474 { 475 TRACE_SERIALIZE (this); 476 if (unlikely (!c->extend (*this, items_len))) return_trace (false); 477 return_trace (true); 478 } 479 template <typename Iterator, 480 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::UnsizedArrayOf481 bool serialize (hb_serialize_context_t *c, Iterator items) 482 { 483 TRACE_SERIALIZE (this); 484 unsigned count = items.len (); 485 if (unlikely (!serialize (c, count))) return_trace (false); 486 /* TODO Umm. Just exhaust the iterator instead? Being extra 487 * cautious right now.. */ 488 for (unsigned i = 0; i < count; i++, ++items) 489 arrayZ[i] = *items; 490 return_trace (true); 491 } 492 copyOT::UnsizedArrayOf493 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const 494 { 495 TRACE_SERIALIZE (this); 496 auto *out = c->start_embed (this); 497 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); 498 return_trace (out); 499 } 500 501 template <typename ...Ts> sanitizeOT::UnsizedArrayOf502 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 503 { 504 TRACE_SANITIZE (this); 505 if (unlikely (!sanitize_shallow (c, count))) return_trace (false); 506 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 507 for (unsigned int i = 0; i < count; i++) 508 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 509 return_trace (false); 510 return_trace (true); 511 } 512 sanitize_shallowOT::UnsizedArrayOf513 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const 514 { 515 TRACE_SANITIZE (this); 516 return_trace (c->check_array (arrayZ, count)); 517 } 518 519 public: 520 Type arrayZ[HB_VAR_ARRAY]; 521 public: 522 DEFINE_SIZE_UNBOUNDED (0); 523 }; 524 525 /* Unsized array of offset's */ 526 template <typename Type, typename OffsetType, bool has_null=true> 527 using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; 528 529 /* Unsized array of offsets relative to the beginning of the array itself. */ 530 template <typename Type, typename OffsetType, bool has_null=true> 531 struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 532 { operator []OT::UnsizedListOfOffset16To533 const Type& operator [] (int i_) const 534 { 535 unsigned int i = (unsigned int) i_; 536 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 537 if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ 538 return this+*p; 539 } operator []OT::UnsizedListOfOffset16To540 Type& operator [] (int i_) 541 { 542 unsigned int i = (unsigned int) i_; 543 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 544 if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ 545 return this+*p; 546 } 547 548 template <typename ...Ts> sanitizeOT::UnsizedListOfOffset16To549 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 550 { 551 TRACE_SANITIZE (this); 552 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 553 ::sanitize (c, count, this, hb_forward<Ts> (ds)...))); 554 } 555 }; 556 557 /* An array with sorted elements. Supports binary searching. */ 558 template <typename Type> 559 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 560 { as_arrayOT::SortedUnsizedArrayOf561 hb_sorted_array_t<Type> as_array (unsigned int len) 562 { return hb_sorted_array (this->arrayZ, len); } as_arrayOT::SortedUnsizedArrayOf563 hb_sorted_array_t<const Type> as_array (unsigned int len) const 564 { return hb_sorted_array (this->arrayZ, len); } 565 #ifdef ENABLE_ICCARM operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf566 operator hb_sorted_array_t<Type> () { return as_array (0); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf567 operator hb_sorted_array_t<const Type> () const { return as_array (0); } 568 #else operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf569 operator hb_sorted_array_t<Type> () { return as_array (); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf570 operator hb_sorted_array_t<const Type> () const { return as_array (); } 571 #endif 572 573 template <typename T> bsearchOT::SortedUnsizedArrayOf574 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 575 { return *as_array (len).bsearch (x, ¬_found); } 576 template <typename T> bsearchOT::SortedUnsizedArrayOf577 const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 578 { return *as_array (len).bsearch (x, ¬_found); } 579 template <typename T> bfindOT::SortedUnsizedArrayOf580 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, 581 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, 582 unsigned int to_store = (unsigned int) -1) const 583 { return as_array (len).bfind (x, i, not_found, to_store); } 584 }; 585 586 587 /* An array with a number of elements. */ 588 template <typename Type, typename LenType> 589 struct ArrayOf 590 { 591 typedef Type item_t; 592 static constexpr unsigned item_size = hb_static_size (Type); 593 594 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); 595 operator []OT::ArrayOf596 const Type& operator [] (int i_) const 597 { 598 unsigned int i = (unsigned int) i_; 599 if (unlikely (i >= len)) return Null (Type); 600 return arrayZ[i]; 601 } operator []OT::ArrayOf602 Type& operator [] (int i_) 603 { 604 unsigned int i = (unsigned int) i_; 605 if (unlikely (i >= len)) return Crap (Type); 606 return arrayZ[i]; 607 } 608 get_sizeOT::ArrayOf609 unsigned int get_size () const 610 { return len.static_size + len * Type::static_size; } 611 operator boolOT::ArrayOf612 explicit operator bool () const { return len; } 613 popOT::ArrayOf614 void pop () { len--; } 615 as_arrayOT::ArrayOf616 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } as_arrayOT::ArrayOf617 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } 618 619 /* Iterator. */ 620 typedef hb_array_t<const Type> iter_t; 621 typedef hb_array_t< Type> writer_t; iterOT::ArrayOf622 iter_t iter () const { return as_array (); } writerOT::ArrayOf623 writer_t writer () { return as_array (); } operator iter_tOT::ArrayOf624 operator iter_t () const { return iter (); } operator writer_tOT::ArrayOf625 operator writer_t () { return writer (); } 626 sub_arrayOT::ArrayOf627 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 628 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf629 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 630 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf631 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 632 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf633 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 634 { return as_array ().sub_array (start_offset, count); } 635 636 template <typename T> lsearchOT::ArrayOf637 Type &lsearch (const T &x, Type ¬_found = Crap (Type)) 638 { return *as_array ().lsearch (x, ¬_found); } 639 template <typename T> lsearchOT::ArrayOf640 const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const 641 { return *as_array ().lsearch (x, ¬_found); } 642 template <typename T> lfindOT::ArrayOf643 bool lfind (const T &x, unsigned *pos = nullptr) const 644 { return as_array ().lfind (x, pos); } 645 qsortOT::ArrayOf646 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) 647 { as_array ().qsort (start, end); } 648 serializeOT::ArrayOf649 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) 650 { 651 TRACE_SERIALIZE (this); 652 if (unlikely (!c->extend_min (*this))) return_trace (false); 653 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 654 if (unlikely (!c->extend (*this))) return_trace (false); 655 return_trace (true); 656 } 657 template <typename Iterator, 658 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::ArrayOf659 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 660 { 661 TRACE_SERIALIZE (this); 662 unsigned count = items.len (); 663 if (unlikely (!serialize (c, count))) return_trace (false); 664 /* TODO Umm. Just exhaust the iterator instead? Being extra 665 * cautious right now.. */ 666 for (unsigned i = 0; i < count; i++, ++items) 667 arrayZ[i] = *items; 668 return_trace (true); 669 } 670 serialize_appendOT::ArrayOf671 Type* serialize_append (hb_serialize_context_t *c) 672 { 673 TRACE_SERIALIZE (this); 674 len++; 675 if (unlikely (!len || !c->extend (*this))) 676 { 677 len--; 678 return_trace (nullptr); 679 } 680 return_trace (&arrayZ[len - 1]); 681 } 682 copyOT::ArrayOf683 ArrayOf* copy (hb_serialize_context_t *c) const 684 { 685 TRACE_SERIALIZE (this); 686 auto *out = c->start_embed (this); 687 if (unlikely (!c->extend_min (out))) return_trace (nullptr); 688 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 689 if (unlikely (!as_array ().copy (c))) return_trace (nullptr); 690 return_trace (out); 691 } 692 693 template <typename ...Ts> sanitizeOT::ArrayOf694 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 695 { 696 TRACE_SANITIZE (this); 697 if (unlikely (!sanitize_shallow (c))) return_trace (false); 698 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 699 unsigned int count = len; 700 for (unsigned int i = 0; i < count; i++) 701 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 702 return_trace (false); 703 return_trace (true); 704 } 705 sanitize_shallowOT::ArrayOf706 bool sanitize_shallow (hb_sanitize_context_t *c) const 707 { 708 TRACE_SANITIZE (this); 709 return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); 710 } 711 712 public: 713 LenType len; 714 Type arrayZ[HB_VAR_ARRAY]; 715 public: 716 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 717 }; 718 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>; 719 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>; 720 using PString = ArrayOf<HBUINT8, HBUINT8>; 721 722 /* Array of Offset's */ 723 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>; 724 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>; 725 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; 726 727 /* Array of offsets relative to the beginning of the array itself. */ 728 template <typename Type> 729 struct List16OfOffset16To : Array16OfOffset16To<Type> 730 { operator []OT::List16OfOffset16To731 const Type& operator [] (int i_) const 732 { 733 unsigned int i = (unsigned int) i_; 734 if (unlikely (i >= this->len)) return Null (Type); 735 return this+this->arrayZ[i]; 736 } operator []OT::List16OfOffset16To737 const Type& operator [] (int i_) 738 { 739 unsigned int i = (unsigned int) i_; 740 if (unlikely (i >= this->len)) return Crap (Type); 741 return this+this->arrayZ[i]; 742 } 743 subsetOT::List16OfOffset16To744 bool subset (hb_subset_context_t *c) const 745 { 746 TRACE_SUBSET (this); 747 struct List16OfOffset16To<Type> *out = c->serializer->embed (*this); 748 if (unlikely (!out)) return_trace (false); 749 unsigned int count = this->len; 750 for (unsigned int i = 0; i < count; i++) 751 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); 752 return_trace (true); 753 } 754 755 template <typename ...Ts> sanitizeOT::List16OfOffset16To756 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 757 { 758 TRACE_SANITIZE (this); 759 return_trace (Array16OfOffset16To<Type>::sanitize (c, this, hb_forward<Ts> (ds)...)); 760 } 761 }; 762 763 /* An array starting at second element. */ 764 template <typename Type, typename LenType=HBUINT16> 765 struct HeadlessArrayOf 766 { 767 static constexpr unsigned item_size = Type::static_size; 768 769 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); 770 operator []OT::HeadlessArrayOf771 const Type& operator [] (int i_) const 772 { 773 unsigned int i = (unsigned int) i_; 774 if (unlikely (i >= lenP1 || !i)) return Null (Type); 775 return arrayZ[i-1]; 776 } operator []OT::HeadlessArrayOf777 Type& operator [] (int i_) 778 { 779 unsigned int i = (unsigned int) i_; 780 if (unlikely (i >= lenP1 || !i)) return Crap (Type); 781 return arrayZ[i-1]; 782 } get_sizeOT::HeadlessArrayOf783 unsigned int get_size () const 784 { return lenP1.static_size + get_length () * Type::static_size; } 785 get_lengthOT::HeadlessArrayOf786 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } 787 as_arrayOT::HeadlessArrayOf788 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } as_arrayOT::HeadlessArrayOf789 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } 790 791 /* Iterator. */ 792 typedef hb_array_t<const Type> iter_t; 793 typedef hb_array_t< Type> writer_t; iterOT::HeadlessArrayOf794 iter_t iter () const { return as_array (); } writerOT::HeadlessArrayOf795 writer_t writer () { return as_array (); } operator iter_tOT::HeadlessArrayOf796 operator iter_t () const { return iter (); } operator writer_tOT::HeadlessArrayOf797 operator writer_t () { return writer (); } 798 serializeOT::HeadlessArrayOf799 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 800 { 801 TRACE_SERIALIZE (this); 802 if (unlikely (!c->extend_min (*this))) return_trace (false); 803 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 804 if (unlikely (!c->extend (*this))) return_trace (false); 805 return_trace (true); 806 } 807 template <typename Iterator, 808 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::HeadlessArrayOf809 bool serialize (hb_serialize_context_t *c, Iterator items) 810 { 811 TRACE_SERIALIZE (this); 812 unsigned count = items.len (); 813 if (unlikely (!serialize (c, count))) return_trace (false); 814 /* TODO Umm. Just exhaust the iterator instead? Being extra 815 * cautious right now.. */ 816 for (unsigned i = 0; i < count; i++, ++items) 817 arrayZ[i] = *items; 818 return_trace (true); 819 } 820 821 template <typename ...Ts> sanitizeOT::HeadlessArrayOf822 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 823 { 824 TRACE_SANITIZE (this); 825 if (unlikely (!sanitize_shallow (c))) return_trace (false); 826 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 827 unsigned int count = get_length (); 828 for (unsigned int i = 0; i < count; i++) 829 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 830 return_trace (false); 831 return_trace (true); 832 } 833 834 private: sanitize_shallowOT::HeadlessArrayOf835 bool sanitize_shallow (hb_sanitize_context_t *c) const 836 { 837 TRACE_SANITIZE (this); 838 return_trace (lenP1.sanitize (c) && 839 (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); 840 } 841 842 public: 843 LenType lenP1; 844 Type arrayZ[HB_VAR_ARRAY]; 845 public: 846 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 847 }; 848 849 /* An array storing length-1. */ 850 template <typename Type, typename LenType=HBUINT16> 851 struct ArrayOfM1 852 { 853 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); 854 operator []OT::ArrayOfM1855 const Type& operator [] (int i_) const 856 { 857 unsigned int i = (unsigned int) i_; 858 if (unlikely (i > lenM1)) return Null (Type); 859 return arrayZ[i]; 860 } operator []OT::ArrayOfM1861 Type& operator [] (int i_) 862 { 863 unsigned int i = (unsigned int) i_; 864 if (unlikely (i > lenM1)) return Crap (Type); 865 return arrayZ[i]; 866 } get_sizeOT::ArrayOfM1867 unsigned int get_size () const 868 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } 869 870 template <typename ...Ts> sanitizeOT::ArrayOfM1871 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 872 { 873 TRACE_SANITIZE (this); 874 if (unlikely (!sanitize_shallow (c))) return_trace (false); 875 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 876 unsigned int count = lenM1 + 1; 877 for (unsigned int i = 0; i < count; i++) 878 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 879 return_trace (false); 880 return_trace (true); 881 } 882 883 private: sanitize_shallowOT::ArrayOfM1884 bool sanitize_shallow (hb_sanitize_context_t *c) const 885 { 886 TRACE_SANITIZE (this); 887 return_trace (lenM1.sanitize (c) && 888 (c->check_array (arrayZ, lenM1 + 1))); 889 } 890 891 public: 892 LenType lenM1; 893 Type arrayZ[HB_VAR_ARRAY]; 894 public: 895 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 896 }; 897 898 /* An array with sorted elements. Supports binary searching. */ 899 template <typename Type, typename LenType> 900 struct SortedArrayOf : ArrayOf<Type, LenType> 901 { as_arrayOT::SortedArrayOf902 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } as_arrayOT::SortedArrayOf903 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } 904 905 /* Iterator. */ 906 typedef hb_sorted_array_t<const Type> iter_t; 907 typedef hb_sorted_array_t< Type> writer_t; iterOT::SortedArrayOf908 iter_t iter () const { return as_array (); } writerOT::SortedArrayOf909 writer_t writer () { return as_array (); } operator iter_tOT::SortedArrayOf910 operator iter_t () const { return iter (); } operator writer_tOT::SortedArrayOf911 operator writer_t () { return writer (); } 912 sub_arrayOT::SortedArrayOf913 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 914 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf915 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 916 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf917 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 918 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf919 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 920 { return as_array ().sub_array (start_offset, count); } 921 serializeOT::SortedArrayOf922 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 923 { 924 TRACE_SERIALIZE (this); 925 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); 926 return_trace (ret); 927 } 928 template <typename Iterator, 929 hb_requires (hb_is_sorted_source_of (Iterator, Type))> serializeOT::SortedArrayOf930 bool serialize (hb_serialize_context_t *c, Iterator items) 931 { 932 TRACE_SERIALIZE (this); 933 bool ret = ArrayOf<Type, LenType>::serialize (c, items); 934 return_trace (ret); 935 } 936 937 template <typename T> bsearchOT::SortedArrayOf938 Type &bsearch (const T &x, Type ¬_found = Crap (Type)) 939 { return *as_array ().bsearch (x, ¬_found); } 940 template <typename T> bsearchOT::SortedArrayOf941 const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const 942 { return *as_array ().bsearch (x, ¬_found); } 943 template <typename T> bfindOT::SortedArrayOf944 bool bfind (const T &x, unsigned int *i = nullptr, 945 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, 946 unsigned int to_store = (unsigned int) -1) const 947 { return as_array ().bfind (x, i, not_found, to_store); } 948 }; 949 950 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>; 951 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>; 952 953 /* 954 * Binary-search arrays 955 */ 956 957 template <typename LenType=HBUINT16> 958 struct BinSearchHeader 959 { operator uint32_tOT::BinSearchHeader960 operator uint32_t () const { return len; } 961 sanitizeOT::BinSearchHeader962 bool sanitize (hb_sanitize_context_t *c) const 963 { 964 TRACE_SANITIZE (this); 965 return_trace (c->check_struct (this)); 966 } 967 operator =OT::BinSearchHeader968 BinSearchHeader& operator = (unsigned int v) 969 { 970 len = v; 971 assert (len == v); 972 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; 973 searchRange = 16 * (1u << entrySelector); 974 rangeShift = v * 16 > searchRange 975 ? 16 * v - searchRange 976 : 0; 977 return *this; 978 } 979 980 protected: 981 LenType len; 982 LenType searchRange; 983 LenType entrySelector; 984 LenType rangeShift; 985 986 public: 987 DEFINE_SIZE_STATIC (8); 988 }; 989 990 template <typename Type, typename LenType=HBUINT16> 991 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; 992 993 994 struct VarSizedBinSearchHeader 995 { 996 sanitizeOT::VarSizedBinSearchHeader997 bool sanitize (hb_sanitize_context_t *c) const 998 { 999 TRACE_SANITIZE (this); 1000 return_trace (c->check_struct (this)); 1001 } 1002 1003 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ 1004 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ 1005 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 1006 * that is less than or equal to the value of nUnits. */ 1007 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than 1008 * or equal to the value of nUnits. */ 1009 HBUINT16 rangeShift; /* The value of unitSize times the difference of the 1010 * value of nUnits minus the largest power of 2 less 1011 * than or equal to the value of nUnits. */ 1012 public: 1013 DEFINE_SIZE_STATIC (10); 1014 }; 1015 1016 template <typename Type> 1017 struct VarSizedBinSearchArrayOf 1018 { 1019 static constexpr unsigned item_size = Type::static_size; 1020 1021 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); 1022 last_is_terminatorOT::VarSizedBinSearchArrayOf1023 bool last_is_terminator () const 1024 { 1025 if (unlikely (!header.nUnits)) return false; 1026 1027 /* Gah. 1028 * 1029 * "The number of termination values that need to be included is table-specific. 1030 * The value that indicates binary search termination is 0xFFFF." */ 1031 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); 1032 unsigned int count = Type::TerminationWordCount; 1033 for (unsigned int i = 0; i < count; i++) 1034 if (words[i] != 0xFFFFu) 1035 return false; 1036 return true; 1037 } 1038 operator []OT::VarSizedBinSearchArrayOf1039 const Type& operator [] (int i_) const 1040 { 1041 unsigned int i = (unsigned int) i_; 1042 if (unlikely (i >= get_length ())) return Null (Type); 1043 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1044 } operator []OT::VarSizedBinSearchArrayOf1045 Type& operator [] (int i_) 1046 { 1047 unsigned int i = (unsigned int) i_; 1048 if (unlikely (i >= get_length ())) return Crap (Type); 1049 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1050 } get_lengthOT::VarSizedBinSearchArrayOf1051 unsigned int get_length () const 1052 { return header.nUnits - last_is_terminator (); } get_sizeOT::VarSizedBinSearchArrayOf1053 unsigned int get_size () const 1054 { return header.static_size + header.nUnits * header.unitSize; } 1055 1056 template <typename ...Ts> sanitizeOT::VarSizedBinSearchArrayOf1057 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1058 { 1059 TRACE_SANITIZE (this); 1060 if (unlikely (!sanitize_shallow (c))) return_trace (false); 1061 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 1062 unsigned int count = get_length (); 1063 for (unsigned int i = 0; i < count; i++) 1064 if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...))) 1065 return_trace (false); 1066 return_trace (true); 1067 } 1068 1069 template <typename T> bsearchOT::VarSizedBinSearchArrayOf1070 const Type *bsearch (const T &key) const 1071 { 1072 unsigned pos; 1073 return hb_bsearch_impl (&pos, 1074 key, 1075 (const void *) bytesZ, 1076 get_length (), 1077 header.unitSize, 1078 _hb_cmp_method<T, Type>) 1079 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) 1080 : nullptr; 1081 } 1082 1083 private: sanitize_shallowOT::VarSizedBinSearchArrayOf1084 bool sanitize_shallow (hb_sanitize_context_t *c) const 1085 { 1086 TRACE_SANITIZE (this); 1087 return_trace (header.sanitize (c) && 1088 Type::static_size <= header.unitSize && 1089 c->check_range (bytesZ.arrayZ, 1090 header.nUnits, 1091 header.unitSize)); 1092 } 1093 1094 protected: 1095 VarSizedBinSearchHeader header; 1096 UnsizedArrayOf<HBUINT8> bytesZ; 1097 public: 1098 DEFINE_SIZE_ARRAY (10, bytesZ); 1099 }; 1100 1101 1102 } /* namespace OT */ 1103 1104 1105 #endif /* HB_OPEN_TYPE_HH */ 1106