hb-open-type-private.hh revision 9417c1c0d2b005eadf0c087ca695121a6200d0f7
1/* 2 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Red Hat Author(s): Behdad Esfahbod 25 */ 26 27#ifndef HB_OPEN_TYPE_PRIVATE_HH 28#define HB_OPEN_TYPE_PRIVATE_HH 29 30#include "hb-private.h" 31 32#include "hb-blob.h" 33 34HB_BEGIN_DECLS 35HB_END_DECLS 36 37 38/* 39 * Casts 40 */ 41 42/* Cast to struct T, reference to reference */ 43template<typename Type, typename TObject> 44inline const Type& CastR(const TObject &X) 45{ return reinterpret_cast<const Type&> (X); } 46template<typename Type, typename TObject> 47inline Type& CastR(TObject &X) 48{ return reinterpret_cast<Type&> (X); } 49 50/* Cast to struct T, pointer to pointer */ 51template<typename Type, typename TObject> 52inline const Type* CastP(const TObject *X) 53{ return reinterpret_cast<const Type*> (X); } 54template<typename Type, typename TObject> 55inline Type* CastP(TObject *X) 56{ return reinterpret_cast<Type*> (X); } 57 58/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory 59 * location pointed to by P plus Ofs bytes. */ 60template<typename Type> 61inline const Type& StructAtOffset(const void *P, unsigned int offset) 62{ return * reinterpret_cast<const Type*> ((const char *) P + offset); } 63template<typename Type> 64inline Type& StructAtOffset(void *P, unsigned int offset) 65{ return * reinterpret_cast<Type*> ((char *) P + offset); } 66 67/* StructAfter<T>(X) returns the struct T& that is placed after X. 68 * Works with X of variable size also. X must implement get_size() */ 69template<typename Type, typename TObject> 70inline const Type& StructAfter(const TObject &X) 71{ return StructAtOffset<Type>(&X, X.get_size()); } 72template<typename Type, typename TObject> 73inline Type& StructAfter(TObject &X) 74{ return StructAtOffset<Type>(&X, X.get_size()); } 75 76 77 78/* 79 * Size checking 80 */ 81 82/* Check _assertion in a method environment */ 83#define _DEFINE_SIZE_ASSERTION(_assertion) \ 84 inline void _size_assertion (void) const \ 85 { ASSERT_STATIC (_assertion); } 86/* Check that _code compiles in a method environment */ 87#define _DEFINE_COMPILES_ASSERTION(_code) \ 88 inline void _compiles_assertion (void) const \ 89 { _code; } 90 91 92#define DEFINE_SIZE_STATIC(size) \ 93 _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size)); \ 94 static const unsigned int static_size = (size); \ 95 static const unsigned int min_size = (size) 96 97/* Size signifying variable-sized array */ 98#define VAR 1 99 100#define DEFINE_SIZE_UNION(size, _member) \ 101 _DEFINE_SIZE_ASSERTION (this->u._member.static_size == (size)); \ 102 static const unsigned int min_size = (size) 103 104#define DEFINE_SIZE_MIN(size) \ 105 _DEFINE_SIZE_ASSERTION (sizeof (*this) >= (size)); \ 106 static const unsigned int min_size = (size) 107 108#define DEFINE_SIZE_ARRAY(size, array) \ 109 _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \ 110 _DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \ 111 static const unsigned int min_size = (size) 112 113#define DEFINE_SIZE_ARRAY2(size, array1, array2) \ 114 _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \ 115 _DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \ 116 static const unsigned int min_size = (size) 117 118 119 120/* 121 * Null objects 122 */ 123 124/* Global nul-content Null pool. Enlarge as necessary. */ 125static const void *_NullPool[64 / sizeof (void *)]; 126 127/* Generic nul-content Null objects. */ 128template <typename Type> 129static inline const Type& Null (void) { 130 ASSERT_STATIC (Type::min_size <= sizeof (_NullPool)); 131 return *CastP<Type> (_NullPool); 132} 133 134/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ 135#define DEFINE_NULL_DATA(Type, data) \ 136static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \ 137template <> \ 138inline const Type& Null<Type> (void) { \ 139 return *CastP<Type> (_Null##Type); \ 140} /* The following line really exists such that we end in a place needing semicolon */ \ 141ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) 142 143/* Accessor macro. */ 144#define Null(Type) Null<Type>() 145 146 147/* 148 * Trace 149 */ 150 151 152template <int max_depth> 153struct hb_trace_t { 154 explicit hb_trace_t (unsigned int *pdepth, const char *what, const char *function, const void *obj) : pdepth(pdepth) { 155 (void) (*pdepth < max_depth && 156 fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function)); 157 if (max_depth) ++*pdepth; 158 } 159 ~hb_trace_t (void) { if (max_depth) --*pdepth; } 160 161 private: 162 unsigned int *pdepth; 163}; 164template <> /* Optimize when tracing is disabled */ 165struct hb_trace_t<0> { 166 explicit hb_trace_t (unsigned int *pdepth HB_UNUSED, const char *what HB_UNUSED, const char *function HB_UNUSED, const void *obj HB_UNUSED) {} 167}; 168 169 170 171/* 172 * Sanitize 173 */ 174 175#ifndef HB_DEBUG_SANITIZE 176#define HB_DEBUG_SANITIZE (HB_DEBUG+0) 177#endif 178 179 180#define TRACE_SANITIZE() \ 181 hb_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", HB_FUNC, this); \ 182 183 184struct hb_sanitize_context_t 185{ 186 inline void init (hb_blob_t *blob) 187 { 188 this->blob = hb_blob_reference (blob); 189 this->start = hb_blob_lock (blob); 190 this->end = this->start + hb_blob_get_length (blob); 191 this->writable = hb_blob_is_writable (blob); 192 this->edit_count = 0; 193 this->debug_depth = 0; 194 195 (void) (HB_DEBUG_SANITIZE && 196 fprintf (stderr, "sanitize %p init [%p..%p] (%lu bytes)\n", 197 this->blob, this->start, this->end, 198 (unsigned long) (this->end - this->start))); 199 } 200 201 inline void finish (void) 202 { 203 (void) (HB_DEBUG_SANITIZE && 204 fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n", 205 this->blob, this->start, this->end, this->edit_count)); 206 207 hb_blob_unlock (this->blob); 208 hb_blob_destroy (this->blob); 209 this->blob = NULL; 210 this->start = this->end = NULL; 211 } 212 213 inline bool check_range (const void *base, unsigned int len) const 214 { 215 const char *p = (const char *) base; 216 bool ret = this->start <= p && 217 p <= this->end && 218 (unsigned int) (this->end - p) >= len; 219 220 (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE && 221 fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n", 222 p, 223 this->debug_depth, this->debug_depth, 224 p, p + len, len, 225 this->start, this->end, 226 ret ? "pass" : "FAIL")); 227 228 return likely (ret); 229 } 230 231 inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const 232 { 233 const char *p = (const char *) base; 234 bool overflows = record_size > 0 && len >= ((unsigned int) -1) / record_size; 235 236 (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE && 237 fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", 238 p, 239 this->debug_depth, this->debug_depth, 240 p, p + (record_size * len), record_size, len, (unsigned long) record_size * len, 241 this->start, this->end, 242 !overflows ? "does not overflow" : "OVERFLOWS FAIL")); 243 244 return likely (!overflows && this->check_range (base, record_size * len)); 245 } 246 247 template <typename Type> 248 inline bool check_struct (const Type *obj) const 249 { 250 return likely (this->check_range (obj, obj->min_size)); 251 } 252 253 inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) 254 { 255 const char *p = (const char *) base; 256 this->edit_count++; 257 258 (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE && 259 fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", 260 p, 261 this->debug_depth, this->debug_depth, 262 this->edit_count, 263 p, p + len, len, 264 this->start, this->end, 265 this->writable ? "granted" : "REJECTED")); 266 267 return this->writable; 268 } 269 270 unsigned int debug_depth; 271 const char *start, *end; 272 bool writable; 273 unsigned int edit_count; 274 hb_blob_t *blob; 275}; 276 277 278 279/* Template to sanitize an object. */ 280template <typename Type> 281struct Sanitizer 282{ 283 static hb_blob_t *sanitize (hb_blob_t *blob) { 284 hb_sanitize_context_t c[1] = {{0}}; 285 bool sane; 286 287 /* TODO is_sane() stuff */ 288 289 retry: 290 (void) (HB_DEBUG_SANITIZE && 291 fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC)); 292 293 c->init (blob); 294 295 if (unlikely (!c->start)) { 296 c->finish (); 297 return blob; 298 } 299 300 Type *t = CastP<Type> (const_cast<char *> (c->start)); 301 302 sane = t->sanitize (c); 303 if (sane) { 304 if (c->edit_count) { 305 (void) (HB_DEBUG_SANITIZE && 306 fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n", 307 blob, c->edit_count, HB_FUNC)); 308 309 /* sanitize again to ensure no toe-stepping */ 310 c->edit_count = 0; 311 sane = t->sanitize (c); 312 if (c->edit_count) { 313 (void) (HB_DEBUG_SANITIZE && 314 fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n", 315 blob, c->edit_count, HB_FUNC)); 316 sane = false; 317 } 318 } 319 c->finish (); 320 } else { 321 unsigned int edit_count = c->edit_count; 322 c->finish (); 323 if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) { 324 /* ok, we made it writable by relocating. try again */ 325 (void) (HB_DEBUG_SANITIZE && 326 fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC)); 327 goto retry; 328 } 329 } 330 331 (void) (HB_DEBUG_SANITIZE && 332 fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC)); 333 if (sane) 334 return blob; 335 else { 336 hb_blob_destroy (blob); 337 return hb_blob_create_empty (); 338 } 339 } 340 341 static const Type* lock_instance (hb_blob_t *blob) { 342 const char *base = hb_blob_lock (blob); 343 return unlikely (!base) ? &Null(Type) : CastP<Type> (base); 344 } 345}; 346 347 348 349 350/* 351 * 352 * The OpenType Font File: Data Types 353 */ 354 355 356/* "The following data types are used in the OpenType font file. 357 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 358 359/* 360 * Int types 361 */ 362 363 364template <typename Type, int Bytes> class BEInt; 365 366/* LONGTERMTODO: On machines allowing unaligned access, we can make the 367 * following tighter by using byteswap instructions on ints directly. */ 368template <typename Type> 369class BEInt<Type, 2> 370{ 371 public: 372 inline void set (Type i) { hb_be_uint16_put (v,i); } 373 inline operator Type (void) const { return hb_be_uint16_get (v); } 374 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); } 375 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); } 376 private: uint8_t v[2]; 377}; 378template <typename Type> 379class BEInt<Type, 4> 380{ 381 public: 382 inline void set (Type i) { hb_be_uint32_put (v,i); } 383 inline operator Type (void) const { return hb_be_uint32_get (v); } 384 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_cmp (v, o.v); } 385 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); } 386 private: uint8_t v[4]; 387}; 388 389/* Integer types in big-endian order and no alignment requirement */ 390template <typename Type> 391struct IntType 392{ 393 inline void set (Type i) { v.set (i); } 394 inline operator Type(void) const { return v; } 395 inline bool operator == (const IntType<Type> &o) const { return v == o.v; } 396 inline bool operator != (const IntType<Type> &o) const { return v != o.v; } 397 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } 398 inline bool sanitize (hb_sanitize_context_t *c) { 399 TRACE_SANITIZE (); 400 return likely (c->check_struct (this)); 401 } 402 protected: 403 BEInt<Type, sizeof (Type)> v; 404 public: 405 DEFINE_SIZE_STATIC (sizeof (Type)); 406}; 407 408typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ 409typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ 410typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ 411typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ 412 413/* Date represented in number of seconds since 12:00 midnight, January 1, 414 * 1904. The value is represented as a signed 64-bit integer. */ 415struct LONGDATETIME 416{ 417 inline bool sanitize (hb_sanitize_context_t *c) { 418 TRACE_SANITIZE (); 419 return likely (c->check_struct (this)); 420 } 421 private: 422 LONG major; 423 ULONG minor; 424 public: 425 DEFINE_SIZE_STATIC (8); 426}; 427 428/* Array of four uint8s (length = 32 bits) used to identify a script, language 429 * system, feature, or baseline */ 430struct Tag : ULONG 431{ 432 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ 433 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); } 434 inline operator char* (void) { return reinterpret_cast<char *> (&this->v); } 435 public: 436 DEFINE_SIZE_STATIC (4); 437}; 438DEFINE_NULL_DATA (Tag, " "); 439 440/* Glyph index number, same as uint16 (length = 16 bits) */ 441typedef USHORT GlyphID; 442 443/* Script/language-system/feature index */ 444struct Index : USHORT { 445 static const unsigned int NOT_FOUND_INDEX = 0xFFFF; 446}; 447DEFINE_NULL_DATA (Index, "\xff\xff"); 448 449/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */ 450typedef USHORT Offset; 451 452/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */ 453typedef ULONG LongOffset; 454 455 456/* CheckSum */ 457struct CheckSum : ULONG 458{ 459 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) 460 { 461 uint32_t Sum = 0L; 462 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size; 463 464 while (Table < EndPtr) 465 Sum += *Table++; 466 return Sum; 467 } 468 public: 469 DEFINE_SIZE_STATIC (4); 470}; 471 472 473/* 474 * Version Numbers 475 */ 476 477struct FixedVersion 478{ 479 inline operator uint32_t (void) const { return (major << 16) + minor; } 480 481 inline bool sanitize (hb_sanitize_context_t *c) { 482 TRACE_SANITIZE (); 483 return c->check_struct (this); 484 } 485 486 USHORT major; 487 USHORT minor; 488 public: 489 DEFINE_SIZE_STATIC (4); 490}; 491 492 493 494/* 495 * Template subclasses of Offset and LongOffset that do the dereferencing. 496 * Use: (base+offset) 497 */ 498 499template <typename OffsetType, typename Type> 500struct GenericOffsetTo : OffsetType 501{ 502 inline const Type& operator () (const void *base) const 503 { 504 unsigned int offset = *this; 505 if (unlikely (!offset)) return Null(Type); 506 return StructAtOffset<Type> (base, offset); 507 } 508 509 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 510 TRACE_SANITIZE (); 511 if (unlikely (!c->check_struct (this))) return false; 512 unsigned int offset = *this; 513 if (unlikely (!offset)) return true; 514 Type &obj = StructAtOffset<Type> (base, offset); 515 return likely (obj.sanitize (c)) || neuter (c); 516 } 517 template <typename T> 518 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { 519 TRACE_SANITIZE (); 520 if (unlikely (!c->check_struct (this))) return false; 521 unsigned int offset = *this; 522 if (unlikely (!offset)) return true; 523 Type &obj = StructAtOffset<Type> (base, offset); 524 return likely (obj.sanitize (c, user_data)) || neuter (c); 525 } 526 527 private: 528 /* Set the offset to Null */ 529 inline bool neuter (hb_sanitize_context_t *c) { 530 if (c->can_edit (this, this->static_size)) { 531 this->set (0); /* 0 is Null offset */ 532 return true; 533 } 534 return false; 535 } 536}; 537template <typename Base, typename OffsetType, typename Type> 538inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); } 539 540template <typename Type> 541struct OffsetTo : GenericOffsetTo<Offset, Type> {}; 542 543template <typename Type> 544struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {}; 545 546 547/* 548 * Array Types 549 */ 550 551template <typename LenType, typename Type> 552struct GenericArrayOf 553{ 554 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const 555 { 556 unsigned int count = len; 557 if (unlikely (start_offset > count)) 558 count = 0; 559 else 560 count -= start_offset; 561 count = MIN (count, *pcount); 562 *pcount = count; 563 return array + start_offset; 564 } 565 566 inline const Type& operator [] (unsigned int i) const 567 { 568 if (unlikely (i >= len)) return Null(Type); 569 return array[i]; 570 } 571 inline unsigned int get_size (void) const 572 { return len.static_size + len * Type::static_size; } 573 574 inline bool sanitize (hb_sanitize_context_t *c) { 575 TRACE_SANITIZE (); 576 if (unlikely (!sanitize_shallow (c))) return false; 577 578 /* Note: for structs that do not reference other structs, 579 * we do not need to call their sanitize() as we already did 580 * a bound check on the aggregate array size. We just include 581 * a small unreachable expression to make sure the structs 582 * pointed to do have a simple sanitize(), ie. they do not 583 * reference other structs via offsets. 584 */ 585 (void) (false && array[0].sanitize (c)); 586 587 return true; 588 } 589 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 590 TRACE_SANITIZE (); 591 if (unlikely (!sanitize_shallow (c))) return false; 592 unsigned int count = len; 593 for (unsigned int i = 0; i < count; i++) 594 if (unlikely (!array[i].sanitize (c, base))) 595 return false; 596 return true; 597 } 598 template <typename T> 599 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { 600 TRACE_SANITIZE (); 601 if (unlikely (!sanitize_shallow (c))) return false; 602 unsigned int count = len; 603 for (unsigned int i = 0; i < count; i++) 604 if (unlikely (!array[i].sanitize (c, base, user_data))) 605 return false; 606 return true; 607 } 608 609 private: 610 inline bool sanitize_shallow (hb_sanitize_context_t *c) { 611 TRACE_SANITIZE (); 612 return c->check_struct (this) 613 && c->check_array (this, Type::static_size, len); 614 } 615 616 public: 617 LenType len; 618 Type array[VAR]; 619 public: 620 DEFINE_SIZE_ARRAY (sizeof (LenType), array); 621}; 622 623/* An array with a USHORT number of elements. */ 624template <typename Type> 625struct ArrayOf : GenericArrayOf<USHORT, Type> {}; 626 627/* An array with a ULONG number of elements. */ 628template <typename Type> 629struct LongArrayOf : GenericArrayOf<ULONG, Type> {}; 630 631/* Array of Offset's */ 632template <typename Type> 633struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {}; 634 635/* Array of LongOffset's */ 636template <typename Type> 637struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {}; 638 639/* LongArray of LongOffset's */ 640template <typename Type> 641struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {}; 642 643/* Array of offsets relative to the beginning of the array itself. */ 644template <typename Type> 645struct OffsetListOf : OffsetArrayOf<Type> 646{ 647 inline const Type& operator [] (unsigned int i) const 648 { 649 if (unlikely (i >= this->len)) return Null(Type); 650 return this+this->array[i]; 651 } 652 653 inline bool sanitize (hb_sanitize_context_t *c) { 654 TRACE_SANITIZE (); 655 return OffsetArrayOf<Type>::sanitize (c, this); 656 } 657 template <typename T> 658 inline bool sanitize (hb_sanitize_context_t *c, T user_data) { 659 TRACE_SANITIZE (); 660 return OffsetArrayOf<Type>::sanitize (c, this, user_data); 661 } 662}; 663 664 665/* An array with a USHORT number of elements, 666 * starting at second element. */ 667template <typename Type> 668struct HeadlessArrayOf 669{ 670 inline const Type& operator [] (unsigned int i) const 671 { 672 if (unlikely (i >= len || !i)) return Null(Type); 673 return array[i-1]; 674 } 675 inline unsigned int get_size (void) const 676 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } 677 678 inline bool sanitize_shallow (hb_sanitize_context_t *c) { 679 return c->check_struct (this) 680 && c->check_array (this, Type::static_size, len); 681 } 682 683 inline bool sanitize (hb_sanitize_context_t *c) { 684 TRACE_SANITIZE (); 685 if (unlikely (!sanitize_shallow (c))) return false; 686 687 /* Note: for structs that do not reference other structs, 688 * we do not need to call their sanitize() as we already did 689 * a bound check on the aggregate array size. We just include 690 * a small unreachable expression to make sure the structs 691 * pointed to do have a simple sanitize(), ie. they do not 692 * reference other structs via offsets. 693 */ 694 (void) (false && array[0].sanitize (c)); 695 696 return true; 697 } 698 699 USHORT len; 700 Type array[VAR]; 701 public: 702 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); 703}; 704 705 706/* An array with sorted elements. Supports binary searching. */ 707template <typename Type> 708struct SortedArrayOf : ArrayOf<Type> { 709 710 template <typename SearchType> 711 inline int search (const SearchType &x) const { 712 class Cmp { 713 public: static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); } 714 }; 715 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp); 716 return p ? p - this->array : -1; 717 } 718}; 719 720 721HB_BEGIN_DECLS 722HB_END_DECLS 723 724#endif /* HB_OPEN_TYPE_PRIVATE_HH */ 725