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_PRIVATE_HH 30#define HB_OPEN_TYPE_PRIVATE_HH 31 32#include "hb-private.hh" 33 34#include "hb-blob.h" 35 36 37namespace OT { 38 39 40 41/* 42 * Casts 43 */ 44 45/* Cast to struct T, reference to reference */ 46template<typename Type, typename TObject> 47inline const Type& CastR(const TObject &X) 48{ return reinterpret_cast<const Type&> (X); } 49template<typename Type, typename TObject> 50inline Type& CastR(TObject &X) 51{ return reinterpret_cast<Type&> (X); } 52 53/* Cast to struct T, pointer to pointer */ 54template<typename Type, typename TObject> 55inline const Type* CastP(const TObject *X) 56{ return reinterpret_cast<const Type*> (X); } 57template<typename Type, typename TObject> 58inline Type* CastP(TObject *X) 59{ return reinterpret_cast<Type*> (X); } 60 61/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory 62 * location pointed to by P plus Ofs bytes. */ 63template<typename Type> 64inline const Type& StructAtOffset(const void *P, unsigned int offset) 65{ return * reinterpret_cast<const Type*> ((const char *) P + offset); } 66template<typename Type> 67inline Type& StructAtOffset(void *P, unsigned int offset) 68{ return * reinterpret_cast<Type*> ((char *) P + offset); } 69 70/* StructAfter<T>(X) returns the struct T& that is placed after X. 71 * Works with X of variable size also. X must implement get_size() */ 72template<typename Type, typename TObject> 73inline const Type& StructAfter(const TObject &X) 74{ return StructAtOffset<Type>(&X, X.get_size()); } 75template<typename Type, typename TObject> 76inline Type& StructAfter(TObject &X) 77{ return StructAtOffset<Type>(&X, X.get_size()); } 78 79 80 81/* 82 * Size checking 83 */ 84 85/* Check _assertion in a method environment */ 86#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ 87 inline void _instance_assertion_on_line_##_line (void) const \ 88 { \ 89 ASSERT_STATIC (_assertion); \ 90 ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \ 91 } 92# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) 93# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) 94 95/* Check that _code compiles in a method environment */ 96#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ 97 inline void _compiles_assertion_on_line_##_line (void) const \ 98 { _code; } 99# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) 100# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) 101 102 103#define DEFINE_SIZE_STATIC(size) \ 104 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \ 105 static const unsigned int static_size = (size); \ 106 static const unsigned int min_size = (size) 107 108/* Size signifying variable-sized array */ 109#define VAR 1 110 111#define DEFINE_SIZE_UNION(size, _member) \ 112 DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \ 113 static const unsigned int min_size = (size) 114 115#define DEFINE_SIZE_MIN(size) \ 116 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \ 117 static const unsigned int min_size = (size) 118 119#define DEFINE_SIZE_ARRAY(size, array) \ 120 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \ 121 DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \ 122 static const unsigned int min_size = (size) 123 124#define DEFINE_SIZE_ARRAY2(size, array1, array2) \ 125 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \ 126 DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \ 127 static const unsigned int min_size = (size) 128 129 130 131/* 132 * Null objects 133 */ 134 135/* Global nul-content Null pool. Enlarge as necessary. */ 136/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */ 137static const void *_NullPool[64 / sizeof (void *)]; 138 139/* Generic nul-content Null objects. */ 140template <typename Type> 141static inline const Type& Null (void) { 142 ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool)); 143 return *CastP<Type> (_NullPool); 144} 145 146/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ 147#define DEFINE_NULL_DATA(Type, data) \ 148static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \ 149template <> \ 150inline const Type& Null<Type> (void) { \ 151 return *CastP<Type> (_Null##Type); \ 152} /* The following line really exists such that we end in a place needing semicolon */ \ 153ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) 154 155/* Accessor macro. */ 156#define Null(Type) Null<Type>() 157 158 159 160/* 161 * Sanitize 162 */ 163 164#ifndef HB_DEBUG_SANITIZE 165#define HB_DEBUG_SANITIZE (HB_DEBUG+0) 166#endif 167 168 169#define TRACE_SANITIZE(this) \ 170 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \ 171 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 172 ""); 173 174/* This limits sanitizing time on really broken fonts. */ 175#ifndef HB_SANITIZE_MAX_EDITS 176#define HB_SANITIZE_MAX_EDITS 100 177#endif 178 179struct hb_sanitize_context_t 180{ 181 inline const char *get_name (void) { return "SANITIZE"; } 182 static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE; 183 typedef bool return_t; 184 template <typename T> 185 inline return_t dispatch (const T &obj) { return obj.sanitize (this); } 186 static return_t default_return_value (void) { return true; } 187 bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } 188 189 inline void init (hb_blob_t *b) 190 { 191 this->blob = hb_blob_reference (b); 192 this->writable = false; 193 } 194 195 inline void start_processing (void) 196 { 197 this->start = hb_blob_get_data (this->blob, NULL); 198 this->end = this->start + hb_blob_get_length (this->blob); 199 this->edit_count = 0; 200 this->debug_depth = 0; 201 202 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1, 203 "start [%p..%p] (%lu bytes)", 204 this->start, this->end, 205 (unsigned long) (this->end - this->start)); 206 } 207 208 inline void end_processing (void) 209 { 210 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1, 211 "end [%p..%p] %u edit requests", 212 this->start, this->end, this->edit_count); 213 214 hb_blob_destroy (this->blob); 215 this->blob = NULL; 216 this->start = this->end = NULL; 217 } 218 219 inline bool check_range (const void *base, unsigned int len) const 220 { 221 const char *p = (const char *) base; 222 223 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace 224 (&this->debug_depth, "SANITIZE", this->blob, NULL, 225 "check_range [%p..%p] (%d bytes) in [%p..%p]", 226 p, p + len, len, 227 this->start, this->end); 228 229 return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len)); 230 } 231 232 inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const 233 { 234 const char *p = (const char *) base; 235 bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); 236 237 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace 238 (&this->debug_depth, "SANITIZE", this->blob, NULL, 239 "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]", 240 p, p + (record_size * len), record_size, len, (unsigned long) record_size * len, 241 this->start, this->end); 242 243 return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len))); 244 } 245 246 template <typename Type> 247 inline bool check_struct (const Type *obj) const 248 { 249 return likely (this->check_range (obj, obj->min_size)); 250 } 251 252 inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) 253 { 254 if (this->edit_count >= HB_SANITIZE_MAX_EDITS) 255 return false; 256 257 const char *p = (const char *) base; 258 this->edit_count++; 259 260 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace 261 (&this->debug_depth, "SANITIZE", this->blob, NULL, 262 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", 263 this->edit_count, 264 p, p + len, len, 265 this->start, this->end, 266 this->writable ? "GRANTED" : "DENIED"); 267 268 return TRACE_RETURN (this->writable); 269 } 270 271 mutable unsigned int debug_depth; 272 const char *start, *end; 273 bool writable; 274 unsigned int edit_count; 275 hb_blob_t *blob; 276}; 277 278 279 280/* Template to sanitize an object. */ 281template <typename Type> 282struct Sanitizer 283{ 284 static hb_blob_t *sanitize (hb_blob_t *blob) { 285 hb_sanitize_context_t c[1] = {{0}}; 286 bool sane; 287 288 /* TODO is_sane() stuff */ 289 290 c->init (blob); 291 292 retry: 293 DEBUG_MSG_FUNC (SANITIZE, blob, "start"); 294 295 c->start_processing (); 296 297 if (unlikely (!c->start)) { 298 c->end_processing (); 299 return blob; 300 } 301 302 Type *t = CastP<Type> (const_cast<char *> (c->start)); 303 304 sane = t->sanitize (c); 305 if (sane) { 306 if (c->edit_count) { 307 DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count); 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 DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count); 314 sane = false; 315 } 316 } 317 } else { 318 unsigned int edit_count = c->edit_count; 319 if (edit_count && !c->writable) { 320 c->start = hb_blob_get_data_writable (blob, NULL); 321 c->end = c->start + hb_blob_get_length (blob); 322 323 if (c->start) { 324 c->writable = true; 325 /* ok, we made it writable by relocating. try again */ 326 DEBUG_MSG_FUNC (SANITIZE, blob, "retry"); 327 goto retry; 328 } 329 } 330 } 331 332 c->end_processing (); 333 334 DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED"); 335 if (sane) 336 return blob; 337 else { 338 hb_blob_destroy (blob); 339 return hb_blob_get_empty (); 340 } 341 } 342 343 static const Type* lock_instance (hb_blob_t *blob) { 344 hb_blob_make_immutable (blob); 345 const char *base = hb_blob_get_data (blob, NULL); 346 return unlikely (!base) ? &Null(Type) : CastP<Type> (base); 347 } 348}; 349 350 351 352/* 353 * Serialize 354 */ 355 356#ifndef HB_DEBUG_SERIALIZE 357#define HB_DEBUG_SERIALIZE (HB_DEBUG+0) 358#endif 359 360 361#define TRACE_SERIALIZE(this) \ 362 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \ 363 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ 364 ""); 365 366 367struct hb_serialize_context_t 368{ 369 inline hb_serialize_context_t (void *start, unsigned int size) 370 { 371 this->start = (char *) start; 372 this->end = this->start + size; 373 374 this->ran_out_of_room = false; 375 this->head = this->start; 376 this->debug_depth = 0; 377 } 378 379 template <typename Type> 380 inline Type *start_serialize (void) 381 { 382 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, 383 "start [%p..%p] (%lu bytes)", 384 this->start, this->end, 385 (unsigned long) (this->end - this->start)); 386 387 return start_embed<Type> (); 388 } 389 390 inline void end_serialize (void) 391 { 392 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, 393 "end [%p..%p] serialized %d bytes; %s", 394 this->start, this->end, 395 (int) (this->head - this->start), 396 this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room"); 397 398 } 399 400 template <typename Type> 401 inline Type *copy (void) 402 { 403 assert (!this->ran_out_of_room); 404 unsigned int len = this->head - this->start; 405 void *p = malloc (len); 406 if (p) 407 memcpy (p, this->start, len); 408 return reinterpret_cast<Type *> (p); 409 } 410 411 template <typename Type> 412 inline Type *allocate_size (unsigned int size) 413 { 414 if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) { 415 this->ran_out_of_room = true; 416 return NULL; 417 } 418 memset (this->head, 0, size); 419 char *ret = this->head; 420 this->head += size; 421 return reinterpret_cast<Type *> (ret); 422 } 423 424 template <typename Type> 425 inline Type *allocate_min (void) 426 { 427 return this->allocate_size<Type> (Type::min_size); 428 } 429 430 template <typename Type> 431 inline Type *start_embed (void) 432 { 433 Type *ret = reinterpret_cast<Type *> (this->head); 434 return ret; 435 } 436 437 template <typename Type> 438 inline Type *embed (const Type &obj) 439 { 440 unsigned int size = obj.get_size (); 441 Type *ret = this->allocate_size<Type> (size); 442 if (unlikely (!ret)) return NULL; 443 memcpy (ret, obj, size); 444 return ret; 445 } 446 447 template <typename Type> 448 inline Type *extend_min (Type &obj) 449 { 450 unsigned int size = obj.min_size; 451 assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); 452 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL; 453 return reinterpret_cast<Type *> (&obj); 454 } 455 456 template <typename Type> 457 inline Type *extend (Type &obj) 458 { 459 unsigned int size = obj.get_size (); 460 assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); 461 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL; 462 return reinterpret_cast<Type *> (&obj); 463 } 464 465 inline void truncate (void *head) 466 { 467 assert (this->start < head && head <= this->head); 468 this->head = (char *) head; 469 } 470 471 unsigned int debug_depth; 472 char *start, *end, *head; 473 bool ran_out_of_room; 474}; 475 476template <typename Type> 477struct Supplier 478{ 479 inline Supplier (const Type *array, unsigned int len_) 480 { 481 head = array; 482 len = len_; 483 } 484 inline const Type operator [] (unsigned int i) const 485 { 486 if (unlikely (i >= len)) return Type (); 487 return head[i]; 488 } 489 490 inline void advance (unsigned int count) 491 { 492 if (unlikely (count > len)) 493 count = len; 494 len -= count; 495 head += count; 496 } 497 498 private: 499 inline Supplier (const Supplier<Type> &); /* Disallow copy */ 500 inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */ 501 502 unsigned int len; 503 const Type *head; 504}; 505 506 507 508 509/* 510 * 511 * The OpenType Font File: Data Types 512 */ 513 514 515/* "The following data types are used in the OpenType font file. 516 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 517 518/* 519 * Int types 520 */ 521 522 523template <typename Type, int Bytes> struct BEInt; 524 525template <typename Type> 526struct BEInt<Type, 2> 527{ 528 public: 529 inline void set (Type i) { hb_be_uint16_put (v,i); } 530 inline operator Type (void) const { return hb_be_uint16_get (v); } 531 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); } 532 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); } 533 private: uint8_t v[2]; 534}; 535template <typename Type> 536struct BEInt<Type, 4> 537{ 538 public: 539 inline void set (Type i) { hb_be_uint32_put (v,i); } 540 inline operator Type (void) const { return hb_be_uint32_get (v); } 541 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); } 542 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); } 543 private: uint8_t v[4]; 544}; 545template <typename Type> 546struct BEInt<Type, 3> 547{ 548 public: 549 inline void set (Type i) { hb_be_uint24_put (v,i); } 550 inline operator Type (void) const { return hb_be_uint24_get (v); } 551 inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); } 552 inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); } 553 private: uint8_t v[3]; 554}; 555 556/* Integer types in big-endian order and no alignment requirement */ 557template <typename Type, unsigned int Size> 558struct IntType 559{ 560 inline void set (Type i) { v.set (i); } 561 inline operator Type(void) const { return v; } 562 inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; } 563 inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; } 564 static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); } 565 inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } 566 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } 567 inline bool sanitize (hb_sanitize_context_t *c) { 568 TRACE_SANITIZE (this); 569 return TRACE_RETURN (likely (c->check_struct (this))); 570 } 571 protected: 572 BEInt<Type, Size> v; 573 public: 574 DEFINE_SIZE_STATIC (Size); 575}; 576 577typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */ 578typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */ 579typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */ 580typedef IntType<int32_t, 4> LONG; /* 32-bit signed integer. */ 581typedef IntType<uint32_t, 3> UINT24; /* 24-bit unsigned integer. */ 582 583/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ 584typedef SHORT FWORD; 585 586/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ 587typedef USHORT UFWORD; 588 589/* Date represented in number of seconds since 12:00 midnight, January 1, 590 * 1904. The value is represented as a signed 64-bit integer. */ 591struct LONGDATETIME 592{ 593 inline bool sanitize (hb_sanitize_context_t *c) { 594 TRACE_SANITIZE (this); 595 return TRACE_RETURN (likely (c->check_struct (this))); 596 } 597 private: 598 LONG major; 599 ULONG minor; 600 public: 601 DEFINE_SIZE_STATIC (8); 602}; 603 604/* Array of four uint8s (length = 32 bits) used to identify a script, language 605 * system, feature, or baseline */ 606struct Tag : ULONG 607{ 608 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ 609 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); } 610 inline operator char* (void) { return reinterpret_cast<char *> (&this->v); } 611 public: 612 DEFINE_SIZE_STATIC (4); 613}; 614DEFINE_NULL_DATA (Tag, " "); 615 616/* Glyph index number, same as uint16 (length = 16 bits) */ 617typedef USHORT GlyphID; 618 619/* Script/language-system/feature index */ 620struct Index : USHORT { 621 static const unsigned int NOT_FOUND_INDEX = 0xFFFF; 622}; 623DEFINE_NULL_DATA (Index, "\xff\xff"); 624 625/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */ 626struct Offset : USHORT 627{ 628 inline bool is_null (void) const { return 0 == *this; } 629 public: 630 DEFINE_SIZE_STATIC (2); 631}; 632 633/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */ 634struct LongOffset : ULONG 635{ 636 inline bool is_null (void) const { return 0 == *this; } 637 public: 638 DEFINE_SIZE_STATIC (4); 639}; 640 641 642/* CheckSum */ 643struct CheckSum : ULONG 644{ 645 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) 646 { 647 uint32_t Sum = 0L; 648 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size; 649 650 while (Table < EndPtr) 651 Sum += *Table++; 652 return Sum; 653 } 654 public: 655 DEFINE_SIZE_STATIC (4); 656}; 657 658 659/* 660 * Version Numbers 661 */ 662 663struct FixedVersion 664{ 665 inline uint32_t to_int (void) const { return (major << 16) + minor; } 666 667 inline bool sanitize (hb_sanitize_context_t *c) { 668 TRACE_SANITIZE (this); 669 return TRACE_RETURN (c->check_struct (this)); 670 } 671 672 USHORT major; 673 USHORT minor; 674 public: 675 DEFINE_SIZE_STATIC (4); 676}; 677 678 679 680/* 681 * Template subclasses of Offset and LongOffset that do the dereferencing. 682 * Use: (base+offset) 683 */ 684 685template <typename OffsetType, typename Type> 686struct GenericOffsetTo : OffsetType 687{ 688 inline const Type& operator () (const void *base) const 689 { 690 unsigned int offset = *this; 691 if (unlikely (!offset)) return Null(Type); 692 return StructAtOffset<Type> (base, offset); 693 } 694 695 inline Type& serialize (hb_serialize_context_t *c, void *base) 696 { 697 Type *t = c->start_embed<Type> (); 698 this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ 699 return *t; 700 } 701 702 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 703 TRACE_SANITIZE (this); 704 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); 705 unsigned int offset = *this; 706 if (unlikely (!offset)) return TRACE_RETURN (true); 707 Type &obj = StructAtOffset<Type> (base, offset); 708 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); 709 } 710 template <typename T> 711 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { 712 TRACE_SANITIZE (this); 713 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); 714 unsigned int offset = *this; 715 if (unlikely (!offset)) return TRACE_RETURN (true); 716 Type &obj = StructAtOffset<Type> (base, offset); 717 return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); 718 } 719 720 inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) { 721 if (c->may_edit (this, this->static_size)) { 722 this->set (v); 723 return true; 724 } 725 return false; 726 } 727 /* Set the offset to Null */ 728 inline bool neuter (hb_sanitize_context_t *c) { 729 if (c->may_edit (this, this->static_size)) { 730 this->set (0); /* 0 is Null offset */ 731 return true; 732 } 733 return false; 734 } 735}; 736template <typename Base, typename OffsetType, typename Type> 737inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); } 738template <typename Base, typename OffsetType, typename Type> 739inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); } 740 741template <typename Type> 742struct OffsetTo : GenericOffsetTo<Offset, Type> {}; 743 744template <typename Type> 745struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {}; 746 747 748/* 749 * Array Types 750 */ 751 752template <typename LenType, typename Type> 753struct GenericArrayOf 754{ 755 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const 756 { 757 unsigned int count = len; 758 if (unlikely (start_offset > count)) 759 count = 0; 760 else 761 count -= start_offset; 762 count = MIN (count, *pcount); 763 *pcount = count; 764 return array + start_offset; 765 } 766 767 inline const Type& operator [] (unsigned int i) const 768 { 769 if (unlikely (i >= len)) return Null(Type); 770 return array[i]; 771 } 772 inline Type& operator [] (unsigned int i) 773 { 774 return array[i]; 775 } 776 inline unsigned int get_size (void) const 777 { return len.static_size + len * Type::static_size; } 778 779 inline bool serialize (hb_serialize_context_t *c, 780 unsigned int items_len) 781 { 782 TRACE_SERIALIZE (this); 783 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 784 len.set (items_len); /* TODO(serialize) Overflow? */ 785 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); 786 return TRACE_RETURN (true); 787 } 788 789 inline bool serialize (hb_serialize_context_t *c, 790 Supplier<Type> &items, 791 unsigned int items_len) 792 { 793 TRACE_SERIALIZE (this); 794 if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false); 795 for (unsigned int i = 0; i < items_len; i++) 796 array[i] = items[i]; 797 items.advance (items_len); 798 return TRACE_RETURN (true); 799 } 800 801 inline bool sanitize (hb_sanitize_context_t *c) { 802 TRACE_SANITIZE (this); 803 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); 804 805 /* Note: for structs that do not reference other structs, 806 * we do not need to call their sanitize() as we already did 807 * a bound check on the aggregate array size. We just include 808 * a small unreachable expression to make sure the structs 809 * pointed to do have a simple sanitize(), ie. they do not 810 * reference other structs via offsets. 811 */ 812 (void) (false && array[0].sanitize (c)); 813 814 return TRACE_RETURN (true); 815 } 816 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 817 TRACE_SANITIZE (this); 818 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); 819 unsigned int count = len; 820 for (unsigned int i = 0; i < count; i++) 821 if (unlikely (!array[i].sanitize (c, base))) 822 return TRACE_RETURN (false); 823 return TRACE_RETURN (true); 824 } 825 template <typename T> 826 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { 827 TRACE_SANITIZE (this); 828 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); 829 unsigned int count = len; 830 for (unsigned int i = 0; i < count; i++) 831 if (unlikely (!array[i].sanitize (c, base, user_data))) 832 return TRACE_RETURN (false); 833 return TRACE_RETURN (true); 834 } 835 836 private: 837 inline bool sanitize_shallow (hb_sanitize_context_t *c) { 838 TRACE_SANITIZE (this); 839 return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len)); 840 } 841 842 public: 843 LenType len; 844 Type array[VAR]; 845 public: 846 DEFINE_SIZE_ARRAY (sizeof (LenType), array); 847}; 848 849/* An array with a USHORT number of elements. */ 850template <typename Type> 851struct ArrayOf : GenericArrayOf<USHORT, Type> {}; 852 853/* An array with a ULONG number of elements. */ 854template <typename Type> 855struct LongArrayOf : GenericArrayOf<ULONG, Type> {}; 856 857/* Array of Offset's */ 858template <typename Type> 859struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {}; 860 861/* Array of LongOffset's */ 862template <typename Type> 863struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {}; 864 865/* LongArray of LongOffset's */ 866template <typename Type> 867struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {}; 868 869/* Array of offsets relative to the beginning of the array itself. */ 870template <typename Type> 871struct OffsetListOf : OffsetArrayOf<Type> 872{ 873 inline const Type& operator [] (unsigned int i) const 874 { 875 if (unlikely (i >= this->len)) return Null(Type); 876 return this+this->array[i]; 877 } 878 879 inline bool sanitize (hb_sanitize_context_t *c) { 880 TRACE_SANITIZE (this); 881 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this)); 882 } 883 template <typename T> 884 inline bool sanitize (hb_sanitize_context_t *c, T user_data) { 885 TRACE_SANITIZE (this); 886 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data)); 887 } 888}; 889 890 891/* An array with a USHORT number of elements, 892 * starting at second element. */ 893template <typename Type> 894struct HeadlessArrayOf 895{ 896 inline const Type& operator [] (unsigned int i) const 897 { 898 if (unlikely (i >= len || !i)) return Null(Type); 899 return array[i-1]; 900 } 901 inline unsigned int get_size (void) const 902 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } 903 904 inline bool serialize (hb_serialize_context_t *c, 905 Supplier<Type> &items, 906 unsigned int items_len) 907 { 908 TRACE_SERIALIZE (this); 909 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 910 len.set (items_len); /* TODO(serialize) Overflow? */ 911 if (unlikely (!items_len)) return TRACE_RETURN (true); 912 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); 913 for (unsigned int i = 0; i < items_len - 1; i++) 914 array[i] = items[i]; 915 items.advance (items_len - 1); 916 return TRACE_RETURN (true); 917 } 918 919 inline bool sanitize_shallow (hb_sanitize_context_t *c) { 920 return c->check_struct (this) 921 && c->check_array (this, Type::static_size, len); 922 } 923 924 inline bool sanitize (hb_sanitize_context_t *c) { 925 TRACE_SANITIZE (this); 926 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); 927 928 /* Note: for structs that do not reference other structs, 929 * we do not need to call their sanitize() as we already did 930 * a bound check on the aggregate array size. We just include 931 * a small unreachable expression to make sure the structs 932 * pointed to do have a simple sanitize(), ie. they do not 933 * reference other structs via offsets. 934 */ 935 (void) (false && array[0].sanitize (c)); 936 937 return TRACE_RETURN (true); 938 } 939 940 USHORT len; 941 Type array[VAR]; 942 public: 943 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); 944}; 945 946 947/* An array with sorted elements. Supports binary searching. */ 948template <typename Type> 949struct SortedArrayOf : ArrayOf<Type> { 950 951 template <typename SearchType> 952 inline int search (const SearchType &x) const { 953 unsigned int count = this->len; 954 /* Linear search is *much* faster for small counts. */ 955 if (likely (count < 32)) { 956 for (unsigned int i = 0; i < count; i++) 957 if (this->array[i].cmp (x) == 0) 958 return i; 959 return -1; 960 } else { 961 struct Cmp { 962 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); } 963 }; 964 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp); 965 return p ? p - this->array : -1; 966 } 967 } 968}; 969 970 971} /* namespace OT */ 972 973 974#endif /* HB_OPEN_TYPE_PRIVATE_HH */ 975