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 typename std::conditional<std::is_signed<Type>::value,signed,unsigned>::typeOT::IntType67 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () 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 (std::is_integral<Type2>::value && 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 /* 15-bit unsigned number; top bit used for extension. */ 126 struct HBUINT15 : HBUINT16 127 { 128 /* TODO Flesh out; actually mask top bit. */ operator =OT::HBUINT15129 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; } 130 public: 131 DEFINE_SIZE_STATIC (2); 132 }; 133 134 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ 135 typedef HBINT16 FWORD; 136 137 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ 138 typedef HBINT32 FWORD32; 139 140 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ 141 typedef HBUINT16 UFWORD; 142 143 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ 144 struct F2DOT14 : HBINT16 145 { operator =OT::F2DOT14146 F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } 147 // 16384 means 1<<14 to_floatOT::F2DOT14148 float to_float () const { return ((int32_t) v) / 16384.f; } set_floatOT::F2DOT14149 void set_float (float f) { v = roundf (f * 16384.f); } 150 public: 151 DEFINE_SIZE_STATIC (2); 152 }; 153 154 /* 32-bit signed fixed-point number (16.16). */ 155 struct HBFixed : HBINT32 156 { operator =OT::HBFixed157 HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } 158 // 65536 means 1<<16 to_floatOT::HBFixed159 float to_float () const { return ((int32_t) v) / 65536.f; } set_floatOT::HBFixed160 void set_float (float f) { v = roundf (f * 65536.f); } 161 public: 162 DEFINE_SIZE_STATIC (4); 163 }; 164 165 /* Date represented in number of seconds since 12:00 midnight, January 1, 166 * 1904. The value is represented as a signed 64-bit integer. */ 167 struct LONGDATETIME 168 { sanitizeOT::LONGDATETIME169 bool sanitize (hb_sanitize_context_t *c) const 170 { 171 TRACE_SANITIZE (this); 172 return_trace (likely (c->check_struct (this))); 173 } 174 protected: 175 HBINT32 major; 176 HBUINT32 minor; 177 public: 178 DEFINE_SIZE_STATIC (8); 179 }; 180 181 /* Array of four uint8s (length = 32 bits) used to identify a script, language 182 * system, feature, or baseline */ 183 struct Tag : HBUINT32 184 { operator =OT::Tag185 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } 186 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char*OT::Tag187 operator const char* () const { return reinterpret_cast<const char *> (this); } operator char*OT::Tag188 operator char* () { return reinterpret_cast<char *> (this); } 189 public: 190 DEFINE_SIZE_STATIC (4); 191 }; 192 193 /* Glyph index number, same as uint16 (length = 16 bits) */ 194 struct HBGlyphID16 : HBUINT16 195 { operator =OT::HBGlyphID16196 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 197 }; 198 199 /* Script/language-system/feature index */ 200 struct Index : HBUINT16 { 201 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; operator =OT::Index202 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 203 }; 204 DECLARE_NULL_NAMESPACE_BYTES (OT, Index); 205 206 typedef Index NameID; 207 208 struct VarIdx : HBUINT32 { 209 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; operator =OT::VarIdx210 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 211 }; 212 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); 213 214 /* Offset, Null offset = 0 */ 215 template <typename Type, bool has_null=true> 216 struct Offset : Type 217 { operator =OT::Offset218 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } 219 220 typedef Type type; 221 is_nullOT::Offset222 bool is_null () const { return has_null && 0 == *this; } 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 331 332 template <typename ...Ts> serialize_subsetOT::OffsetTo333 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, 334 const void *src_base, Ts&&... ds) 335 { 336 *this = 0; 337 if (src.is_null ()) 338 return false; 339 340 auto *s = c->serializer; 341 342 s->push (); 343 344 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...); 345 346 if (ret || !has_null) 347 s->add_link (*this, s->pop_pack ()); 348 else 349 s->pop_discard (); 350 351 return ret; 352 } 353 354 355 template <typename ...Ts> serialize_serializeOT::OffsetTo356 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds) 357 { 358 *this = 0; 359 360 Type* obj = c->push<Type> (); 361 bool ret = obj->serialize (c, std::forward<Ts> (ds)...); 362 363 if (ret) 364 c->add_link (*this, c->pop_pack ()); 365 else 366 c->pop_discard (); 367 368 return ret; 369 } 370 371 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ 372 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 373 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... 374 */ 375 template <typename ...Ts> serialize_copyOT::OffsetTo376 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 377 const void *src_base, unsigned dst_bias, 378 hb_serialize_context_t::whence_t whence, 379 Ts&&... ds) 380 { 381 *this = 0; 382 if (src.is_null ()) 383 return false; 384 385 c->push (); 386 387 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...); 388 389 c->add_link (*this, c->pop_pack (), whence, dst_bias); 390 391 return ret; 392 } 393 serialize_copyOT::OffsetTo394 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 395 const void *src_base, unsigned dst_bias = 0) 396 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } 397 sanitize_shallowOT::OffsetTo398 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const 399 { 400 TRACE_SANITIZE (this); 401 if (unlikely (!c->check_struct (this))) return_trace (false); 402 if (unlikely (this->is_null ())) return_trace (true); 403 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); 404 return_trace (true); 405 } 406 407 template <typename ...Ts> sanitizeOT::OffsetTo408 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 409 { 410 TRACE_SANITIZE (this); 411 return_trace (sanitize_shallow (c, base) && 412 (this->is_null () || 413 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) || 414 neuter (c))); 415 } 416 417 /* Set the offset to Null */ neuterOT::OffsetTo418 bool neuter (hb_sanitize_context_t *c) const 419 { 420 if (!has_null) return false; 421 return c->try_set (this, 0); 422 } 423 DEFINE_SIZE_STATIC (sizeof (OffsetType)); 424 }; 425 /* Partial specializations. */ 426 template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>; 427 template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>; 428 template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>; 429 430 template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>; 431 template <typename Type> using NNOffset16To = Offset16To<Type, false>; 432 template <typename Type> using NNOffset24To = Offset24To<Type, false>; 433 template <typename Type> using NNOffset32To = Offset32To<Type, false>; 434 435 436 /* 437 * Array Types 438 */ 439 440 template <typename Type> 441 struct UnsizedArrayOf 442 { 443 typedef Type item_t; 444 static constexpr unsigned item_size = hb_static_size (Type); 445 446 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); 447 operator []OT::UnsizedArrayOf448 const Type& operator [] (int i_) const 449 { 450 unsigned int i = (unsigned int) i_; 451 const Type *p = &arrayZ[i]; 452 if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ 453 return *p; 454 } operator []OT::UnsizedArrayOf455 Type& operator [] (int i_) 456 { 457 unsigned int i = (unsigned int) i_; 458 Type *p = &arrayZ[i]; 459 if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ 460 return *p; 461 } 462 get_sizeOT::UnsizedArrayOf463 unsigned int get_size (unsigned int len) const 464 { return len * Type::static_size; } 465 operator T*OT::UnsizedArrayOf466 template <typename T> operator T * () { return arrayZ; } operator const T*OT::UnsizedArrayOf467 template <typename T> operator const T * () const { return arrayZ; } as_arrayOT::UnsizedArrayOf468 hb_array_t<Type> as_array (unsigned int len) 469 { return hb_array (arrayZ, len); } as_arrayOT::UnsizedArrayOf470 hb_array_t<const Type> as_array (unsigned int len) const 471 { return hb_array (arrayZ, len); } 472 473 template <typename T> lsearchOT::UnsizedArrayOf474 Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 475 { return *as_array (len).lsearch (x, ¬_found); } 476 template <typename T> lsearchOT::UnsizedArrayOf477 const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 478 { return *as_array (len).lsearch (x, ¬_found); } 479 template <typename T> lfindOT::UnsizedArrayOf480 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr, 481 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 482 unsigned int to_store = (unsigned int) -1) const 483 { return as_array (len).lfind (x, i, not_found, to_store); } 484 qsortOT::UnsizedArrayOf485 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) 486 { as_array (len).qsort (start, end); } 487 serializeOT::UnsizedArrayOf488 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 489 { 490 TRACE_SERIALIZE (this); 491 if (unlikely (!c->extend (this, items_len))) return_trace (false); 492 return_trace (true); 493 } 494 template <typename Iterator, 495 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::UnsizedArrayOf496 bool serialize (hb_serialize_context_t *c, Iterator items) 497 { 498 TRACE_SERIALIZE (this); 499 unsigned count = items.len (); 500 if (unlikely (!serialize (c, count))) return_trace (false); 501 /* TODO Umm. Just exhaust the iterator instead? Being extra 502 * cautious right now.. */ 503 for (unsigned i = 0; i < count; i++, ++items) 504 arrayZ[i] = *items; 505 return_trace (true); 506 } 507 copyOT::UnsizedArrayOf508 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const 509 { 510 TRACE_SERIALIZE (this); 511 auto *out = c->start_embed (this); 512 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); 513 return_trace (out); 514 } 515 516 template <typename ...Ts> sanitizeOT::UnsizedArrayOf517 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 518 { 519 TRACE_SANITIZE (this); 520 if (unlikely (!sanitize_shallow (c, count))) return_trace (false); 521 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); 522 for (unsigned int i = 0; i < count; i++) 523 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 524 return_trace (false); 525 return_trace (true); 526 } 527 sanitize_shallowOT::UnsizedArrayOf528 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const 529 { 530 TRACE_SANITIZE (this); 531 return_trace (c->check_array (arrayZ, count)); 532 } 533 534 public: 535 Type arrayZ[HB_VAR_ARRAY]; 536 public: 537 DEFINE_SIZE_UNBOUNDED (0); 538 }; 539 540 /* Unsized array of offset's */ 541 template <typename Type, typename OffsetType, bool has_null=true> 542 using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; 543 544 /* Unsized array of offsets relative to the beginning of the array itself. */ 545 template <typename Type, typename OffsetType, bool has_null=true> 546 struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 547 { operator []OT::UnsizedListOfOffset16To548 const Type& operator [] (int i_) const 549 { 550 unsigned int i = (unsigned int) i_; 551 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 552 if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ 553 return this+*p; 554 } operator []OT::UnsizedListOfOffset16To555 Type& operator [] (int i_) 556 { 557 unsigned int i = (unsigned int) i_; 558 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 559 if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ 560 return this+*p; 561 } 562 563 template <typename ...Ts> sanitizeOT::UnsizedListOfOffset16To564 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 565 { 566 TRACE_SANITIZE (this); 567 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 568 ::sanitize (c, count, this, std::forward<Ts> (ds)...))); 569 } 570 }; 571 572 /* An array with sorted elements. Supports binary searching. */ 573 template <typename Type> 574 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 575 { as_arrayOT::SortedUnsizedArrayOf576 hb_sorted_array_t<Type> as_array (unsigned int len) 577 { return hb_sorted_array (this->arrayZ, len); } as_arrayOT::SortedUnsizedArrayOf578 hb_sorted_array_t<const Type> as_array (unsigned int len) const 579 { return hb_sorted_array (this->arrayZ, len); } operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf580 operator hb_sorted_array_t<Type> () { return as_array (); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf581 operator hb_sorted_array_t<const Type> () const { return as_array (); } 582 583 template <typename T> bsearchOT::SortedUnsizedArrayOf584 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 585 { return *as_array (len).bsearch (x, ¬_found); } 586 template <typename T> bsearchOT::SortedUnsizedArrayOf587 const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 588 { return *as_array (len).bsearch (x, ¬_found); } 589 template <typename T> bfindOT::SortedUnsizedArrayOf590 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, 591 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 592 unsigned int to_store = (unsigned int) -1) const 593 { return as_array (len).bfind (x, i, not_found, to_store); } 594 }; 595 596 597 /* An array with a number of elements. */ 598 template <typename Type, typename LenType> 599 struct ArrayOf 600 { 601 typedef Type item_t; 602 static constexpr unsigned item_size = hb_static_size (Type); 603 604 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); 605 operator []OT::ArrayOf606 const Type& operator [] (int i_) const 607 { 608 unsigned int i = (unsigned int) i_; 609 if (unlikely (i >= len)) return Null (Type); 610 return arrayZ[i]; 611 } operator []OT::ArrayOf612 Type& operator [] (int i_) 613 { 614 unsigned int i = (unsigned int) i_; 615 if (unlikely (i >= len)) return Crap (Type); 616 return arrayZ[i]; 617 } 618 get_sizeOT::ArrayOf619 unsigned int get_size () const 620 { return len.static_size + len * Type::static_size; } 621 operator boolOT::ArrayOf622 explicit operator bool () const { return len; } 623 popOT::ArrayOf624 void pop () { len--; } 625 as_arrayOT::ArrayOf626 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } as_arrayOT::ArrayOf627 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } 628 629 /* Iterator. */ 630 typedef hb_array_t<const Type> iter_t; 631 typedef hb_array_t< Type> writer_t; iterOT::ArrayOf632 iter_t iter () const { return as_array (); } writerOT::ArrayOf633 writer_t writer () { return as_array (); } operator iter_tOT::ArrayOf634 operator iter_t () const { return iter (); } operator writer_tOT::ArrayOf635 operator writer_t () { return writer (); } 636 sub_arrayOT::ArrayOf637 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 638 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf639 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 640 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf641 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 642 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf643 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 644 { return as_array ().sub_array (start_offset, count); } 645 646 template <typename T> lsearchOT::ArrayOf647 Type &lsearch (const T &x, Type ¬_found = Crap (Type)) 648 { return *as_array ().lsearch (x, ¬_found); } 649 template <typename T> lsearchOT::ArrayOf650 const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const 651 { return *as_array ().lsearch (x, ¬_found); } 652 template <typename T> lfindOT::ArrayOf653 bool lfind (const T &x, unsigned int *i = nullptr, 654 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 655 unsigned int to_store = (unsigned int) -1) const 656 { return as_array ().lfind (x, i, not_found, to_store); } 657 qsortOT::ArrayOf658 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) 659 { as_array ().qsort (start, end); } 660 serializeOT::ArrayOf661 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) 662 { 663 TRACE_SERIALIZE (this); 664 if (unlikely (!c->extend_min (this))) return_trace (false); 665 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 666 if (unlikely (!c->extend (this))) return_trace (false); 667 return_trace (true); 668 } 669 template <typename Iterator, 670 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::ArrayOf671 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 672 { 673 TRACE_SERIALIZE (this); 674 unsigned count = items.len (); 675 if (unlikely (!serialize (c, count))) return_trace (false); 676 /* TODO Umm. Just exhaust the iterator instead? Being extra 677 * cautious right now.. */ 678 for (unsigned i = 0; i < count; i++, ++items) 679 arrayZ[i] = *items; 680 return_trace (true); 681 } 682 serialize_appendOT::ArrayOf683 Type* serialize_append (hb_serialize_context_t *c) 684 { 685 TRACE_SERIALIZE (this); 686 len++; 687 if (unlikely (!len || !c->extend (this))) 688 { 689 len--; 690 return_trace (nullptr); 691 } 692 return_trace (&arrayZ[len - 1]); 693 } 694 copyOT::ArrayOf695 ArrayOf* copy (hb_serialize_context_t *c) const 696 { 697 TRACE_SERIALIZE (this); 698 auto *out = c->start_embed (this); 699 if (unlikely (!c->extend_min (out))) return_trace (nullptr); 700 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 701 if (unlikely (!as_array ().copy (c))) return_trace (nullptr); 702 return_trace (out); 703 } 704 705 template <typename ...Ts> sanitizeOT::ArrayOf706 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 707 { 708 TRACE_SANITIZE (this); 709 if (unlikely (!sanitize_shallow (c))) return_trace (false); 710 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); 711 unsigned int count = len; 712 for (unsigned int i = 0; i < count; i++) 713 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 714 return_trace (false); 715 return_trace (true); 716 } 717 sanitize_shallowOT::ArrayOf718 bool sanitize_shallow (hb_sanitize_context_t *c) const 719 { 720 TRACE_SANITIZE (this); 721 return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); 722 } 723 724 public: 725 LenType len; 726 Type arrayZ[HB_VAR_ARRAY]; 727 public: 728 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 729 }; 730 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>; 731 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>; 732 using PString = ArrayOf<HBUINT8, HBUINT8>; 733 734 /* Array of Offset's */ 735 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>; 736 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>; 737 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; 738 739 /* Array of offsets relative to the beginning of the array itself. */ 740 template <typename Type> 741 struct List16OfOffset16To : Array16OfOffset16To<Type> 742 { operator []OT::List16OfOffset16To743 const Type& operator [] (int i_) const 744 { 745 unsigned int i = (unsigned int) i_; 746 if (unlikely (i >= this->len)) return Null (Type); 747 return this+this->arrayZ[i]; 748 } operator []OT::List16OfOffset16To749 const Type& operator [] (int i_) 750 { 751 unsigned int i = (unsigned int) i_; 752 if (unlikely (i >= this->len)) return Crap (Type); 753 return this+this->arrayZ[i]; 754 } 755 subsetOT::List16OfOffset16To756 bool subset (hb_subset_context_t *c) const 757 { 758 TRACE_SUBSET (this); 759 struct List16OfOffset16To<Type> *out = c->serializer->embed (*this); 760 if (unlikely (!out)) return_trace (false); 761 unsigned int count = this->len; 762 for (unsigned int i = 0; i < count; i++) 763 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); 764 return_trace (true); 765 } 766 767 template <typename ...Ts> sanitizeOT::List16OfOffset16To768 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 769 { 770 TRACE_SANITIZE (this); 771 return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...)); 772 } 773 }; 774 775 /* An array starting at second element. */ 776 template <typename Type, typename LenType=HBUINT16> 777 struct HeadlessArrayOf 778 { 779 static constexpr unsigned item_size = Type::static_size; 780 781 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); 782 operator []OT::HeadlessArrayOf783 const Type& operator [] (int i_) const 784 { 785 unsigned int i = (unsigned int) i_; 786 if (unlikely (i >= lenP1 || !i)) return Null (Type); 787 return arrayZ[i-1]; 788 } operator []OT::HeadlessArrayOf789 Type& operator [] (int i_) 790 { 791 unsigned int i = (unsigned int) i_; 792 if (unlikely (i >= lenP1 || !i)) return Crap (Type); 793 return arrayZ[i-1]; 794 } get_sizeOT::HeadlessArrayOf795 unsigned int get_size () const 796 { return lenP1.static_size + get_length () * Type::static_size; } 797 get_lengthOT::HeadlessArrayOf798 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } 799 as_arrayOT::HeadlessArrayOf800 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } as_arrayOT::HeadlessArrayOf801 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } 802 803 /* Iterator. */ 804 typedef hb_array_t<const Type> iter_t; 805 typedef hb_array_t< Type> writer_t; iterOT::HeadlessArrayOf806 iter_t iter () const { return as_array (); } writerOT::HeadlessArrayOf807 writer_t writer () { return as_array (); } operator iter_tOT::HeadlessArrayOf808 operator iter_t () const { return iter (); } operator writer_tOT::HeadlessArrayOf809 operator writer_t () { return writer (); } 810 serializeOT::HeadlessArrayOf811 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 812 { 813 TRACE_SERIALIZE (this); 814 if (unlikely (!c->extend_min (this))) return_trace (false); 815 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 816 if (unlikely (!c->extend (this))) return_trace (false); 817 return_trace (true); 818 } 819 template <typename Iterator, 820 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::HeadlessArrayOf821 bool serialize (hb_serialize_context_t *c, Iterator items) 822 { 823 TRACE_SERIALIZE (this); 824 unsigned count = items.len (); 825 if (unlikely (!serialize (c, count))) return_trace (false); 826 /* TODO Umm. Just exhaust the iterator instead? Being extra 827 * cautious right now.. */ 828 for (unsigned i = 0; i < count; i++, ++items) 829 arrayZ[i] = *items; 830 return_trace (true); 831 } 832 833 template <typename ...Ts> sanitizeOT::HeadlessArrayOf834 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 835 { 836 TRACE_SANITIZE (this); 837 if (unlikely (!sanitize_shallow (c))) return_trace (false); 838 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); 839 unsigned int count = get_length (); 840 for (unsigned int i = 0; i < count; i++) 841 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 842 return_trace (false); 843 return_trace (true); 844 } 845 846 private: sanitize_shallowOT::HeadlessArrayOf847 bool sanitize_shallow (hb_sanitize_context_t *c) const 848 { 849 TRACE_SANITIZE (this); 850 return_trace (lenP1.sanitize (c) && 851 (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); 852 } 853 854 public: 855 LenType lenP1; 856 Type arrayZ[HB_VAR_ARRAY]; 857 public: 858 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 859 }; 860 861 /* An array storing length-1. */ 862 template <typename Type, typename LenType=HBUINT16> 863 struct ArrayOfM1 864 { 865 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); 866 operator []OT::ArrayOfM1867 const Type& operator [] (int i_) const 868 { 869 unsigned int i = (unsigned int) i_; 870 if (unlikely (i > lenM1)) return Null (Type); 871 return arrayZ[i]; 872 } operator []OT::ArrayOfM1873 Type& operator [] (int i_) 874 { 875 unsigned int i = (unsigned int) i_; 876 if (unlikely (i > lenM1)) return Crap (Type); 877 return arrayZ[i]; 878 } get_sizeOT::ArrayOfM1879 unsigned int get_size () const 880 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } 881 882 template <typename ...Ts> sanitizeOT::ArrayOfM1883 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 884 { 885 TRACE_SANITIZE (this); 886 if (unlikely (!sanitize_shallow (c))) return_trace (false); 887 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); 888 unsigned int count = lenM1 + 1; 889 for (unsigned int i = 0; i < count; i++) 890 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 891 return_trace (false); 892 return_trace (true); 893 } 894 895 private: sanitize_shallowOT::ArrayOfM1896 bool sanitize_shallow (hb_sanitize_context_t *c) const 897 { 898 TRACE_SANITIZE (this); 899 return_trace (lenM1.sanitize (c) && 900 (c->check_array (arrayZ, lenM1 + 1))); 901 } 902 903 public: 904 LenType lenM1; 905 Type arrayZ[HB_VAR_ARRAY]; 906 public: 907 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 908 }; 909 910 /* An array with sorted elements. Supports binary searching. */ 911 template <typename Type, typename LenType> 912 struct SortedArrayOf : ArrayOf<Type, LenType> 913 { as_arrayOT::SortedArrayOf914 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } as_arrayOT::SortedArrayOf915 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } 916 917 /* Iterator. */ 918 typedef hb_sorted_array_t<const Type> iter_t; 919 typedef hb_sorted_array_t< Type> writer_t; iterOT::SortedArrayOf920 iter_t iter () const { return as_array (); } writerOT::SortedArrayOf921 writer_t writer () { return as_array (); } operator iter_tOT::SortedArrayOf922 operator iter_t () const { return iter (); } operator writer_tOT::SortedArrayOf923 operator writer_t () { return writer (); } 924 sub_arrayOT::SortedArrayOf925 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 926 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf927 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 928 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf929 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 930 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf931 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 932 { return as_array ().sub_array (start_offset, count); } 933 serializeOT::SortedArrayOf934 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 935 { 936 TRACE_SERIALIZE (this); 937 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); 938 return_trace (ret); 939 } 940 template <typename Iterator, 941 hb_requires (hb_is_sorted_source_of (Iterator, Type))> serializeOT::SortedArrayOf942 bool serialize (hb_serialize_context_t *c, Iterator items) 943 { 944 TRACE_SERIALIZE (this); 945 bool ret = ArrayOf<Type, LenType>::serialize (c, items); 946 return_trace (ret); 947 } 948 949 template <typename T> bsearchOT::SortedArrayOf950 Type &bsearch (const T &x, Type ¬_found = Crap (Type)) 951 { return *as_array ().bsearch (x, ¬_found); } 952 template <typename T> bsearchOT::SortedArrayOf953 const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const 954 { return *as_array ().bsearch (x, ¬_found); } 955 template <typename T> bfindOT::SortedArrayOf956 bool bfind (const T &x, unsigned int *i = nullptr, 957 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 958 unsigned int to_store = (unsigned int) -1) const 959 { return as_array ().bfind (x, i, not_found, to_store); } 960 }; 961 962 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>; 963 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>; 964 965 /* 966 * Binary-search arrays 967 */ 968 969 template <typename LenType=HBUINT16> 970 struct BinSearchHeader 971 { operator uint32_tOT::BinSearchHeader972 operator uint32_t () const { return len; } 973 sanitizeOT::BinSearchHeader974 bool sanitize (hb_sanitize_context_t *c) const 975 { 976 TRACE_SANITIZE (this); 977 return_trace (c->check_struct (this)); 978 } 979 operator =OT::BinSearchHeader980 BinSearchHeader& operator = (unsigned int v) 981 { 982 len = v; 983 assert (len == v); 984 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; 985 searchRange = 16 * (1u << entrySelector); 986 rangeShift = v * 16 > searchRange 987 ? 16 * v - searchRange 988 : 0; 989 return *this; 990 } 991 992 protected: 993 LenType len; 994 LenType searchRange; 995 LenType entrySelector; 996 LenType rangeShift; 997 998 public: 999 DEFINE_SIZE_STATIC (8); 1000 }; 1001 1002 template <typename Type, typename LenType=HBUINT16> 1003 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; 1004 1005 1006 struct VarSizedBinSearchHeader 1007 { 1008 sanitizeOT::VarSizedBinSearchHeader1009 bool sanitize (hb_sanitize_context_t *c) const 1010 { 1011 TRACE_SANITIZE (this); 1012 return_trace (c->check_struct (this)); 1013 } 1014 1015 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ 1016 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ 1017 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 1018 * that is less than or equal to the value of nUnits. */ 1019 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than 1020 * or equal to the value of nUnits. */ 1021 HBUINT16 rangeShift; /* The value of unitSize times the difference of the 1022 * value of nUnits minus the largest power of 2 less 1023 * than or equal to the value of nUnits. */ 1024 public: 1025 DEFINE_SIZE_STATIC (10); 1026 }; 1027 1028 template <typename Type> 1029 struct VarSizedBinSearchArrayOf 1030 { 1031 static constexpr unsigned item_size = Type::static_size; 1032 1033 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); 1034 last_is_terminatorOT::VarSizedBinSearchArrayOf1035 bool last_is_terminator () const 1036 { 1037 if (unlikely (!header.nUnits)) return false; 1038 1039 /* Gah. 1040 * 1041 * "The number of termination values that need to be included is table-specific. 1042 * The value that indicates binary search termination is 0xFFFF." */ 1043 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); 1044 unsigned int count = Type::TerminationWordCount; 1045 for (unsigned int i = 0; i < count; i++) 1046 if (words[i] != 0xFFFFu) 1047 return false; 1048 return true; 1049 } 1050 operator []OT::VarSizedBinSearchArrayOf1051 const Type& operator [] (int i_) const 1052 { 1053 unsigned int i = (unsigned int) i_; 1054 if (unlikely (i >= get_length ())) return Null (Type); 1055 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1056 } operator []OT::VarSizedBinSearchArrayOf1057 Type& operator [] (int i_) 1058 { 1059 unsigned int i = (unsigned int) i_; 1060 if (unlikely (i >= get_length ())) return Crap (Type); 1061 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1062 } get_lengthOT::VarSizedBinSearchArrayOf1063 unsigned int get_length () const 1064 { return header.nUnits - last_is_terminator (); } get_sizeOT::VarSizedBinSearchArrayOf1065 unsigned int get_size () const 1066 { return header.static_size + header.nUnits * header.unitSize; } 1067 1068 template <typename ...Ts> sanitizeOT::VarSizedBinSearchArrayOf1069 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1070 { 1071 TRACE_SANITIZE (this); 1072 if (unlikely (!sanitize_shallow (c))) return_trace (false); 1073 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); 1074 unsigned int count = get_length (); 1075 for (unsigned int i = 0; i < count; i++) 1076 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) 1077 return_trace (false); 1078 return_trace (true); 1079 } 1080 1081 template <typename T> bsearchOT::VarSizedBinSearchArrayOf1082 const Type *bsearch (const T &key) const 1083 { 1084 unsigned pos; 1085 return hb_bsearch_impl (&pos, 1086 key, 1087 (const void *) bytesZ, 1088 get_length (), 1089 header.unitSize, 1090 _hb_cmp_method<T, Type>) 1091 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) 1092 : nullptr; 1093 } 1094 1095 private: sanitize_shallowOT::VarSizedBinSearchArrayOf1096 bool sanitize_shallow (hb_sanitize_context_t *c) const 1097 { 1098 TRACE_SANITIZE (this); 1099 return_trace (header.sanitize (c) && 1100 Type::static_size <= header.unitSize && 1101 c->check_range (bytesZ.arrayZ, 1102 header.nUnits, 1103 header.unitSize)); 1104 } 1105 1106 protected: 1107 VarSizedBinSearchHeader header; 1108 UnsizedArrayOf<HBUINT8> bytesZ; 1109 public: 1110 DEFINE_SIZE_ARRAY (10, bytesZ); 1111 }; 1112 1113 1114 } /* namespace OT */ 1115 1116 1117 #endif /* HB_OPEN_TYPE_HH */ 1118