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-meta.hh" 37 #include "hb-subset.hh" 38 39 40 namespace OT { 41 42 43 /* 44 * 45 * The OpenType Font File: Data Types 46 */ 47 48 49 /* "The following data types are used in the OpenType font file. 50 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 51 52 /* 53 * Int types 54 */ 55 56 /* Integer types in big-endian order and no alignment requirement */ 57 template <typename Type, 58 unsigned int Size = sizeof (Type)> 59 struct IntType 60 { 61 typedef Type type; 62 63 IntType () = default; IntTypeOT::IntType64 explicit constexpr IntType (Type V) : v {V} {} operator =OT::IntType65 IntType& operator = (Type i) { v = i; return *this; } 66 /* For reason we define cast out operator for signed/unsigned, instead of Type, see: 67 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ operator typename std::conditional<std::is_signed<Type>::value,signed,unsigned>::typeOT::IntType68 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; } 69 operator ==OT::IntType70 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } operator !=OT::IntType71 bool operator != (const IntType &o) const { return !(*this == o); } 72 operator +=OT::IntType73 IntType& operator += (unsigned count) { *this = *this + count; return *this; } operator -=OT::IntType74 IntType& operator -= (unsigned count) { *this = *this - count; return *this; } operator ++OT::IntType75 IntType& operator ++ () { *this += 1; return *this; } operator --OT::IntType76 IntType& operator -- () { *this -= 1; return *this; } operator ++OT::IntType77 IntType operator ++ (int) { IntType c (*this); ++*this; return c; } operator --OT::IntType78 IntType operator -- (int) { IntType c (*this); --*this; return c; } 79 cmpOT::IntType80 HB_INTERNAL static int cmp (const IntType *a, const IntType *b) 81 { return b->cmp (*a); } cmpOT::IntType82 HB_INTERNAL static int cmp (const void *a, const void *b) 83 { 84 IntType *pa = (IntType *) a; 85 IntType *pb = (IntType *) b; 86 87 return pb->cmp (*pa); 88 } 89 template <typename Type2, 90 hb_enable_if (std::is_integral<Type2>::value && 91 sizeof (Type2) < sizeof (int) && 92 sizeof (Type) < sizeof (int))> cmpOT::IntType93 int cmp (Type2 a) const 94 { 95 Type b = v; 96 return (int) a - (int) b; 97 } 98 template <typename Type2, 99 hb_enable_if (hb_is_convertible (Type2, Type))> cmpOT::IntType100 int cmp (Type2 a) const 101 { 102 Type b = v; 103 return a < b ? -1 : a == b ? 0 : +1; 104 } sanitizeOT::IntType105 bool sanitize (hb_sanitize_context_t *c) const 106 { 107 TRACE_SANITIZE (this); 108 return_trace (c->check_struct (this)); 109 } 110 protected: 111 BEInt<Type, Size> v; 112 public: 113 DEFINE_SIZE_STATIC (Size); 114 }; 115 116 typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */ 117 typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */ 118 typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */ 119 typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */ 120 typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */ 121 typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */ 122 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. 123 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ 124 typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ 125 126 /* 15-bit unsigned number; top bit used for extension. */ 127 struct HBUINT15 : HBUINT16 128 { 129 /* TODO Flesh out; actually mask top bit. */ operator =OT::HBUINT15130 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; } 131 public: 132 DEFINE_SIZE_STATIC (2); 133 }; 134 135 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ 136 typedef HBINT16 FWORD; 137 138 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ 139 typedef HBINT32 FWORD32; 140 141 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ 142 typedef HBUINT16 UFWORD; 143 144 template <typename Type, unsigned fraction_bits> 145 struct HBFixed : Type 146 { 147 static constexpr float shift = (float) (1 << fraction_bits); 148 static_assert (Type::static_size * 8 > fraction_bits, ""); 149 operator =OT::HBFixed150 HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; } to_floatOT::HBFixed151 float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } set_floatOT::HBFixed152 void set_float (float f) { Type::v = roundf (f * shift); } 153 public: 154 DEFINE_SIZE_STATIC (Type::static_size); 155 }; 156 157 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ 158 using F2DOT14 = HBFixed<HBINT16, 14>; 159 160 /* 16-bit signed fixed number with the low 12 bits of fraction (4.12). */ 161 using F4DOT12 = HBFixed<HBINT16, 12>; 162 163 /* 32-bit signed fixed-point number (16.16). */ 164 using F16DOT16 = HBFixed<HBINT32, 16>; 165 166 /* Date represented in number of seconds since 12:00 midnight, January 1, 167 * 1904. The value is represented as a signed 64-bit integer. */ 168 struct LONGDATETIME 169 { sanitizeOT::LONGDATETIME170 bool sanitize (hb_sanitize_context_t *c) const 171 { 172 TRACE_SANITIZE (this); 173 return_trace (c->check_struct (this)); 174 } 175 protected: 176 HBINT32 major; 177 HBUINT32 minor; 178 public: 179 DEFINE_SIZE_STATIC (8); 180 }; 181 182 /* Array of four uint8s (length = 32 bits) used to identify a script, language 183 * system, feature, or baseline */ 184 struct Tag : HBUINT32 185 { operator =OT::Tag186 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } 187 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char*OT::Tag188 operator const char* () const { return reinterpret_cast<const char *> (this); } operator char*OT::Tag189 operator char* () { return reinterpret_cast<char *> (this); } 190 public: 191 DEFINE_SIZE_STATIC (4); 192 }; 193 194 /* Glyph index number, same as uint16 (length = 16 bits) */ 195 struct HBGlyphID16 : HBUINT16 196 { operator =OT::HBGlyphID16197 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 198 }; 199 struct HBGlyphID24 : HBUINT24 200 { operator =OT::HBGlyphID24201 HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; } 202 }; 203 204 /* Script/language-system/feature index */ 205 struct Index : HBUINT16 { 206 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; operator =OT::Index207 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 208 }; 209 DECLARE_NULL_NAMESPACE_BYTES (OT, Index); 210 211 typedef Index NameID; 212 213 struct VarIdx : HBUINT32 { 214 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; 215 static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); addOT::VarIdx216 static uint32_t add (uint32_t i, unsigned short v) 217 { 218 if (i == NO_VARIATION) return i; 219 return i + v; 220 } operator =OT::VarIdx221 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 222 }; 223 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); 224 225 /* Offset, Null offset = 0 */ 226 template <typename Type, bool has_null=true> 227 struct Offset : Type 228 { operator =OT::Offset229 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } 230 231 typedef Type type; 232 is_nullOT::Offset233 bool is_null () const { return has_null && 0 == *this; } 234 235 public: 236 DEFINE_SIZE_STATIC (sizeof (Type)); 237 }; 238 239 typedef Offset<HBUINT16> Offset16; 240 typedef Offset<HBUINT24> Offset24; 241 typedef Offset<HBUINT32> Offset32; 242 243 244 /* CheckSum */ 245 struct CheckSum : HBUINT32 246 { operator =OT::CheckSum247 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 248 249 /* This is reference implementation from the spec. */ CalcTableChecksumOT::CheckSum250 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) 251 { 252 uint32_t Sum = 0L; 253 assert (0 == (Length & 3)); 254 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; 255 256 while (Table < EndPtr) 257 Sum += *Table++; 258 return Sum; 259 } 260 261 /* Note: data should be 4byte aligned and have 4byte padding at the end. */ set_for_dataOT::CheckSum262 void set_for_data (const void *data, unsigned int length) 263 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } 264 265 public: 266 DEFINE_SIZE_STATIC (4); 267 }; 268 269 270 /* 271 * Version Numbers 272 */ 273 274 template <typename FixedType=HBUINT16> 275 struct FixedVersion 276 { to_intOT::FixedVersion277 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } 278 sanitizeOT::FixedVersion279 bool sanitize (hb_sanitize_context_t *c) const 280 { 281 TRACE_SANITIZE (this); 282 return_trace (c->check_struct (this)); 283 } 284 285 FixedType major; 286 FixedType minor; 287 public: 288 DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); 289 }; 290 291 292 /* 293 * Template subclasses of Offset that do the dereferencing. 294 * Use: (base+offset) 295 */ 296 297 template <typename Type, bool has_null> 298 struct _hb_has_null 299 { get_nullOT::_hb_has_null300 static const Type *get_null () { return nullptr; } get_crapOT::_hb_has_null301 static Type *get_crap () { return nullptr; } 302 }; 303 template <typename Type> 304 struct _hb_has_null<Type, true> 305 { get_nullOT::_hb_has_null306 static const Type *get_null () { return &Null (Type); } get_crapOT::_hb_has_null307 static Type *get_crap () { return &Crap (Type); } 308 }; 309 310 template <typename Type, typename OffsetType, bool has_null=true> 311 struct OffsetTo : Offset<OffsetType, has_null> 312 { 313 // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. 314 static_assert (has_null == false || 315 (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); 316 317 HB_DELETE_COPY_ASSIGN (OffsetTo); 318 OffsetTo () = default; 319 operator =OT::OffsetTo320 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } 321 operator ()OT::OffsetTo322 const Type& operator () (const void *base) const 323 { 324 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); 325 return StructAtOffset<const Type> (base, *this); 326 } operator ()OT::OffsetTo327 Type& operator () (void *base) const 328 { 329 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); 330 return StructAtOffset<Type> (base, *this); 331 } 332 333 template <typename Base, 334 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const Base & base,const OffsetTo & offset)335 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } 336 template <typename Base, 337 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const OffsetTo & offset,const Base & base)338 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } 339 template <typename Base, 340 hb_enable_if (hb_is_convertible (Base, void *))> operator +(Base && base,OffsetTo & offset)341 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } 342 template <typename Base, 343 hb_enable_if (hb_is_convertible (Base, void *))> operator +(OffsetTo & offset,Base && base)344 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } 345 346 347 template <typename ...Ts> serialize_subsetOT::OffsetTo348 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, 349 const void *src_base, Ts&&... ds) 350 { 351 *this = 0; 352 if (src.is_null ()) 353 return false; 354 355 auto *s = c->serializer; 356 357 s->push (); 358 359 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...); 360 361 if (ret || !has_null) 362 s->add_link (*this, s->pop_pack ()); 363 else 364 s->pop_discard (); 365 366 return ret; 367 } 368 369 370 template <typename ...Ts> serialize_serializeOT::OffsetTo371 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds) 372 { 373 *this = 0; 374 375 Type* obj = c->push<Type> (); 376 bool ret = obj->serialize (c, std::forward<Ts> (ds)...); 377 378 if (ret) 379 c->add_link (*this, c->pop_pack ()); 380 else 381 c->pop_discard (); 382 383 return ret; 384 } 385 386 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ 387 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 388 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... 389 */ 390 template <typename ...Ts> serialize_copyOT::OffsetTo391 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 392 const void *src_base, unsigned dst_bias, 393 hb_serialize_context_t::whence_t whence, 394 Ts&&... ds) 395 { 396 *this = 0; 397 if (src.is_null ()) 398 return false; 399 400 c->push (); 401 402 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...); 403 404 c->add_link (*this, c->pop_pack (), whence, dst_bias); 405 406 return ret; 407 } 408 serialize_copyOT::OffsetTo409 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 410 const void *src_base, unsigned dst_bias = 0) 411 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } 412 sanitize_shallowOT::OffsetTo413 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const 414 { 415 TRACE_SANITIZE (this); 416 if (unlikely (!c->check_struct (this))) return_trace (false); 417 if (unlikely (this->is_null ())) return_trace (true); 418 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); 419 return_trace (true); 420 } 421 422 template <typename ...Ts> sanitizeOT::OffsetTo423 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 424 { 425 TRACE_SANITIZE (this); 426 return_trace (sanitize_shallow (c, base) && 427 (this->is_null () || 428 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) || 429 neuter (c))); 430 } 431 432 /* Set the offset to Null */ neuterOT::OffsetTo433 bool neuter (hb_sanitize_context_t *c) const 434 { 435 if (!has_null) return false; 436 return c->try_set (this, 0); 437 } 438 DEFINE_SIZE_STATIC (sizeof (OffsetType)); 439 }; 440 /* Partial specializations. */ 441 template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>; 442 template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>; 443 template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>; 444 445 template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>; 446 template <typename Type> using NNOffset16To = Offset16To<Type, false>; 447 template <typename Type> using NNOffset24To = Offset24To<Type, false>; 448 template <typename Type> using NNOffset32To = Offset32To<Type, false>; 449 450 451 /* 452 * Array Types 453 */ 454 455 template <typename Type> 456 struct UnsizedArrayOf 457 { 458 typedef Type item_t; 459 static constexpr unsigned item_size = hb_static_size (Type); 460 461 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); 462 operator []OT::UnsizedArrayOf463 const Type& operator [] (int i_) const 464 { 465 unsigned int i = (unsigned int) i_; 466 const Type *p = &arrayZ[i]; 467 if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */ 468 _hb_compiler_memory_r_barrier (); 469 return *p; 470 } operator []OT::UnsizedArrayOf471 Type& operator [] (int i_) 472 { 473 unsigned int i = (unsigned int) i_; 474 Type *p = &arrayZ[i]; 475 if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */ 476 _hb_compiler_memory_r_barrier (); 477 return *p; 478 } 479 get_sizeOT::UnsizedArrayOf480 unsigned int get_size (unsigned int len) const 481 { return len * Type::static_size; } 482 operator T*OT::UnsizedArrayOf483 template <typename T> operator T * () { return arrayZ; } operator const T*OT::UnsizedArrayOf484 template <typename T> operator const T * () const { return arrayZ; } as_arrayOT::UnsizedArrayOf485 hb_array_t<Type> as_array (unsigned int len) 486 { return hb_array (arrayZ, len); } as_arrayOT::UnsizedArrayOf487 hb_array_t<const Type> as_array (unsigned int len) const 488 { return hb_array (arrayZ, len); } 489 490 template <typename T> lsearchOT::UnsizedArrayOf491 Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 492 { return *as_array (len).lsearch (x, ¬_found); } 493 template <typename T> lsearchOT::UnsizedArrayOf494 const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 495 { return *as_array (len).lsearch (x, ¬_found); } 496 template <typename T> lfindOT::UnsizedArrayOf497 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr, 498 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 499 unsigned int to_store = (unsigned int) -1) const 500 { return as_array (len).lfind (x, i, not_found, to_store); } 501 qsortOT::UnsizedArrayOf502 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) 503 { as_array (len).qsort (start, end); } 504 serializeOT::UnsizedArrayOf505 bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) 506 { 507 TRACE_SERIALIZE (this); 508 if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); 509 return_trace (true); 510 } 511 template <typename Iterator, 512 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::UnsizedArrayOf513 bool serialize (hb_serialize_context_t *c, Iterator items) 514 { 515 TRACE_SERIALIZE (this); 516 unsigned count = hb_len (items); 517 if (unlikely (!serialize (c, count, false))) return_trace (false); 518 /* TODO Umm. Just exhaust the iterator instead? Being extra 519 * cautious right now.. */ 520 for (unsigned i = 0; i < count; i++, ++items) 521 arrayZ[i] = *items; 522 return_trace (true); 523 } 524 copyOT::UnsizedArrayOf525 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const 526 { 527 TRACE_SERIALIZE (this); 528 auto *out = c->start_embed (this); 529 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); 530 return_trace (out); 531 } 532 533 template <typename ...Ts> sanitizeOT::UnsizedArrayOf534 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 535 { 536 TRACE_SANITIZE (this); 537 if (unlikely (!sanitize_shallow (c, count))) return_trace (false); 538 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 539 for (unsigned int i = 0; i < count; i++) 540 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 541 return_trace (false); 542 return_trace (true); 543 } 544 sanitize_shallowOT::UnsizedArrayOf545 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const 546 { 547 TRACE_SANITIZE (this); 548 return_trace (c->check_array (arrayZ, count)); 549 } 550 551 public: 552 Type arrayZ[HB_VAR_ARRAY]; 553 public: 554 DEFINE_SIZE_UNBOUNDED (0); 555 }; 556 557 /* Unsized array of offset's */ 558 template <typename Type, typename OffsetType, bool has_null=true> 559 using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; 560 561 /* Unsized array of offsets relative to the beginning of the array itself. */ 562 template <typename Type, typename OffsetType, bool has_null=true> 563 struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 564 { operator []OT::UnsizedListOfOffset16To565 const Type& operator [] (int i_) const 566 { 567 unsigned int i = (unsigned int) i_; 568 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 569 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ 570 _hb_compiler_memory_r_barrier (); 571 return this+*p; 572 } operator []OT::UnsizedListOfOffset16To573 Type& operator [] (int i_) 574 { 575 unsigned int i = (unsigned int) i_; 576 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 577 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ 578 _hb_compiler_memory_r_barrier (); 579 return this+*p; 580 } 581 582 template <typename ...Ts> sanitizeOT::UnsizedListOfOffset16To583 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 584 { 585 TRACE_SANITIZE (this); 586 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 587 ::sanitize (c, count, this, std::forward<Ts> (ds)...))); 588 } 589 }; 590 591 /* An array with sorted elements. Supports binary searching. */ 592 template <typename Type> 593 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 594 { as_arrayOT::SortedUnsizedArrayOf595 hb_sorted_array_t<Type> as_array (unsigned int len) 596 { return hb_sorted_array (this->arrayZ, len); } as_arrayOT::SortedUnsizedArrayOf597 hb_sorted_array_t<const Type> as_array (unsigned int len) const 598 { return hb_sorted_array (this->arrayZ, len); } operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf599 operator hb_sorted_array_t<Type> () { return as_array (); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf600 operator hb_sorted_array_t<const Type> () const { return as_array (); } 601 602 template <typename T> bsearchOT::SortedUnsizedArrayOf603 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 604 { return *as_array (len).bsearch (x, ¬_found); } 605 template <typename T> bsearchOT::SortedUnsizedArrayOf606 const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 607 { return *as_array (len).bsearch (x, ¬_found); } 608 template <typename T> bfindOT::SortedUnsizedArrayOf609 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, 610 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 611 unsigned int to_store = (unsigned int) -1) const 612 { return as_array (len).bfind (x, i, not_found, to_store); } 613 }; 614 615 616 /* An array with a number of elements. */ 617 template <typename Type, typename LenType> 618 struct ArrayOf 619 { 620 typedef Type item_t; 621 static constexpr unsigned item_size = hb_static_size (Type); 622 623 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); 624 operator []OT::ArrayOf625 const Type& operator [] (int i_) const 626 { 627 unsigned int i = (unsigned int) i_; 628 if (unlikely (i >= len)) return Null (Type); 629 _hb_compiler_memory_r_barrier (); 630 return arrayZ[i]; 631 } operator []OT::ArrayOf632 Type& operator [] (int i_) 633 { 634 unsigned int i = (unsigned int) i_; 635 if (unlikely (i >= len)) return Crap (Type); 636 _hb_compiler_memory_r_barrier (); 637 return arrayZ[i]; 638 } 639 get_sizeOT::ArrayOf640 unsigned int get_size () const 641 { return len.static_size + len * Type::static_size; } 642 operator boolOT::ArrayOf643 explicit operator bool () const { return len; } 644 popOT::ArrayOf645 void pop () { len--; } 646 as_arrayOT::ArrayOf647 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } as_arrayOT::ArrayOf648 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } 649 650 /* Iterator. */ 651 typedef hb_array_t<const Type> iter_t; 652 typedef hb_array_t< Type> writer_t; iterOT::ArrayOf653 iter_t iter () const { return as_array (); } writerOT::ArrayOf654 writer_t writer () { return as_array (); } operator iter_tOT::ArrayOf655 operator iter_t () const { return iter (); } operator writer_tOT::ArrayOf656 operator writer_t () { return writer (); } 657 658 /* Faster range-based for loop. */ beginOT::ArrayOf659 const Type *begin () const { return arrayZ; } endOT::ArrayOf660 const Type *end () const { return arrayZ + len; } 661 662 template <typename T> lsearchOT::ArrayOf663 Type &lsearch (const T &x, Type ¬_found = Crap (Type)) 664 { return *as_array ().lsearch (x, ¬_found); } 665 template <typename T> lsearchOT::ArrayOf666 const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const 667 { return *as_array ().lsearch (x, ¬_found); } 668 template <typename T> lfindOT::ArrayOf669 bool lfind (const T &x, unsigned int *i = nullptr, 670 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 671 unsigned int to_store = (unsigned int) -1) const 672 { return as_array ().lfind (x, i, not_found, to_store); } 673 qsortOT::ArrayOf674 void qsort () 675 { as_array ().qsort (); } 676 serializeOT::ArrayOf677 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) 678 { 679 TRACE_SERIALIZE (this); 680 if (unlikely (!c->extend_min (this))) return_trace (false); 681 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 682 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); 683 return_trace (true); 684 } 685 template <typename Iterator, 686 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::ArrayOf687 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 688 { 689 TRACE_SERIALIZE (this); 690 unsigned count = hb_len (items); 691 if (unlikely (!serialize (c, count, false))) return_trace (false); 692 /* TODO Umm. Just exhaust the iterator instead? Being extra 693 * cautious right now.. */ 694 for (unsigned i = 0; i < count; i++, ++items) 695 arrayZ[i] = *items; 696 return_trace (true); 697 } 698 serialize_appendOT::ArrayOf699 Type* serialize_append (hb_serialize_context_t *c) 700 { 701 TRACE_SERIALIZE (this); 702 len++; 703 if (unlikely (!len || !c->extend (this))) 704 { 705 len--; 706 return_trace (nullptr); 707 } 708 return_trace (&arrayZ[len - 1]); 709 } 710 copyOT::ArrayOf711 ArrayOf* copy (hb_serialize_context_t *c) const 712 { 713 TRACE_SERIALIZE (this); 714 auto *out = c->start_embed (this); 715 if (unlikely (!c->extend_min (out))) return_trace (nullptr); 716 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 717 if (unlikely (!as_array ().copy (c))) return_trace (nullptr); 718 return_trace (out); 719 } 720 721 template <typename ...Ts> sanitizeOT::ArrayOf722 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 723 { 724 TRACE_SANITIZE (this); 725 if (unlikely (!sanitize_shallow (c))) return_trace (false); 726 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 727 unsigned int count = len; 728 for (unsigned int i = 0; i < count; i++) 729 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 730 return_trace (false); 731 return_trace (true); 732 } 733 sanitize_shallowOT::ArrayOf734 bool sanitize_shallow (hb_sanitize_context_t *c) const 735 { 736 TRACE_SANITIZE (this); 737 return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); 738 } 739 740 public: 741 LenType len; 742 Type arrayZ[HB_VAR_ARRAY]; 743 public: 744 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 745 }; 746 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>; 747 template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>; 748 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>; 749 using PString = ArrayOf<HBUINT8, HBUINT8>; 750 751 /* Array of Offset's */ 752 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>; 753 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>; 754 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; 755 756 /* Array of offsets relative to the beginning of the array itself. */ 757 template <typename Type, typename OffsetType> 758 struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16> 759 { operator []OT::List16OfOffsetTo760 const Type& operator [] (int i_) const 761 { 762 unsigned int i = (unsigned int) i_; 763 if (unlikely (i >= this->len)) return Null (Type); 764 _hb_compiler_memory_r_barrier (); 765 return this+this->arrayZ[i]; 766 } operator []OT::List16OfOffsetTo767 const Type& operator [] (int i_) 768 { 769 unsigned int i = (unsigned int) i_; 770 if (unlikely (i >= this->len)) return Crap (Type); 771 _hb_compiler_memory_r_barrier (); 772 return this+this->arrayZ[i]; 773 } 774 subsetOT::List16OfOffsetTo775 bool subset (hb_subset_context_t *c) const 776 { 777 TRACE_SUBSET (this); 778 struct List16OfOffsetTo *out = c->serializer->embed (*this); 779 if (unlikely (!out)) return_trace (false); 780 unsigned int count = this->len; 781 for (unsigned int i = 0; i < count; i++) 782 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); 783 return_trace (true); 784 } 785 786 template <typename ...Ts> sanitizeOT::List16OfOffsetTo787 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 788 { 789 TRACE_SANITIZE (this); 790 return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...))); 791 } 792 }; 793 794 template <typename Type> 795 using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>; 796 797 /* An array starting at second element. */ 798 template <typename Type, typename LenType=HBUINT16> 799 struct HeadlessArrayOf 800 { 801 static constexpr unsigned item_size = Type::static_size; 802 803 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); 804 operator []OT::HeadlessArrayOf805 const Type& operator [] (int i_) const 806 { 807 unsigned int i = (unsigned int) i_; 808 if (unlikely (i >= lenP1 || !i)) return Null (Type); 809 _hb_compiler_memory_r_barrier (); 810 return arrayZ[i-1]; 811 } operator []OT::HeadlessArrayOf812 Type& operator [] (int i_) 813 { 814 unsigned int i = (unsigned int) i_; 815 if (unlikely (i >= lenP1 || !i)) return Crap (Type); 816 _hb_compiler_memory_r_barrier (); 817 return arrayZ[i-1]; 818 } get_sizeOT::HeadlessArrayOf819 unsigned int get_size () const 820 { return lenP1.static_size + get_length () * Type::static_size; } 821 get_lengthOT::HeadlessArrayOf822 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } 823 as_arrayOT::HeadlessArrayOf824 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } as_arrayOT::HeadlessArrayOf825 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } 826 827 /* Iterator. */ 828 typedef hb_array_t<const Type> iter_t; 829 typedef hb_array_t< Type> writer_t; iterOT::HeadlessArrayOf830 iter_t iter () const { return as_array (); } writerOT::HeadlessArrayOf831 writer_t writer () { return as_array (); } operator iter_tOT::HeadlessArrayOf832 operator iter_t () const { return iter (); } operator writer_tOT::HeadlessArrayOf833 operator writer_t () { return writer (); } 834 835 /* Faster range-based for loop. */ beginOT::HeadlessArrayOf836 const Type *begin () const { return arrayZ; } endOT::HeadlessArrayOf837 const Type *end () const { return arrayZ + get_length (); } 838 serializeOT::HeadlessArrayOf839 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) 840 { 841 TRACE_SERIALIZE (this); 842 if (unlikely (!c->extend_min (this))) return_trace (false); 843 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 844 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); 845 return_trace (true); 846 } 847 template <typename Iterator, 848 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::HeadlessArrayOf849 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 850 { 851 TRACE_SERIALIZE (this); 852 unsigned count = hb_len (items); 853 if (unlikely (!serialize (c, count, false))) return_trace (false); 854 /* TODO Umm. Just exhaust the iterator instead? Being extra 855 * cautious right now.. */ 856 for (unsigned i = 0; i < count; i++, ++items) 857 arrayZ[i] = *items; 858 return_trace (true); 859 } 860 861 template <typename ...Ts> sanitizeOT::HeadlessArrayOf862 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 863 { 864 TRACE_SANITIZE (this); 865 if (unlikely (!sanitize_shallow (c))) return_trace (false); 866 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 867 unsigned int count = get_length (); 868 for (unsigned int i = 0; i < count; i++) 869 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 870 return_trace (false); 871 return_trace (true); 872 } 873 874 private: sanitize_shallowOT::HeadlessArrayOf875 bool sanitize_shallow (hb_sanitize_context_t *c) const 876 { 877 TRACE_SANITIZE (this); 878 return_trace (lenP1.sanitize (c) && 879 (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); 880 } 881 882 public: 883 LenType lenP1; 884 Type arrayZ[HB_VAR_ARRAY]; 885 public: 886 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 887 }; 888 889 /* An array storing length-1. */ 890 template <typename Type, typename LenType=HBUINT16> 891 struct ArrayOfM1 892 { 893 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); 894 operator []OT::ArrayOfM1895 const Type& operator [] (int i_) const 896 { 897 unsigned int i = (unsigned int) i_; 898 if (unlikely (i > lenM1)) return Null (Type); 899 _hb_compiler_memory_r_barrier (); 900 return arrayZ[i]; 901 } operator []OT::ArrayOfM1902 Type& operator [] (int i_) 903 { 904 unsigned int i = (unsigned int) i_; 905 if (unlikely (i > lenM1)) return Crap (Type); 906 _hb_compiler_memory_r_barrier (); 907 return arrayZ[i]; 908 } get_sizeOT::ArrayOfM1909 unsigned int get_size () const 910 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } 911 912 template <typename ...Ts> sanitizeOT::ArrayOfM1913 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 914 { 915 TRACE_SANITIZE (this); 916 if (unlikely (!sanitize_shallow (c))) return_trace (false); 917 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 918 unsigned int count = lenM1 + 1; 919 for (unsigned int i = 0; i < count; i++) 920 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 921 return_trace (false); 922 return_trace (true); 923 } 924 925 private: sanitize_shallowOT::ArrayOfM1926 bool sanitize_shallow (hb_sanitize_context_t *c) const 927 { 928 TRACE_SANITIZE (this); 929 return_trace (lenM1.sanitize (c) && 930 (c->check_array (arrayZ, lenM1 + 1))); 931 } 932 933 public: 934 LenType lenM1; 935 Type arrayZ[HB_VAR_ARRAY]; 936 public: 937 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 938 }; 939 940 /* An array with sorted elements. Supports binary searching. */ 941 template <typename Type, typename LenType> 942 struct SortedArrayOf : ArrayOf<Type, LenType> 943 { as_arrayOT::SortedArrayOf944 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } as_arrayOT::SortedArrayOf945 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } 946 947 /* Iterator. */ 948 typedef hb_sorted_array_t<const Type> iter_t; 949 typedef hb_sorted_array_t< Type> writer_t; iterOT::SortedArrayOf950 iter_t iter () const { return as_array (); } writerOT::SortedArrayOf951 writer_t writer () { return as_array (); } operator iter_tOT::SortedArrayOf952 operator iter_t () const { return iter (); } operator writer_tOT::SortedArrayOf953 operator writer_t () { return writer (); } 954 955 /* Faster range-based for loop. */ beginOT::SortedArrayOf956 const Type *begin () const { return this->arrayZ; } endOT::SortedArrayOf957 const Type *end () const { return this->arrayZ + this->len; } 958 serializeOT::SortedArrayOf959 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 960 { 961 TRACE_SERIALIZE (this); 962 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); 963 return_trace (ret); 964 } 965 template <typename Iterator, 966 hb_requires (hb_is_sorted_source_of (Iterator, Type))> serializeOT::SortedArrayOf967 bool serialize (hb_serialize_context_t *c, Iterator items) 968 { 969 TRACE_SERIALIZE (this); 970 bool ret = ArrayOf<Type, LenType>::serialize (c, items); 971 return_trace (ret); 972 } 973 974 template <typename T> bsearchOT::SortedArrayOf975 Type &bsearch (const T &x, Type ¬_found = Crap (Type)) 976 { return *as_array ().bsearch (x, ¬_found); } 977 template <typename T> bsearchOT::SortedArrayOf978 const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const 979 { return *as_array ().bsearch (x, ¬_found); } 980 template <typename T> bfindOT::SortedArrayOf981 bool bfind (const T &x, unsigned int *i = nullptr, 982 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 983 unsigned int to_store = (unsigned int) -1) const 984 { return as_array ().bfind (x, i, not_found, to_store); } 985 }; 986 987 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>; 988 template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>; 989 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>; 990 991 /* 992 * Binary-search arrays 993 */ 994 995 template <typename LenType=HBUINT16> 996 struct BinSearchHeader 997 { operator uint32_tOT::BinSearchHeader998 operator uint32_t () const { return len; } 999 sanitizeOT::BinSearchHeader1000 bool sanitize (hb_sanitize_context_t *c) const 1001 { 1002 TRACE_SANITIZE (this); 1003 return_trace (c->check_struct (this)); 1004 } 1005 operator =OT::BinSearchHeader1006 BinSearchHeader& operator = (unsigned int v) 1007 { 1008 len = v; 1009 assert (len == v); 1010 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; 1011 searchRange = 16 * (1u << entrySelector); 1012 rangeShift = v * 16 > searchRange 1013 ? 16 * v - searchRange 1014 : 0; 1015 return *this; 1016 } 1017 1018 protected: 1019 LenType len; 1020 LenType searchRange; 1021 LenType entrySelector; 1022 LenType rangeShift; 1023 1024 public: 1025 DEFINE_SIZE_STATIC (8); 1026 }; 1027 1028 template <typename Type, typename LenType=HBUINT16> 1029 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; 1030 1031 1032 struct VarSizedBinSearchHeader 1033 { 1034 sanitizeOT::VarSizedBinSearchHeader1035 bool sanitize (hb_sanitize_context_t *c) const 1036 { 1037 TRACE_SANITIZE (this); 1038 return_trace (c->check_struct (this)); 1039 } 1040 1041 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ 1042 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ 1043 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 1044 * that is less than or equal to the value of nUnits. */ 1045 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than 1046 * or equal to the value of nUnits. */ 1047 HBUINT16 rangeShift; /* The value of unitSize times the difference of the 1048 * value of nUnits minus the largest power of 2 less 1049 * than or equal to the value of nUnits. */ 1050 public: 1051 DEFINE_SIZE_STATIC (10); 1052 }; 1053 1054 template <typename Type> 1055 struct VarSizedBinSearchArrayOf 1056 { 1057 static constexpr unsigned item_size = Type::static_size; 1058 1059 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); 1060 last_is_terminatorOT::VarSizedBinSearchArrayOf1061 bool last_is_terminator () const 1062 { 1063 if (unlikely (!header.nUnits)) return false; 1064 1065 /* Gah. 1066 * 1067 * "The number of termination values that need to be included is table-specific. 1068 * The value that indicates binary search termination is 0xFFFF." */ 1069 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); 1070 unsigned int count = Type::TerminationWordCount; 1071 for (unsigned int i = 0; i < count; i++) 1072 if (words[i] != 0xFFFFu) 1073 return false; 1074 return true; 1075 } 1076 operator []OT::VarSizedBinSearchArrayOf1077 const Type& operator [] (int i_) const 1078 { 1079 unsigned int i = (unsigned int) i_; 1080 if (unlikely (i >= get_length ())) return Null (Type); 1081 _hb_compiler_memory_r_barrier (); 1082 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1083 } operator []OT::VarSizedBinSearchArrayOf1084 Type& operator [] (int i_) 1085 { 1086 unsigned int i = (unsigned int) i_; 1087 if (unlikely (i >= get_length ())) return Crap (Type); 1088 _hb_compiler_memory_r_barrier (); 1089 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1090 } get_lengthOT::VarSizedBinSearchArrayOf1091 unsigned int get_length () const 1092 { return header.nUnits - last_is_terminator (); } get_sizeOT::VarSizedBinSearchArrayOf1093 unsigned int get_size () const 1094 { return header.static_size + header.nUnits * header.unitSize; } 1095 1096 template <typename ...Ts> sanitizeOT::VarSizedBinSearchArrayOf1097 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1098 { 1099 TRACE_SANITIZE (this); 1100 if (unlikely (!sanitize_shallow (c))) return_trace (false); 1101 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 1102 unsigned int count = get_length (); 1103 for (unsigned int i = 0; i < count; i++) 1104 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) 1105 return_trace (false); 1106 return_trace (true); 1107 } 1108 1109 template <typename T> bsearchOT::VarSizedBinSearchArrayOf1110 const Type *bsearch (const T &key) const 1111 { 1112 unsigned pos; 1113 return hb_bsearch_impl (&pos, 1114 key, 1115 (const void *) bytesZ, 1116 get_length (), 1117 header.unitSize, 1118 _hb_cmp_method<T, Type>) 1119 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) 1120 : nullptr; 1121 } 1122 1123 private: sanitize_shallowOT::VarSizedBinSearchArrayOf1124 bool sanitize_shallow (hb_sanitize_context_t *c) const 1125 { 1126 TRACE_SANITIZE (this); 1127 return_trace (header.sanitize (c) && 1128 Type::static_size <= header.unitSize && 1129 c->check_range (bytesZ.arrayZ, 1130 header.nUnits, 1131 header.unitSize)); 1132 } 1133 1134 protected: 1135 VarSizedBinSearchHeader header; 1136 UnsizedArrayOf<HBUINT8> bytesZ; 1137 public: 1138 DEFINE_SIZE_ARRAY (10, bytesZ); 1139 }; 1140 1141 1142 } /* namespace OT */ 1143 1144 1145 #endif /* HB_OPEN_TYPE_HH */ 1146