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