hb-open-type-private.hh revision 2c9fd2adce5a6a9dcd62c874bd64613ea68d8d9b
1/* 2 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. 3 * 4 * This is part of HarfBuzz, an OpenType Layout engine 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_TYPES_PRIVATE_HH 28#define HB_OPEN_TYPES_PRIVATE_HH 29 30#include "hb-private.h" 31 32#include "hb-blob.h" 33 34 35#define NO_INDEX ((unsigned int) 0xFFFF) 36 37 38/* 39 * Casts 40 */ 41 42#define CONST_CHARP(X) (reinterpret_cast<const char *>(X)) 43#define DECONST_CHARP(X) ((char *)reinterpret_cast<const char *>(X)) 44#define CHARP(X) (reinterpret_cast<char *>(X)) 45 46#define CONST_CAST(T,X,Ofs) (*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + Ofs))) 47#define DECONST_CAST(T,X,Ofs) (*(reinterpret_cast<T *>((char *)CONST_CHARP(&(X)) + Ofs))) 48#define CAST(T,X,Ofs) (*(reinterpret_cast<T *>(CHARP(&(X)) + Ofs))) 49 50#define CONST_NEXT(T,X) (*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + (X).get_size ()))) 51#define NEXT(T,X) (*(reinterpret_cast<T *>(CHARP(&(X)) + (X).get_size ()))) 52 53#define CONST_ARRAY_AFTER(T,X) ((reinterpret_cast<const T *>(CONST_CHARP(&(X)) + X.get_size ()))) 54#define ARRAY_AFTER(T,X) ((reinterpret_cast<T *>(CHARP(&(X)) + X.get_size ()))) 55 56/* 57 * Class features 58 */ 59 60 61/* Null objects */ 62 63/* Global nul-content Null pool. Enlarge as necessary. */ 64static const void *_NullPool[32 / sizeof (void *)]; 65 66/* Generic template for nul-content sizeof-sized Null objects. */ 67template <typename Type> 68static inline const Type& Null () { 69 ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool)); 70 return CONST_CAST (Type, *_NullPool, 0); 71} 72 73/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ 74#define DEFINE_NULL_DATA(Type, size, data) \ 75static const char _Null##Type[size + 1] = data; \ 76template <> \ 77inline const Type& Null<Type> () { \ 78 return CONST_CAST (Type, *_Null##Type, 0); \ 79} 80 81/* Accessor macro. */ 82#define Null(Type) Null<Type>() 83 84 85/* get_for_data() is a static class method returning a reference to an 86 * instance of Type located at the input data location. It's just a 87 * fancy, NULL-safe, cast! */ 88#define STATIC_DEFINE_GET_FOR_DATA(Type) \ 89 static inline const Type& get_for_data (const char *data) \ 90 { \ 91 if (HB_UNLIKELY (data == NULL)) return Null(Type); \ 92 return CONST_CAST (Type, *data, 0); \ 93 } 94/* Like get_for_data(), but checks major version first. */ 95#define STATIC_DEFINE_GET_FOR_DATA_CHECK_MAJOR_VERSION(Type, MajorMin, MajorMax) \ 96 static inline const Type& get_for_data (const char *data) \ 97 { \ 98 if (HB_UNLIKELY (data == NULL)) return Null(Type); \ 99 const Type& t = CONST_CAST (Type, *data, 0); \ 100 if (HB_UNLIKELY (t.version.major < MajorMin || t.version.major > MajorMax)) return Null(Type); \ 101 return t; \ 102 } 103 104 105/* 106 * Sanitize 107 */ 108 109#ifndef HB_DEBUG_SANITIZE 110#define HB_DEBUG_SANITIZE HB_DEBUG 111#endif 112 113#if HB_DEBUG_SANITIZE 114#include <stdio.h> 115#define TRACE_SANITIZE_ARG_DEF , unsigned int sanitize_depth HB_GNUC_UNUSED 116#define TRACE_SANITIZE_ARG , sanitize_depth + 1 117#define TRACE_SANITIZE_ARG_INIT , 1 118#define TRACE_SANITIZE() \ 119 HB_STMT_START { \ 120 if (sanitize_depth < HB_DEBUG_SANITIZE) \ 121 fprintf (stderr, "SANITIZE(%p) %-*d-> %s\n", \ 122 (CONST_CHARP (this) == CONST_CHARP (&NullPool)) ? 0 : this, \ 123 sanitize_depth, sanitize_depth, \ 124 __PRETTY_FUNCTION__); \ 125 } HB_STMT_END 126#else 127#define TRACE_SANITIZE_ARG_DEF 128#define TRACE_SANITIZE_ARG 129#define TRACE_SANITIZE_ARG_INIT 130#define TRACE_SANITIZE() HB_STMT_START {} HB_STMT_END 131#endif 132 133#define SANITIZE_ARG_DEF \ 134 hb_sanitize_context_t *context TRACE_SANITIZE_ARG_DEF 135#define SANITIZE_ARG \ 136 context TRACE_SANITIZE_ARG 137#define SANITIZE_ARG_INIT \ 138 &context TRACE_SANITIZE_ARG_INIT 139 140typedef struct _hb_sanitize_context_t hb_sanitize_context_t; 141struct _hb_sanitize_context_t 142{ 143 const char *start, *end; 144 int edit_count; 145 hb_blob_t *blob; 146}; 147 148static HB_GNUC_UNUSED void 149_hb_sanitize_init (hb_sanitize_context_t *context, 150 hb_blob_t *blob) 151{ 152 context->blob = blob; 153 context->start = hb_blob_lock (blob); 154 context->end = context->start + hb_blob_get_length (blob); 155 context->edit_count = 0; 156 157#if HB_DEBUG_SANITIZE 158 fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n", 159 context->blob, context->start, context->end, context->end - context->start); 160#endif 161} 162 163static HB_GNUC_UNUSED void 164_hb_sanitize_fini (hb_sanitize_context_t *context, 165 bool unlock) 166{ 167#if HB_DEBUG_SANITIZE 168 fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n", 169 context->blob, context->start, context->end, context->edit_count); 170#endif 171 172 if (unlock) 173 hb_blob_unlock (context->blob); 174} 175 176static HB_GNUC_UNUSED inline bool 177_hb_sanitize_check (SANITIZE_ARG_DEF, 178 const char *base, 179 unsigned int len) 180{ 181 bool ret = context->start <= base && 182 base <= context->end && 183 (unsigned int) (context->end - base) >= len; 184 185#if HB_DEBUG_SANITIZE 186 if (sanitize_depth < HB_DEBUG_SANITIZE) \ 187 fprintf (stderr, "SANITIZE(%p) %-*d-> check [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \ 188 base, 189 sanitize_depth, sanitize_depth, 190 base, base+len, len, 191 context->start, context->end, 192 ret ? "pass" : "FAIL"); 193#endif 194 return ret; 195} 196 197static HB_GNUC_UNUSED inline bool 198_hb_sanitize_array (SANITIZE_ARG_DEF, 199 const char *base, 200 unsigned int record_size, 201 unsigned int len) 202{ 203 bool overflows = len >= ((unsigned int) -1) / record_size; 204 205#if HB_DEBUG_SANITIZE 206 if (sanitize_depth < HB_DEBUG_SANITIZE) \ 207 fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \ 208 base, 209 sanitize_depth, sanitize_depth, 210 base, base + (record_size * len), record_size, len, (unsigned long) record_size * len, 211 context->start, context->end, 212 !overflows ? "does not overflow" : "OVERFLOWS FAIL"); 213#endif 214 return HB_LIKELY (!overflows) && _hb_sanitize_check (SANITIZE_ARG, base, record_size * len); 215} 216 217static HB_GNUC_UNUSED inline bool 218_hb_sanitize_edit (SANITIZE_ARG_DEF, 219 const char *base HB_GNUC_UNUSED, 220 unsigned int len HB_GNUC_UNUSED) 221{ 222 bool perm = hb_blob_try_writable_inplace (context->blob); 223 context->edit_count++; 224 225#if HB_DEBUG_SANITIZE 226 fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \ 227 base, 228 sanitize_depth, sanitize_depth, 229 context->edit_count, 230 base, base+len, len, 231 context->start, context->end, 232 perm ? "granted" : "REJECTED"); 233#endif 234 return perm; 235} 236 237#define SANITIZE(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG)) 238#define SANITIZE2(X,Y) (SANITIZE (X) && SANITIZE (Y)) 239 240#define SANITIZE_THIS(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG, CONST_CHARP(this))) 241#define SANITIZE_THIS2(X,Y) (SANITIZE_THIS (X) && SANITIZE_THIS (Y)) 242#define SANITIZE_THIS3(X,Y,Z) (SANITIZE_THIS (X) && SANITIZE_THIS (Y) && SANITIZE_THIS(Z)) 243 244#define SANITIZE_BASE(X,B) HB_LIKELY ((X).sanitize (SANITIZE_ARG, B)) 245#define SANITIZE_BASE2(X,Y,B) (SANITIZE_BASE (X,B) && SANITIZE_BASE (Y,B)) 246 247#define SANITIZE_SELF() SANITIZE_OBJ (*this) 248#define SANITIZE_OBJ(X) SANITIZE_MEM(&(X), sizeof (X)) 249#define SANITIZE_GET_SIZE() SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ()) 250 251#define SANITIZE_MEM(B,L) HB_LIKELY (_hb_sanitize_check (SANITIZE_ARG, CONST_CHARP(B), (L))) 252 253#define SANITIZE_ARRAY(A,S,L) HB_LIKELY (_hb_sanitize_array (SANITIZE_ARG, CONST_CHARP(A), S, L)) 254 255#define NEUTER(Var, Val) \ 256 (SANITIZE_OBJ (Var) && \ 257 _hb_sanitize_edit (SANITIZE_ARG, CONST_CHARP(&(Var)), sizeof (Var)) && \ 258 ((Var).set (Val), true)) 259 260 261/* Template to sanitize an object. */ 262template <typename Type> 263struct Sanitizer 264{ 265 static hb_blob_t *sanitize (hb_blob_t *blob) { 266 hb_sanitize_context_t context; 267 bool sane; 268 269 /* TODO is_sane() stuff */ 270 271 retry: 272#if HB_DEBUG_SANITIZE 273 fprintf (stderr, "Sanitizer %p start %s\n", blob, __PRETTY_FUNCTION__); 274#endif 275 276 _hb_sanitize_init (&context, blob); 277 278 Type *t = &CAST (Type, *DECONST_CHARP(context.start), 0); 279 280 sane = t->sanitize (SANITIZE_ARG_INIT); 281 if (sane) { 282 if (context.edit_count) { 283#if HB_DEBUG_SANITIZE 284 fprintf (stderr, "Sanitizer %p passed first round with %d edits; going a second round %s\n", 285 blob, context.edit_count, __PRETTY_FUNCTION__); 286#endif 287 /* sanitize again to ensure no toe-stepping */ 288 context.edit_count = 0; 289 sane = t->sanitize (SANITIZE_ARG_INIT); 290 if (context.edit_count) { 291#if HB_DEBUG_SANITIZE 292 fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n", 293 blob, context.edit_count, __PRETTY_FUNCTION__); 294#endif 295 sane = false; 296 } 297 } 298 _hb_sanitize_fini (&context, true); 299 } else { 300 unsigned int edit_count = context.edit_count; 301 _hb_sanitize_fini (&context, true); 302 if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) { 303 /* ok, we made it writable by relocating. try again */ 304#if HB_DEBUG_SANITIZE 305 fprintf (stderr, "Sanitizer %p retry %s\n", blob, __PRETTY_FUNCTION__); 306#endif 307 goto retry; 308 } 309 } 310 311#if HB_DEBUG_SANITIZE 312 fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", __PRETTY_FUNCTION__); 313#endif 314 if (sane) 315 return blob; 316 else { 317 hb_blob_destroy (blob); 318 return hb_blob_create_empty (); 319 } 320 } 321 322 static const Type& lock_instance (hb_blob_t *blob) { 323 return Type::get_for_data (hb_blob_lock (blob)); 324 } 325}; 326 327 328/* 329 * 330 * The OpenType Font File: Data Types 331 */ 332 333 334/* "The following data types are used in the OpenType font file. 335 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 336 337/* 338 * Int types 339 */ 340 341#define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN, BYTES) \ 342 struct NAME \ 343 { \ 344 static inline unsigned int get_size () { return BYTES; } \ 345 inline void set (TYPE i) { BIG_ENDIAN##_put (v, i); } \ 346 inline operator TYPE(void) const { return BIG_ENDIAN##_get (v); } \ 347 inline bool operator == (const NAME &o) const { return BIG_ENDIAN##_cmp (v, o.v); } \ 348 inline bool sanitize (SANITIZE_ARG_DEF) { \ 349 TRACE_SANITIZE (); \ 350 return SANITIZE_SELF (); \ 351 } \ 352 private: unsigned char v[BYTES]; \ 353 }; \ 354 ASSERT_SIZE (NAME, BYTES) 355#define DEFINE_INT_TYPE0(NAME, type, b) DEFINE_INT_TYPE1 (NAME, type##_t, hb_be_##type, b) 356#define DEFINE_INT_TYPE(NAME, u, w) DEFINE_INT_TYPE0 (NAME, u##int##w, (w / 8)) 357 358 359DEFINE_INT_TYPE (USHORT, u, 16); /* 16-bit unsigned integer. */ 360DEFINE_INT_TYPE (SHORT, , 16); /* 16-bit signed integer. */ 361DEFINE_INT_TYPE (ULONG, u, 32); /* 32-bit unsigned integer. */ 362DEFINE_INT_TYPE (LONG, , 32); /* 32-bit signed integer. */ 363 364 365/* Array of four uint8s (length = 32 bits) used to identify a script, language 366 * system, feature, or baseline */ 367struct Tag : ULONG 368{ 369 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ 370 inline operator const char* (void) const { return CONST_CHARP(this); } 371 inline operator char* (void) { return CHARP(this); } 372 373 inline bool sanitize (SANITIZE_ARG_DEF) { 374 TRACE_SANITIZE (); 375 /* Note: Only accept ASCII-visible tags (mind DEL) 376 * This is one of the few places (only place?) that we check 377 * for data integrity, as opposed to just boundary checks. 378 */ 379 return SANITIZE_SELF () && (((uint32_t) *this) & 0x80808080) == 0; 380 } 381}; 382ASSERT_SIZE (Tag, 4); 383DEFINE_NULL_DATA (Tag, 4, " "); 384 385/* Glyph index number, same as uint16 (length = 16 bits) */ 386typedef USHORT GlyphID; 387 388/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */ 389typedef USHORT Offset; 390 391/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */ 392typedef ULONG LongOffset; 393 394 395/* CheckSum */ 396struct CheckSum : ULONG 397{ 398 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) 399 { 400 uint32_t Sum = 0L; 401 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::get_size (); 402 403 while (Table < EndPtr) 404 Sum += *Table++; 405 return Sum; 406 } 407}; 408ASSERT_SIZE (CheckSum, 4); 409 410 411/* 412 * Version Numbers 413 */ 414 415struct FixedVersion 416{ 417 inline operator uint32_t (void) const { return (major << 16) + minor; } 418 419 inline bool sanitize (SANITIZE_ARG_DEF) { 420 TRACE_SANITIZE (); 421 return SANITIZE_SELF (); 422 } 423 424 USHORT major; 425 USHORT minor; 426}; 427ASSERT_SIZE (FixedVersion, 4); 428 429 430 431/* 432 * Template subclasses of Offset and LongOffset that do the dereferencing. 433 * Use: (this+memberName) 434 */ 435 436template <typename OffsetType, typename Type> 437struct GenericOffsetTo : OffsetType 438{ 439 inline const Type& operator () (const void *base) const 440 { 441 unsigned int offset = *this; 442 if (HB_UNLIKELY (!offset)) return Null(Type); 443 return CONST_CAST(Type, *CONST_CHARP(base), offset); 444 } 445 446 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) { 447 TRACE_SANITIZE (); 448 if (!SANITIZE_SELF ()) return false; 449 unsigned int offset = *this; 450 if (HB_UNLIKELY (!offset)) return true; 451 return SANITIZE (CAST(Type, *DECONST_CHARP(base), offset)) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0); 452 } 453 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) { 454 TRACE_SANITIZE (); 455 if (!SANITIZE_SELF ()) return false; 456 unsigned int offset = *this; 457 if (HB_UNLIKELY (!offset)) return true; 458 return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), base2) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0); 459 } 460 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) { 461 TRACE_SANITIZE (); 462 if (!SANITIZE_SELF ()) return false; 463 unsigned int offset = *this; 464 if (HB_UNLIKELY (!offset)) return true; 465 return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), user_data) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0); 466 } 467}; 468template <typename Base, typename OffsetType, typename Type> 469inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); } 470 471template <typename Type> 472struct OffsetTo : GenericOffsetTo<Offset, Type> {}; 473 474template <typename Type> 475struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {}; 476 477 478/* 479 * Array Types 480 */ 481 482template <typename LenType, typename Type> 483struct GenericArrayOf 484{ 485 const Type *const_array(void) const { return CONST_ARRAY_AFTER (Type, len); } 486 Type *array(void) { return ARRAY_AFTER (Type, len); } 487 488 const Type *const_sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const 489 { 490 unsigned int count = len; 491 if (HB_UNLIKELY (start_offset > count)) 492 count = 0; 493 else 494 count -= start_offset; 495 count = MIN (count, *pcount); 496 *pcount = count; 497 return const_array() + start_offset; 498 } 499 500 inline const Type& operator [] (unsigned int i) const 501 { 502 if (HB_UNLIKELY (i >= len)) return Null(Type); 503 return const_array()[i]; 504 } 505 inline unsigned int get_size () const 506 { return len.get_size () + len * Type::get_size (); } 507 508 inline bool sanitize (SANITIZE_ARG_DEF) { 509 TRACE_SANITIZE (); 510 if (!SANITIZE_GET_SIZE()) return false; 511 /* Note: for structs that do not reference other structs, 512 * we do not need to call their sanitize() as we already did 513 * a bound check on the aggregate array size, hence the return. 514 */ 515 return true; 516 /* We do keep this code though to make sure the structs pointed 517 * to do have a simple sanitize(), ie. they do not reference 518 * other structs. */ 519 unsigned int count = len; 520 for (unsigned int i = 0; i < count; i++) 521 if (!SANITIZE (array()[i])) 522 return false; 523 return true; 524 } 525 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) { 526 TRACE_SANITIZE (); 527 if (!SANITIZE_GET_SIZE()) return false; 528 unsigned int count = len; 529 for (unsigned int i = 0; i < count; i++) 530 if (!array()[i].sanitize (SANITIZE_ARG, base)) 531 return false; 532 return true; 533 } 534 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) { 535 TRACE_SANITIZE (); 536 if (!SANITIZE_GET_SIZE()) return false; 537 unsigned int count = len; 538 for (unsigned int i = 0; i < count; i++) 539 if (!array()[i].sanitize (SANITIZE_ARG, base, base2)) 540 return false; 541 return true; 542 } 543 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) { 544 TRACE_SANITIZE (); 545 if (!SANITIZE_GET_SIZE()) return false; 546 unsigned int count = len; 547 for (unsigned int i = 0; i < count; i++) 548 if (!array()[i].sanitize (SANITIZE_ARG, base, user_data)) 549 return false; 550 return true; 551 } 552 553 LenType len; 554/*Type array[VAR];*/ 555}; 556 557/* An array with a USHORT number of elements. */ 558template <typename Type> 559struct ArrayOf : GenericArrayOf<USHORT, Type> {}; 560 561/* An array with a ULONG number of elements. */ 562template <typename Type> 563struct LongArrayOf : GenericArrayOf<ULONG, Type> {}; 564 565/* Array of Offset's */ 566template <typename Type> 567struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {}; 568 569/* Array of LongOffset's */ 570template <typename Type> 571struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {}; 572 573/* LongArray of LongOffset's */ 574template <typename Type> 575struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {}; 576 577/* Array of offsets relative to the beginning of the array itself. */ 578template <typename Type> 579struct OffsetListOf : OffsetArrayOf<Type> 580{ 581 inline const Type& operator [] (unsigned int i) const 582 { 583 if (HB_UNLIKELY (i >= this->len)) return Null(Type); 584 return this+this->const_array()[i]; 585 } 586 587 inline bool sanitize (SANITIZE_ARG_DEF) { 588 TRACE_SANITIZE (); 589 return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this)); 590 } 591 inline bool sanitize (SANITIZE_ARG_DEF, unsigned int user_data) { 592 TRACE_SANITIZE (); 593 return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this), user_data); 594 } 595}; 596 597 598/* An array with a USHORT number of elements, 599 * starting at second element. */ 600template <typename Type> 601struct HeadlessArrayOf 602{ 603 const Type *const_array(void) const { return CONST_ARRAY_AFTER (Type, len); } 604 Type *array(void) { return ARRAY_AFTER (Type, len); } 605 606 inline const Type& operator [] (unsigned int i) const 607 { 608 if (HB_UNLIKELY (i >= len || !i)) return Null(Type); 609 return const_array()[i-1]; 610 } 611 inline unsigned int get_size () const 612 { return len.get_size () + (len ? len - 1 : 0) * Type::get_size (); } 613 614 inline bool sanitize (SANITIZE_ARG_DEF) { 615 TRACE_SANITIZE (); 616 if (!SANITIZE_GET_SIZE()) return false; 617 /* Note: for structs that do not reference other structs, 618 * we do not need to call their sanitize() as we already did 619 * a bound check on the aggregate array size, hence the return. 620 */ 621 return true; 622 /* We do keep this code though to make sure the structs pointed 623 * to do have a simple sanitize(), ie. they do not reference 624 * other structs. */ 625 unsigned int count = len ? len - 1 : 0; 626 Type *a = array(); 627 for (unsigned int i = 0; i < count; i++) 628 if (!SANITIZE (a[i])) 629 return false; 630 return true; 631 } 632 633 USHORT len; 634/*Type array[VAR];*/ 635}; 636 637 638#endif /* HB_OPEN_TYPE_PRIVATE_HH */ 639