1 /* 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright © 2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef HB_OPEN_TYPE_HH 30 #define HB_OPEN_TYPE_HH 31 32 #include "hb.hh" 33 #include "hb-blob.hh" 34 #include "hb-face.hh" 35 #include "hb-machinery.hh" 36 #include "hb-subset.hh" 37 38 39 namespace OT { 40 41 42 /* 43 * 44 * The OpenType Font File: Data Types 45 */ 46 47 48 /* "The following data types are used in the OpenType font file. 49 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 50 51 /* 52 * Int types 53 */ 54 55 /* Integer types in big-endian order and no alignment requirement */ 56 template <typename Type, unsigned int Size> 57 struct IntType 58 { 59 typedef Type type; 60 typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type; 61 operator =OT::IntType62 IntType& operator = (wide_type i) { v = i; return *this; } operator wide_typeOT::IntType63 operator wide_type () const { return v; } operator ==OT::IntType64 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } operator !=OT::IntType65 bool operator != (const IntType &o) const { return !(*this == o); } 66 operator +=OT::IntType67 IntType& operator += (unsigned count) { *this = *this + count; return *this; } operator -=OT::IntType68 IntType& operator -= (unsigned count) { *this = *this - count; return *this; } operator ++OT::IntType69 IntType& operator ++ () { *this += 1; return *this; } operator --OT::IntType70 IntType& operator -- () { *this -= 1; return *this; } operator ++OT::IntType71 IntType operator ++ (int) { IntType c (*this); ++*this; return c; } operator --OT::IntType72 IntType operator -- (int) { IntType c (*this); --*this; return c; } 73 cmpOT::IntType74 HB_INTERNAL static int cmp (const IntType *a, const IntType *b) 75 { return b->cmp (*a); } 76 template <typename Type2> cmpOT::IntType77 int cmp (Type2 a) const 78 { 79 Type b = v; 80 if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) 81 return (int) a - (int) b; 82 else 83 return a < b ? -1 : a == b ? 0 : +1; 84 } sanitizeOT::IntType85 bool sanitize (hb_sanitize_context_t *c) const 86 { 87 TRACE_SANITIZE (this); 88 return_trace (likely (c->check_struct (this))); 89 } 90 protected: 91 BEInt<Type, Size> v; 92 public: 93 DEFINE_SIZE_STATIC (Size); 94 }; 95 96 typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */ 97 typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */ 98 typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */ 99 typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */ 100 typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */ 101 typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */ 102 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. 103 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ 104 typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ 105 106 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ 107 typedef HBINT16 FWORD; 108 109 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ 110 typedef HBINT32 FWORD32; 111 112 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ 113 typedef HBUINT16 UFWORD; 114 115 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ 116 struct F2DOT14 : HBINT16 117 { operator =OT::F2DOT14118 F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } 119 // 16384 means 1<<14 to_floatOT::F2DOT14120 float to_float () const { return ((int32_t) v) / 16384.f; } set_floatOT::F2DOT14121 void set_float (float f) { v = roundf (f * 16384.f); } 122 public: 123 DEFINE_SIZE_STATIC (2); 124 }; 125 126 /* 32-bit signed fixed-point number (16.16). */ 127 struct HBFixed : HBINT32 128 { operator =OT::HBFixed129 HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } 130 // 65536 means 1<<16 to_floatOT::HBFixed131 float to_float () const { return ((int32_t) v) / 65536.f; } set_floatOT::HBFixed132 void set_float (float f) { v = roundf (f * 65536.f); } 133 public: 134 DEFINE_SIZE_STATIC (4); 135 }; 136 137 /* Date represented in number of seconds since 12:00 midnight, January 1, 138 * 1904. The value is represented as a signed 64-bit integer. */ 139 struct LONGDATETIME 140 { sanitizeOT::LONGDATETIME141 bool sanitize (hb_sanitize_context_t *c) const 142 { 143 TRACE_SANITIZE (this); 144 return_trace (likely (c->check_struct (this))); 145 } 146 protected: 147 HBINT32 major; 148 HBUINT32 minor; 149 public: 150 DEFINE_SIZE_STATIC (8); 151 }; 152 153 /* Array of four uint8s (length = 32 bits) used to identify a script, language 154 * system, feature, or baseline */ 155 struct Tag : HBUINT32 156 { operator =OT::Tag157 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } 158 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char*OT::Tag159 operator const char* () const { return reinterpret_cast<const char *> (&this->v); } operator char*OT::Tag160 operator char* () { return reinterpret_cast<char *> (&this->v); } 161 public: 162 DEFINE_SIZE_STATIC (4); 163 }; 164 165 /* Glyph index number, same as uint16 (length = 16 bits) */ 166 struct HBGlyphID : HBUINT16 167 { operator =OT::HBGlyphID168 HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 169 }; 170 171 /* Script/language-system/feature index */ 172 struct Index : HBUINT16 { 173 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; operator =OT::Index174 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 175 }; 176 DECLARE_NULL_NAMESPACE_BYTES (OT, Index); 177 178 typedef Index NameID; 179 180 /* Offset, Null offset = 0 */ 181 template <typename Type, bool has_null=true> 182 struct Offset : Type 183 { operator =OT::Offset184 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } 185 186 typedef Type type; 187 is_nullOT::Offset188 bool is_null () const { return has_null && 0 == *this; } 189 serializeOT::Offset190 void *serialize (hb_serialize_context_t *c, const void *base) 191 { 192 void *t = c->start_embed<void> (); 193 c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); 194 return t; 195 } 196 197 public: 198 DEFINE_SIZE_STATIC (sizeof (Type)); 199 }; 200 201 typedef Offset<HBUINT16> Offset16; 202 typedef Offset<HBUINT32> Offset32; 203 204 205 /* CheckSum */ 206 struct CheckSum : HBUINT32 207 { operator =OT::CheckSum208 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 209 210 /* This is reference implementation from the spec. */ CalcTableChecksumOT::CheckSum211 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) 212 { 213 uint32_t Sum = 0L; 214 assert (0 == (Length & 3)); 215 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; 216 217 while (Table < EndPtr) 218 Sum += *Table++; 219 return Sum; 220 } 221 222 /* Note: data should be 4byte aligned and have 4byte padding at the end. */ set_for_dataOT::CheckSum223 void set_for_data (const void *data, unsigned int length) 224 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } 225 226 public: 227 DEFINE_SIZE_STATIC (4); 228 }; 229 230 231 /* 232 * Version Numbers 233 */ 234 235 template <typename FixedType=HBUINT16> 236 struct FixedVersion 237 { to_intOT::FixedVersion238 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } 239 sanitizeOT::FixedVersion240 bool sanitize (hb_sanitize_context_t *c) const 241 { 242 TRACE_SANITIZE (this); 243 return_trace (c->check_struct (this)); 244 } 245 246 FixedType major; 247 FixedType minor; 248 public: 249 DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); 250 }; 251 252 253 /* 254 * Template subclasses of Offset that do the dereferencing. 255 * Use: (base+offset) 256 */ 257 258 template <typename Type, bool has_null> 259 struct _hb_has_null 260 { get_nullOT::_hb_has_null261 static const Type *get_null () { return nullptr; } get_crapOT::_hb_has_null262 static Type *get_crap () { return nullptr; } 263 }; 264 template <typename Type> 265 struct _hb_has_null<Type, true> 266 { get_nullOT::_hb_has_null267 static const Type *get_null () { return &Null (Type); } get_crapOT::_hb_has_null268 static Type *get_crap () { return &Crap (Type); } 269 }; 270 271 template <typename Type, typename OffsetType=HBUINT16, bool has_null=true> 272 struct OffsetTo : Offset<OffsetType, has_null> 273 { 274 HB_DELETE_COPY_ASSIGN (OffsetTo); 275 OffsetTo () = default; 276 operator =OT::OffsetTo277 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } 278 operator ()OT::OffsetTo279 const Type& operator () (const void *base) const 280 { 281 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); 282 return StructAtOffset<const Type> (base, *this); 283 } operator ()OT::OffsetTo284 Type& operator () (void *base) const 285 { 286 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); 287 return StructAtOffset<Type> (base, *this); 288 } 289 290 template <typename Base, 291 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const Base & base,const OffsetTo & offset)292 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } 293 template <typename Base, 294 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const OffsetTo & offset,const Base & base)295 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } 296 template <typename Base, 297 hb_enable_if (hb_is_convertible (Base, void *))> operator +(Base && base,OffsetTo & offset)298 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } 299 template <typename Base, 300 hb_enable_if (hb_is_convertible (Base, void *))> operator +(OffsetTo & offset,Base && base)301 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } 302 serializeOT::OffsetTo303 Type& serialize (hb_serialize_context_t *c, const void *base) 304 { 305 return * (Type *) Offset<OffsetType>::serialize (c, base); 306 } 307 308 template <typename ...Ts> serialize_subsetOT::OffsetTo309 bool serialize_subset (hb_subset_context_t *c, 310 const OffsetTo& src, 311 const void *src_base, 312 const void *dst_base, 313 Ts&&... ds) 314 { 315 *this = 0; 316 if (src.is_null ()) 317 return false; 318 319 auto *s = c->serializer; 320 321 s->push (); 322 323 bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...); 324 325 if (ret || !has_null) 326 s->add_link (*this, s->pop_pack (), dst_base); 327 else 328 s->pop_discard (); 329 330 return ret; 331 } 332 333 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ 334 template <typename ...Ts> serialize_copyOT::OffsetTo335 bool serialize_copy (hb_serialize_context_t *c, 336 const OffsetTo& src, 337 const void *src_base, 338 const void *dst_base, 339 Ts&&... ds) 340 { 341 *this = 0; 342 if (src.is_null ()) 343 return false; 344 345 c->push (); 346 347 bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...); 348 349 c->add_link (*this, c->pop_pack (), dst_base); 350 351 return ret; 352 } 353 sanitize_shallowOT::OffsetTo354 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const 355 { 356 TRACE_SANITIZE (this); 357 if (unlikely (!c->check_struct (this))) return_trace (false); 358 if (unlikely (this->is_null ())) return_trace (true); 359 if (unlikely (!c->check_range (base, *this))) return_trace (false); 360 return_trace (true); 361 } 362 363 template <typename ...Ts> sanitizeOT::OffsetTo364 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 365 { 366 TRACE_SANITIZE (this); 367 return_trace (sanitize_shallow (c, base) && 368 (this->is_null () || 369 c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) || 370 neuter (c))); 371 } 372 373 /* Set the offset to Null */ neuterOT::OffsetTo374 bool neuter (hb_sanitize_context_t *c) const 375 { 376 if (!has_null) return false; 377 return c->try_set (this, 0); 378 } 379 DEFINE_SIZE_STATIC (sizeof (OffsetType)); 380 }; 381 /* Partial specializations. */ 382 template <typename Type, bool has_null=true> 383 using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>; 384 template <typename Type, typename OffsetType=HBUINT16> 385 using NNOffsetTo = OffsetTo<Type, OffsetType, false>; 386 template <typename Type> 387 using LNNOffsetTo = LOffsetTo<Type, false>; 388 389 390 /* 391 * Array Types 392 */ 393 394 template <typename Type> 395 struct UnsizedArrayOf 396 { 397 typedef Type item_t; 398 static constexpr unsigned item_size = hb_static_size (Type); 399 400 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); 401 operator []OT::UnsizedArrayOf402 const Type& operator [] (int i_) const 403 { 404 unsigned int i = (unsigned int) i_; 405 const Type *p = &arrayZ[i]; 406 if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ 407 return *p; 408 } operator []OT::UnsizedArrayOf409 Type& operator [] (int i_) 410 { 411 unsigned int i = (unsigned int) i_; 412 Type *p = &arrayZ[i]; 413 if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ 414 return *p; 415 } 416 get_sizeOT::UnsizedArrayOf417 unsigned int get_size (unsigned int len) const 418 { return len * Type::static_size; } 419 operator T*OT::UnsizedArrayOf420 template <typename T> operator T * () { return arrayZ; } operator const T*OT::UnsizedArrayOf421 template <typename T> operator const T * () const { return arrayZ; } as_arrayOT::UnsizedArrayOf422 hb_array_t<Type> as_array (unsigned int len) 423 { return hb_array (arrayZ, len); } as_arrayOT::UnsizedArrayOf424 hb_array_t<const Type> as_array (unsigned int len) const 425 { return hb_array (arrayZ, len); } operator hb_array_t<Type>OT::UnsizedArrayOf426 operator hb_array_t< Type> () { return as_array (); } operator hb_array_t<const Type>OT::UnsizedArrayOf427 operator hb_array_t<const Type> () const { return as_array (); } 428 429 template <typename T> lsearchOT::UnsizedArrayOf430 Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 431 { return *as_array (len).lsearch (x, ¬_found); } 432 template <typename T> lsearchOT::UnsizedArrayOf433 const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 434 { return *as_array (len).lsearch (x, ¬_found); } 435 qsortOT::UnsizedArrayOf436 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) 437 { as_array (len).qsort (start, end); } 438 serializeOT::UnsizedArrayOf439 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 440 { 441 TRACE_SERIALIZE (this); 442 if (unlikely (!c->extend (*this, items_len))) return_trace (false); 443 return_trace (true); 444 } 445 template <typename Iterator, 446 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::UnsizedArrayOf447 bool serialize (hb_serialize_context_t *c, Iterator items) 448 { 449 TRACE_SERIALIZE (this); 450 unsigned count = items.len (); 451 if (unlikely (!serialize (c, count))) return_trace (false); 452 /* TODO Umm. Just exhaust the iterator instead? Being extra 453 * cautious right now.. */ 454 for (unsigned i = 0; i < count; i++, ++items) 455 arrayZ[i] = *items; 456 return_trace (true); 457 } 458 copyOT::UnsizedArrayOf459 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const 460 { 461 TRACE_SERIALIZE (this); 462 auto *out = c->start_embed (this); 463 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); 464 return_trace (out); 465 } 466 467 template <typename ...Ts> sanitizeOT::UnsizedArrayOf468 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 469 { 470 TRACE_SANITIZE (this); 471 if (unlikely (!sanitize_shallow (c, count))) return_trace (false); 472 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 473 for (unsigned int i = 0; i < count; i++) 474 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 475 return_trace (false); 476 return_trace (true); 477 } 478 sanitize_shallowOT::UnsizedArrayOf479 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const 480 { 481 TRACE_SANITIZE (this); 482 return_trace (c->check_array (arrayZ, count)); 483 } 484 485 public: 486 Type arrayZ[HB_VAR_ARRAY]; 487 public: 488 DEFINE_SIZE_UNBOUNDED (0); 489 }; 490 491 /* Unsized array of offset's */ 492 template <typename Type, typename OffsetType, bool has_null=true> 493 using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; 494 495 /* Unsized array of offsets relative to the beginning of the array itself. */ 496 template <typename Type, typename OffsetType, bool has_null=true> 497 struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> 498 { operator []OT::UnsizedOffsetListOf499 const Type& operator [] (int i_) const 500 { 501 unsigned int i = (unsigned int) i_; 502 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 503 if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ 504 return this+*p; 505 } operator []OT::UnsizedOffsetListOf506 Type& operator [] (int i_) 507 { 508 unsigned int i = (unsigned int) i_; 509 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 510 if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ 511 return this+*p; 512 } 513 514 template <typename ...Ts> sanitizeOT::UnsizedOffsetListOf515 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 516 { 517 TRACE_SANITIZE (this); 518 return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null> 519 ::sanitize (c, count, this, hb_forward<Ts> (ds)...))); 520 } 521 }; 522 523 /* An array with sorted elements. Supports binary searching. */ 524 template <typename Type> 525 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 526 { as_arrayOT::SortedUnsizedArrayOf527 hb_sorted_array_t<Type> as_array (unsigned int len) 528 { return hb_sorted_array (this->arrayZ, len); } as_arrayOT::SortedUnsizedArrayOf529 hb_sorted_array_t<const Type> as_array (unsigned int len) const 530 { return hb_sorted_array (this->arrayZ, len); } operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf531 operator hb_sorted_array_t<Type> () { return as_array (); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf532 operator hb_sorted_array_t<const Type> () const { return as_array (); } 533 534 template <typename T> bsearchOT::SortedUnsizedArrayOf535 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 536 { return *as_array (len).bsearch (x, ¬_found); } 537 template <typename T> bsearchOT::SortedUnsizedArrayOf538 const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 539 { return *as_array (len).bsearch (x, ¬_found); } 540 template <typename T> bfindOT::SortedUnsizedArrayOf541 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, 542 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, 543 unsigned int to_store = (unsigned int) -1) const 544 { return as_array (len).bfind (x, i, not_found, to_store); } 545 }; 546 547 548 /* An array with a number of elements. */ 549 template <typename Type, typename LenType=HBUINT16> 550 struct ArrayOf 551 { 552 typedef Type item_t; 553 static constexpr unsigned item_size = hb_static_size (Type); 554 555 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); 556 operator []OT::ArrayOf557 const Type& operator [] (int i_) const 558 { 559 unsigned int i = (unsigned int) i_; 560 if (unlikely (i >= len)) return Null (Type); 561 return arrayZ[i]; 562 } operator []OT::ArrayOf563 Type& operator [] (int i_) 564 { 565 unsigned int i = (unsigned int) i_; 566 if (unlikely (i >= len)) return Crap (Type); 567 return arrayZ[i]; 568 } 569 get_sizeOT::ArrayOf570 unsigned int get_size () const 571 { return len.static_size + len * Type::static_size; } 572 operator boolOT::ArrayOf573 explicit operator bool () const { return len; } 574 popOT::ArrayOf575 void pop () { len--; } 576 as_arrayOT::ArrayOf577 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } as_arrayOT::ArrayOf578 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } 579 580 /* Iterator. */ 581 typedef hb_array_t<const Type> iter_t; 582 typedef hb_array_t< Type> writer_t; iterOT::ArrayOf583 iter_t iter () const { return as_array (); } writerOT::ArrayOf584 writer_t writer () { return as_array (); } operator iter_tOT::ArrayOf585 operator iter_t () const { return iter (); } operator writer_tOT::ArrayOf586 operator writer_t () { return writer (); } 587 sub_arrayOT::ArrayOf588 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 589 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf590 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 591 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf592 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 593 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::ArrayOf594 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 595 { return as_array ().sub_array (start_offset, count); } 596 serializeOT::ArrayOf597 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 598 { 599 TRACE_SERIALIZE (this); 600 if (unlikely (!c->extend_min (*this))) return_trace (false); 601 c->check_assign (len, items_len); 602 if (unlikely (!c->extend (*this))) return_trace (false); 603 return_trace (true); 604 } 605 template <typename Iterator, 606 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::ArrayOf607 bool serialize (hb_serialize_context_t *c, Iterator items) 608 { 609 TRACE_SERIALIZE (this); 610 unsigned count = items.len (); 611 if (unlikely (!serialize (c, count))) return_trace (false); 612 /* TODO Umm. Just exhaust the iterator instead? Being extra 613 * cautious right now.. */ 614 for (unsigned i = 0; i < count; i++, ++items) 615 arrayZ[i] = *items; 616 return_trace (true); 617 } 618 serialize_appendOT::ArrayOf619 Type* serialize_append (hb_serialize_context_t *c) 620 { 621 TRACE_SERIALIZE (this); 622 len++; 623 if (unlikely (!len || !c->extend (*this))) 624 { 625 len--; 626 return_trace (nullptr); 627 } 628 return_trace (&arrayZ[len - 1]); 629 } 630 copyOT::ArrayOf631 ArrayOf* copy (hb_serialize_context_t *c) const 632 { 633 TRACE_SERIALIZE (this); 634 auto *out = c->start_embed (this); 635 if (unlikely (!c->extend_min (out))) return_trace (nullptr); 636 c->check_assign (out->len, len); 637 if (unlikely (!as_array ().copy (c))) return_trace (nullptr); 638 return_trace (out); 639 } 640 641 template <typename ...Ts> sanitizeOT::ArrayOf642 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 643 { 644 TRACE_SANITIZE (this); 645 if (unlikely (!sanitize_shallow (c))) return_trace (false); 646 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 647 unsigned int count = len; 648 for (unsigned int i = 0; i < count; i++) 649 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 650 return_trace (false); 651 return_trace (true); 652 } 653 654 template <typename T> lsearchOT::ArrayOf655 Type &lsearch (const T &x, Type ¬_found = Crap (Type)) 656 { return *as_array ().lsearch (x, ¬_found); } 657 template <typename T> lsearchOT::ArrayOf658 const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const 659 { return *as_array ().lsearch (x, ¬_found); } 660 qsortOT::ArrayOf661 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) 662 { as_array ().qsort (start, end); } 663 sanitize_shallowOT::ArrayOf664 bool sanitize_shallow (hb_sanitize_context_t *c) const 665 { 666 TRACE_SANITIZE (this); 667 return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); 668 } 669 670 public: 671 LenType len; 672 Type arrayZ[HB_VAR_ARRAY]; 673 public: 674 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 675 }; 676 template <typename Type> 677 using LArrayOf = ArrayOf<Type, HBUINT32>; 678 using PString = ArrayOf<HBUINT8, HBUINT8>; 679 680 /* Array of Offset's */ 681 template <typename Type> 682 using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>; 683 template <typename Type> 684 using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>; 685 template <typename Type> 686 using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; 687 688 /* Array of offsets relative to the beginning of the array itself. */ 689 template <typename Type> 690 struct OffsetListOf : OffsetArrayOf<Type> 691 { operator []OT::OffsetListOf692 const Type& operator [] (int i_) const 693 { 694 unsigned int i = (unsigned int) i_; 695 if (unlikely (i >= this->len)) return Null (Type); 696 return this+this->arrayZ[i]; 697 } operator []OT::OffsetListOf698 const Type& operator [] (int i_) 699 { 700 unsigned int i = (unsigned int) i_; 701 if (unlikely (i >= this->len)) return Crap (Type); 702 return this+this->arrayZ[i]; 703 } 704 subsetOT::OffsetListOf705 bool subset (hb_subset_context_t *c) const 706 { 707 TRACE_SUBSET (this); 708 struct OffsetListOf<Type> *out = c->serializer->embed (*this); 709 if (unlikely (!out)) return_trace (false); 710 unsigned int count = this->len; 711 for (unsigned int i = 0; i < count; i++) 712 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); 713 return_trace (true); 714 } 715 716 template <typename ...Ts> sanitizeOT::OffsetListOf717 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 718 { 719 TRACE_SANITIZE (this); 720 return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...)); 721 } 722 }; 723 724 /* An array starting at second element. */ 725 template <typename Type, typename LenType=HBUINT16> 726 struct HeadlessArrayOf 727 { 728 static constexpr unsigned item_size = Type::static_size; 729 730 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); 731 operator []OT::HeadlessArrayOf732 const Type& operator [] (int i_) const 733 { 734 unsigned int i = (unsigned int) i_; 735 if (unlikely (i >= lenP1 || !i)) return Null (Type); 736 return arrayZ[i-1]; 737 } operator []OT::HeadlessArrayOf738 Type& operator [] (int i_) 739 { 740 unsigned int i = (unsigned int) i_; 741 if (unlikely (i >= lenP1 || !i)) return Crap (Type); 742 return arrayZ[i-1]; 743 } get_sizeOT::HeadlessArrayOf744 unsigned int get_size () const 745 { return lenP1.static_size + get_length () * Type::static_size; } 746 get_lengthOT::HeadlessArrayOf747 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } 748 as_arrayOT::HeadlessArrayOf749 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } as_arrayOT::HeadlessArrayOf750 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } 751 752 /* Iterator. */ 753 typedef hb_array_t<const Type> iter_t; 754 typedef hb_array_t< Type> writer_t; iterOT::HeadlessArrayOf755 iter_t iter () const { return as_array (); } writerOT::HeadlessArrayOf756 writer_t writer () { return as_array (); } operator iter_tOT::HeadlessArrayOf757 operator iter_t () const { return iter (); } operator writer_tOT::HeadlessArrayOf758 operator writer_t () { return writer (); } 759 serializeOT::HeadlessArrayOf760 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 761 { 762 TRACE_SERIALIZE (this); 763 if (unlikely (!c->extend_min (*this))) return_trace (false); 764 c->check_assign (lenP1, items_len + 1); 765 if (unlikely (!c->extend (*this))) return_trace (false); 766 return_trace (true); 767 } 768 template <typename Iterator, 769 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::HeadlessArrayOf770 bool serialize (hb_serialize_context_t *c, Iterator items) 771 { 772 TRACE_SERIALIZE (this); 773 unsigned count = items.len (); 774 if (unlikely (!serialize (c, count))) return_trace (false); 775 /* TODO Umm. Just exhaust the iterator instead? Being extra 776 * cautious right now.. */ 777 for (unsigned i = 0; i < count; i++, ++items) 778 arrayZ[i] = *items; 779 return_trace (true); 780 } 781 782 template <typename ...Ts> sanitizeOT::HeadlessArrayOf783 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 784 { 785 TRACE_SANITIZE (this); 786 if (unlikely (!sanitize_shallow (c))) return_trace (false); 787 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 788 unsigned int count = get_length (); 789 for (unsigned int i = 0; i < count; i++) 790 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 791 return_trace (false); 792 return_trace (true); 793 } 794 795 private: sanitize_shallowOT::HeadlessArrayOf796 bool sanitize_shallow (hb_sanitize_context_t *c) const 797 { 798 TRACE_SANITIZE (this); 799 return_trace (lenP1.sanitize (c) && 800 (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); 801 } 802 803 public: 804 LenType lenP1; 805 Type arrayZ[HB_VAR_ARRAY]; 806 public: 807 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 808 }; 809 810 /* An array storing length-1. */ 811 template <typename Type, typename LenType=HBUINT16> 812 struct ArrayOfM1 813 { 814 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); 815 operator []OT::ArrayOfM1816 const Type& operator [] (int i_) const 817 { 818 unsigned int i = (unsigned int) i_; 819 if (unlikely (i > lenM1)) return Null (Type); 820 return arrayZ[i]; 821 } operator []OT::ArrayOfM1822 Type& operator [] (int i_) 823 { 824 unsigned int i = (unsigned int) i_; 825 if (unlikely (i > lenM1)) return Crap (Type); 826 return arrayZ[i]; 827 } get_sizeOT::ArrayOfM1828 unsigned int get_size () const 829 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } 830 831 template <typename ...Ts> sanitizeOT::ArrayOfM1832 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 833 { 834 TRACE_SANITIZE (this); 835 if (unlikely (!sanitize_shallow (c))) return_trace (false); 836 unsigned int count = lenM1 + 1; 837 for (unsigned int i = 0; i < count; i++) 838 if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) 839 return_trace (false); 840 return_trace (true); 841 } 842 843 private: sanitize_shallowOT::ArrayOfM1844 bool sanitize_shallow (hb_sanitize_context_t *c) const 845 { 846 TRACE_SANITIZE (this); 847 return_trace (lenM1.sanitize (c) && 848 (c->check_array (arrayZ, lenM1 + 1))); 849 } 850 851 public: 852 LenType lenM1; 853 Type arrayZ[HB_VAR_ARRAY]; 854 public: 855 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 856 }; 857 858 /* An array with sorted elements. Supports binary searching. */ 859 template <typename Type, typename LenType=HBUINT16> 860 struct SortedArrayOf : ArrayOf<Type, LenType> 861 { as_arrayOT::SortedArrayOf862 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } as_arrayOT::SortedArrayOf863 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } 864 865 /* Iterator. */ 866 typedef hb_sorted_array_t<const Type> iter_t; 867 typedef hb_sorted_array_t< Type> writer_t; iterOT::SortedArrayOf868 iter_t iter () const { return as_array (); } writerOT::SortedArrayOf869 writer_t writer () { return as_array (); } operator iter_tOT::SortedArrayOf870 operator iter_t () const { return iter (); } operator writer_tOT::SortedArrayOf871 operator writer_t () { return writer (); } 872 sub_arrayOT::SortedArrayOf873 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const 874 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf875 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const 876 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf877 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) 878 { return as_array ().sub_array (start_offset, count); } sub_arrayOT::SortedArrayOf879 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) 880 { return as_array ().sub_array (start_offset, count); } 881 serializeOT::SortedArrayOf882 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 883 { 884 TRACE_SERIALIZE (this); 885 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); 886 return_trace (ret); 887 } 888 template <typename Iterator, 889 hb_requires (hb_is_sorted_source_of (Iterator, Type))> serializeOT::SortedArrayOf890 bool serialize (hb_serialize_context_t *c, Iterator items) 891 { 892 TRACE_SERIALIZE (this); 893 bool ret = ArrayOf<Type, LenType>::serialize (c, items); 894 return_trace (ret); 895 } 896 897 template <typename T> bsearchOT::SortedArrayOf898 Type &bsearch (const T &x, Type ¬_found = Crap (Type)) 899 { return *as_array ().bsearch (x, ¬_found); } 900 template <typename T> bsearchOT::SortedArrayOf901 const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const 902 { return *as_array ().bsearch (x, ¬_found); } 903 template <typename T> bfindOT::SortedArrayOf904 bool bfind (const T &x, unsigned int *i = nullptr, 905 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, 906 unsigned int to_store = (unsigned int) -1) const 907 { return as_array ().bfind (x, i, not_found, to_store); } 908 }; 909 910 /* 911 * Binary-search arrays 912 */ 913 914 template <typename LenType=HBUINT16> 915 struct BinSearchHeader 916 { operator uint32_tOT::BinSearchHeader917 operator uint32_t () const { return len; } 918 sanitizeOT::BinSearchHeader919 bool sanitize (hb_sanitize_context_t *c) const 920 { 921 TRACE_SANITIZE (this); 922 return_trace (c->check_struct (this)); 923 } 924 operator =OT::BinSearchHeader925 BinSearchHeader& operator = (unsigned int v) 926 { 927 len = v; 928 assert (len == v); 929 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; 930 searchRange = 16 * (1u << entrySelector); 931 rangeShift = v * 16 > searchRange 932 ? 16 * v - searchRange 933 : 0; 934 return *this; 935 } 936 937 protected: 938 LenType len; 939 LenType searchRange; 940 LenType entrySelector; 941 LenType rangeShift; 942 943 public: 944 DEFINE_SIZE_STATIC (8); 945 }; 946 947 template <typename Type, typename LenType=HBUINT16> 948 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; 949 950 951 struct VarSizedBinSearchHeader 952 { 953 sanitizeOT::VarSizedBinSearchHeader954 bool sanitize (hb_sanitize_context_t *c) const 955 { 956 TRACE_SANITIZE (this); 957 return_trace (c->check_struct (this)); 958 } 959 960 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ 961 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ 962 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 963 * that is less than or equal to the value of nUnits. */ 964 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than 965 * or equal to the value of nUnits. */ 966 HBUINT16 rangeShift; /* The value of unitSize times the difference of the 967 * value of nUnits minus the largest power of 2 less 968 * than or equal to the value of nUnits. */ 969 public: 970 DEFINE_SIZE_STATIC (10); 971 }; 972 973 template <typename Type> 974 struct VarSizedBinSearchArrayOf 975 { 976 static constexpr unsigned item_size = Type::static_size; 977 978 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); 979 last_is_terminatorOT::VarSizedBinSearchArrayOf980 bool last_is_terminator () const 981 { 982 if (unlikely (!header.nUnits)) return false; 983 984 /* Gah. 985 * 986 * "The number of termination values that need to be included is table-specific. 987 * The value that indicates binary search termination is 0xFFFF." */ 988 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); 989 unsigned int count = Type::TerminationWordCount; 990 for (unsigned int i = 0; i < count; i++) 991 if (words[i] != 0xFFFFu) 992 return false; 993 return true; 994 } 995 operator []OT::VarSizedBinSearchArrayOf996 const Type& operator [] (int i_) const 997 { 998 unsigned int i = (unsigned int) i_; 999 if (unlikely (i >= get_length ())) return Null (Type); 1000 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1001 } operator []OT::VarSizedBinSearchArrayOf1002 Type& operator [] (int i_) 1003 { 1004 unsigned int i = (unsigned int) i_; 1005 if (unlikely (i >= get_length ())) return Crap (Type); 1006 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1007 } get_lengthOT::VarSizedBinSearchArrayOf1008 unsigned int get_length () const 1009 { return header.nUnits - last_is_terminator (); } get_sizeOT::VarSizedBinSearchArrayOf1010 unsigned int get_size () const 1011 { return header.static_size + header.nUnits * header.unitSize; } 1012 1013 template <typename ...Ts> sanitizeOT::VarSizedBinSearchArrayOf1014 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1015 { 1016 TRACE_SANITIZE (this); 1017 if (unlikely (!sanitize_shallow (c))) return_trace (false); 1018 if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); 1019 unsigned int count = get_length (); 1020 for (unsigned int i = 0; i < count; i++) 1021 if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...))) 1022 return_trace (false); 1023 return_trace (true); 1024 } 1025 1026 template <typename T> bsearchOT::VarSizedBinSearchArrayOf1027 const Type *bsearch (const T &key) const 1028 { 1029 unsigned int size = header.unitSize; 1030 int min = 0, max = (int) get_length () - 1; 1031 while (min <= max) 1032 { 1033 int mid = ((unsigned int) min + (unsigned int) max) / 2; 1034 const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); 1035 int c = p->cmp (key); 1036 if (c < 0) max = mid - 1; 1037 else if (c > 0) min = mid + 1; 1038 else return p; 1039 } 1040 return nullptr; 1041 } 1042 1043 private: sanitize_shallowOT::VarSizedBinSearchArrayOf1044 bool sanitize_shallow (hb_sanitize_context_t *c) const 1045 { 1046 TRACE_SANITIZE (this); 1047 return_trace (header.sanitize (c) && 1048 Type::static_size <= header.unitSize && 1049 c->check_range (bytesZ.arrayZ, 1050 header.nUnits, 1051 header.unitSize)); 1052 } 1053 1054 protected: 1055 VarSizedBinSearchHeader header; 1056 UnsizedArrayOf<HBUINT8> bytesZ; 1057 public: 1058 DEFINE_SIZE_ARRAY (10, bytesZ); 1059 }; 1060 1061 1062 } /* namespace OT */ 1063 1064 1065 #endif /* HB_OPEN_TYPE_HH */ 1066