hb-open-type-private.hh 19.7 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
 */

27 28
#ifndef HB_OPEN_TYPES_PRIVATE_HH
#define HB_OPEN_TYPES_PRIVATE_HH
29

30
#include "hb-private.h"
31

B
Behdad Esfahbod 已提交
32 33
#include "hb-blob.h"

B
Behdad Esfahbod 已提交
34

35
#define NO_INDEX		((unsigned int) 0xFFFF)
36

37

38 39 40 41
/*
 * Casts
 */

B
Behdad Esfahbod 已提交
42 43 44 45 46 47 48
#define CONST_CHARP(X)		(reinterpret_cast<const char *>(X))
#define DECONST_CHARP(X)	((char *)reinterpret_cast<const char *>(X))
#define CHARP(X)		(reinterpret_cast<char *>(X))

#define CONST_CAST(T,X,Ofs)	(*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + Ofs)))
#define DECONST_CAST(T,X,Ofs)	(*(reinterpret_cast<T *>((char *)CONST_CHARP(&(X)) + Ofs)))
#define CAST(T,X,Ofs) 		(*(reinterpret_cast<T *>(CHARP(&(X)) + Ofs)))
49

B
Behdad Esfahbod 已提交
50 51
#define CONST_NEXT(T,X)		(*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + (X).get_size ())))
#define NEXT(T,X)		(*(reinterpret_cast<T *>(CHARP(&(X)) + (X).get_size ())))
B
Behdad Esfahbod 已提交
52

B
Behdad Esfahbod 已提交
53 54
#define CONST_ARRAY_AFTER(T,X)	((reinterpret_cast<const T *>(CONST_CHARP(&(X)) + X.get_size ())))
#define ARRAY_AFTER(T,X)	((reinterpret_cast<T *>(CHARP(&(X)) + X.get_size ())))
B
Behdad Esfahbod 已提交
55

56 57 58 59
/*
 * Class features
 */

60 61 62 63

/* Null objects */

/* Global nul-content Null pool.  Enlarge as necessary. */
64
static const void *_NullPool[32 / sizeof (void *)];
65 66 67

/* Generic template for nul-content sizeof-sized Null objects. */
template <typename Type>
68 69 70 71
static inline const Type& Null () {
  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
  return CONST_CAST (Type, *_NullPool, 0);
}
72 73 74

/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
#define DEFINE_NULL_DATA(Type, size, data) \
75
static const char _Null##Type[size + 1] = data; \
76
template <> \
77 78
inline const Type& Null<Type> () { \
  return CONST_CAST (Type, *_Null##Type, 0); \
79 80 81
}

/* Accessor macro. */
82
#define Null(Type) Null<Type>()
83 84


85 86
/* get_for_data() is a static class method returning a reference to an
 * instance of Type located at the input data location.  It's just a
B
Behdad Esfahbod 已提交
87
 * fancy, NULL-safe, cast! */
B
Behdad Esfahbod 已提交
88
#define STATIC_DEFINE_GET_FOR_DATA(Type) \
B
Behdad Esfahbod 已提交
89 90
  static inline const Type& get_for_data (const char *data) \
  { \
91
    if (HB_UNLIKELY (data == NULL)) return Null(Type); \
B
Behdad Esfahbod 已提交
92
    return CONST_CAST (Type, *data, 0); \
93 94
  }
/* Like get_for_data(), but checks major version first. */
B
Behdad Esfahbod 已提交
95
#define STATIC_DEFINE_GET_FOR_DATA_CHECK_MAJOR_VERSION(Type, MajorMin, MajorMax) \
96 97 98
  static inline const Type& get_for_data (const char *data) \
  { \
    if (HB_UNLIKELY (data == NULL)) return Null(Type); \
B
Behdad Esfahbod 已提交
99
    const Type& t = CONST_CAST (Type, *data, 0); \
B
Behdad Esfahbod 已提交
100
    if (HB_UNLIKELY (t.version.major < MajorMin || t.version.major > MajorMax)) return Null(Type); \
101 102
    return t; \
  }
103 104


B
Behdad Esfahbod 已提交
105 106 107 108
/*
 * Sanitize
 */

109 110 111 112 113
#ifndef HB_DEBUG_SANITIZE
#define HB_DEBUG_SANITIZE HB_DEBUG
#endif

#if HB_DEBUG_SANITIZE
B
Behdad Esfahbod 已提交
114
#include <stdio.h>
B
Behdad Esfahbod 已提交
115
#define TRACE_SANITIZE_ARG_DEF	, unsigned int sanitize_depth HB_GNUC_UNUSED
116 117 118
#define TRACE_SANITIZE_ARG	, sanitize_depth + 1
#define TRACE_SANITIZE_ARG_INIT	, 1
#define TRACE_SANITIZE() \
119
	HB_STMT_START { \
120
	    if (sanitize_depth < HB_DEBUG_SANITIZE) \
121
		fprintf (stderr, "SANITIZE(%p) %-*d-> %s\n", \
B
Behdad Esfahbod 已提交
122
			 (CONST_CHARP (this) == CONST_CHARP (&NullPool)) ? 0 : this, \
B
Behdad Esfahbod 已提交
123
			 sanitize_depth, sanitize_depth, \
124
			 __PRETTY_FUNCTION__); \
125 126
	} HB_STMT_END
#else
127 128 129 130
#define TRACE_SANITIZE_ARG_DEF
#define TRACE_SANITIZE_ARG
#define TRACE_SANITIZE_ARG_INIT
#define TRACE_SANITIZE() HB_STMT_START {} HB_STMT_END
131 132
#endif

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

B
Behdad Esfahbod 已提交
140 141 142 143 144 145 146 147 148
typedef struct _hb_sanitize_context_t hb_sanitize_context_t;
struct _hb_sanitize_context_t
{
  const char *start, *end;
  int edit_count;
  hb_blob_t *blob;
};

static HB_GNUC_UNUSED void
B
Behdad Esfahbod 已提交
149 150
_hb_sanitize_init (hb_sanitize_context_t *context,
		   hb_blob_t *blob)
B
Behdad Esfahbod 已提交
151 152 153 154 155
{
  context->blob = blob;
  context->start = hb_blob_lock (blob);
  context->end = context->start + hb_blob_get_length (blob);
  context->edit_count = 0;
B
Behdad Esfahbod 已提交
156

157
#if HB_DEBUG_SANITIZE
158
  fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
B
Behdad Esfahbod 已提交
159
	   context->blob, context->start, context->end, context->end - context->start);
B
Behdad Esfahbod 已提交
160
#endif
B
Behdad Esfahbod 已提交
161 162 163
}

static HB_GNUC_UNUSED void
B
Behdad Esfahbod 已提交
164 165
_hb_sanitize_fini (hb_sanitize_context_t *context,
		   bool unlock)
B
Behdad Esfahbod 已提交
166
{
167
#if HB_DEBUG_SANITIZE
168 169
  fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
	   context->blob, context->start, context->end, context->edit_count);
B
Behdad Esfahbod 已提交
170 171
#endif

B
Behdad Esfahbod 已提交
172 173 174 175
  if (unlock)
    hb_blob_unlock (context->blob);
}

B
Behdad Esfahbod 已提交
176
static HB_GNUC_UNUSED inline bool
177 178 179 180
_hb_sanitize_check (SANITIZE_ARG_DEF,
		    const char *base,
		    unsigned int len)
{
181 182 183 184
  bool ret = context->start <= base &&
	     base <= context->end &&
	     (unsigned int) (context->end - base) >= len;

185 186
#if HB_DEBUG_SANITIZE
  if (sanitize_depth < HB_DEBUG_SANITIZE) \
187 188 189 190 191 192 193 194
    fprintf (stderr, "SANITIZE(%p) %-*d-> check [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
	     base,
	     sanitize_depth, sanitize_depth,
	     base, base+len, len,
	     context->start, context->end,
	     ret ? "pass" : "FAIL");
#endif
  return ret;
195 196
}

197 198 199 200 201 202 203 204
static HB_GNUC_UNUSED inline bool
_hb_sanitize_array (SANITIZE_ARG_DEF,
		    const char *base,
		    unsigned int record_size,
		    unsigned int len)
{
  bool overflows = len >= ((unsigned int) -1) / record_size;

205 206
#if HB_DEBUG_SANITIZE
  if (sanitize_depth < HB_DEBUG_SANITIZE) \
207 208 209 210 211 212 213 214 215 216
    fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
	     base,
	     sanitize_depth, sanitize_depth,
	     base, base + (record_size * len), record_size, len, (unsigned long) record_size * len,
	     context->start, context->end,
	     !overflows ? "does not overflow" : "OVERFLOWS FAIL");
#endif
  return HB_LIKELY (!overflows) && _hb_sanitize_check (SANITIZE_ARG, base, record_size * len);
}

217 218
static HB_GNUC_UNUSED inline bool
_hb_sanitize_edit (SANITIZE_ARG_DEF,
B
Behdad Esfahbod 已提交
219 220
		   const char *base HB_GNUC_UNUSED,
		   unsigned int len HB_GNUC_UNUSED)
B
Behdad Esfahbod 已提交
221
{
B
Behdad Esfahbod 已提交
222
  bool perm = hb_blob_try_writable_inplace (context->blob);
223
  context->edit_count++;
B
Behdad Esfahbod 已提交
224

225
#if HB_DEBUG_SANITIZE
226 227 228 229 230 231 232
  fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
	   base,
	   sanitize_depth, sanitize_depth,
	   context->edit_count,
	   base, base+len, len,
	   context->start, context->end,
	   perm ? "granted" : "REJECTED");
B
Behdad Esfahbod 已提交
233 234
#endif
  return perm;
B
Behdad Esfahbod 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
}

#define SANITIZE(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG))
#define SANITIZE2(X,Y) (SANITIZE (X) && SANITIZE (Y))

#define SANITIZE_THIS(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG, CONST_CHARP(this)))
#define SANITIZE_THIS2(X,Y) (SANITIZE_THIS (X) && SANITIZE_THIS (Y))
#define SANITIZE_THIS3(X,Y,Z) (SANITIZE_THIS (X) && SANITIZE_THIS (Y) && SANITIZE_THIS(Z))

#define SANITIZE_BASE(X,B) HB_LIKELY ((X).sanitize (SANITIZE_ARG, B))
#define SANITIZE_BASE2(X,Y,B) (SANITIZE_BASE (X,B) && SANITIZE_BASE (Y,B))

#define SANITIZE_SELF() SANITIZE_OBJ (*this)
#define SANITIZE_OBJ(X) SANITIZE_MEM(&(X), sizeof (X))
#define SANITIZE_GET_SIZE() SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ())

251
#define SANITIZE_MEM(B,L) HB_LIKELY (_hb_sanitize_check (SANITIZE_ARG, CONST_CHARP(B), (L)))
B
Behdad Esfahbod 已提交
252

253 254
#define SANITIZE_ARRAY(A,S,L) HB_LIKELY (_hb_sanitize_array (SANITIZE_ARG, CONST_CHARP(A), S, L))

B
Behdad Esfahbod 已提交
255 256
#define NEUTER(Var, Val) \
	(SANITIZE_OBJ (Var) && \
257
	 _hb_sanitize_edit (SANITIZE_ARG, CONST_CHARP(&(Var)), sizeof (Var)) && \
B
Behdad Esfahbod 已提交
258
	 ((Var).set (Val), true))
B
Behdad Esfahbod 已提交
259 260


B
Behdad Esfahbod 已提交
261 262 263 264 265 266 267 268
/* Template to sanitize an object. */
template <typename Type>
struct Sanitizer
{
  static hb_blob_t *sanitize (hb_blob_t *blob) {
    hb_sanitize_context_t context;
    bool sane;

B
Behdad Esfahbod 已提交
269
    /* TODO is_sane() stuff */
B
Behdad Esfahbod 已提交
270 271

  retry:
272
#if HB_DEBUG_SANITIZE
273
    fprintf (stderr, "Sanitizer %p start %s\n", blob, __PRETTY_FUNCTION__);
B
Behdad Esfahbod 已提交
274 275
#endif

B
Behdad Esfahbod 已提交
276 277
    _hb_sanitize_init (&context, blob);

B
Behdad Esfahbod 已提交
278
    Type *t = &CAST (Type, *DECONST_CHARP(context.start), 0);
B
Behdad Esfahbod 已提交
279

280
    sane = t->sanitize (SANITIZE_ARG_INIT);
B
Behdad Esfahbod 已提交
281 282
    if (sane) {
      if (context.edit_count) {
283
#if HB_DEBUG_SANITIZE
B
Behdad Esfahbod 已提交
284 285 286
	fprintf (stderr, "Sanitizer %p passed first round with %d edits; going a second round %s\n",
		 blob, context.edit_count, __PRETTY_FUNCTION__);
#endif
B
Behdad Esfahbod 已提交
287
        /* sanitize again to ensure no toe-stepping */
B
Behdad Esfahbod 已提交
288
        context.edit_count = 0;
289
	sane = t->sanitize (SANITIZE_ARG_INIT);
B
Behdad Esfahbod 已提交
290
	if (context.edit_count) {
291
#if HB_DEBUG_SANITIZE
292
	  fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
B
Behdad Esfahbod 已提交
293 294
		   blob, context.edit_count, __PRETTY_FUNCTION__);
#endif
B
Behdad Esfahbod 已提交
295 296 297 298 299
	  sane = false;
	}
      }
      _hb_sanitize_fini (&context, true);
    } else {
B
Behdad Esfahbod 已提交
300
      unsigned int edit_count = context.edit_count;
B
Behdad Esfahbod 已提交
301
      _hb_sanitize_fini (&context, true);
B
Behdad Esfahbod 已提交
302 303
      if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
        /* 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__);
B
Behdad Esfahbod 已提交
306
#endif
B
Behdad Esfahbod 已提交
307 308 309 310
        goto retry;
      }
    }

311
#if HB_DEBUG_SANITIZE
312
    fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", __PRETTY_FUNCTION__);
B
Behdad Esfahbod 已提交
313
#endif
B
Behdad Esfahbod 已提交
314 315 316 317 318 319 320 321
    if (sane)
      return blob;
    else {
      hb_blob_destroy (blob);
      return hb_blob_create_empty ();
    }
  }

322
  static const Type& lock_instance (hb_blob_t *blob) {
B
Behdad Esfahbod 已提交
323 324 325 326
    return Type::get_for_data (hb_blob_lock (blob));
  }
};

B
Behdad Esfahbod 已提交
327

B
Behdad Esfahbod 已提交
328 329
/*
 *
330
 * The OpenType Font File: Data Types
B
Behdad Esfahbod 已提交
331 332 333 334 335 336
 */


/* "The following data types are used in the OpenType font file.
 *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */

B
Behdad Esfahbod 已提交
337 338 339 340
/*
 * Int types
 */

341

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
template <typename Type, int Bytes> class BEInt;

template <typename Type>
class BEInt<Type, 2>
{
  public:
  inline void put (Type i) { hb_be_uint16_put (v,i); }
  inline Type get () const { return hb_be_uint16_get (v); }
  inline bool cmp (const BEInt<Type, 2> o) const { return hb_be_uint16_cmp (v, o.v); }
  private: uint8_t v[2];
};
template <typename Type>
class BEInt<Type, 4>
{
  public:
  inline void put (Type i) { hb_be_uint32_put (v,i); }
  inline Type get () const { return hb_be_uint32_get (v); }
  inline bool cmp (const BEInt<Type, 4> o) const { return hb_be_uint32_cmp (v, o.v); }
  private: uint8_t v[4];
};

template <typename Type>
struct IntType
{
  static inline unsigned int get_size () { return sizeof (Type); }
  inline void set (Type i) { v.put (i); }
  inline operator Type(void) const { return v.get (); }
  inline bool operator == (const IntType<Type> &o) const { return v.cmp (o.v); }
  inline bool sanitize (SANITIZE_ARG_DEF) {
    TRACE_SANITIZE ();
    return SANITIZE_SELF ();
  }
  private: BEInt<Type, sizeof (Type)> v;
};

typedef IntType<uint16_t> USHORT;	/* 16-bit unsigned integer. */
typedef IntType<int16_t>  SHORT;	/* 16-bit signed integer. */
typedef IntType<uint32_t> ULONG;	/* 32-bit unsigned integer. */
typedef IntType<int32_t>  LONG;		/* 32-bit signed integer. */

ASSERT_SIZE (USHORT, 2);
ASSERT_SIZE (SHORT, 2);
ASSERT_SIZE (ULONG, 4);
ASSERT_SIZE (LONG, 4);
386

387 388
/* Array of four uint8s (length = 32 bits) used to identify a script, language
 * system, feature, or baseline */
B
Behdad Esfahbod 已提交
389
struct Tag : ULONG
B
Behdad Esfahbod 已提交
390
{
B
LangSys  
Behdad Esfahbod 已提交
391
  /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
B
Behdad Esfahbod 已提交
392 393
  inline operator const char* (void) const { return CONST_CHARP(this); }
  inline operator char* (void) { return CHARP(this); }
B
Behdad Esfahbod 已提交
394 395

  inline bool sanitize (SANITIZE_ARG_DEF) {
396
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
397
    /* Note: Only accept ASCII-visible tags (mind DEL)
B
Typo  
Behdad Esfahbod 已提交
398 399
     * This is one of the few places (only place?) that we check
     * for data integrity, as opposed to just boundary checks.
B
Behdad Esfahbod 已提交
400 401 402
     */
    return SANITIZE_SELF () && (((uint32_t) *this) & 0x80808080) == 0;
  }
403
};
B
Behdad Esfahbod 已提交
404
ASSERT_SIZE (Tag, 4);
405
DEFINE_NULL_DATA (Tag, 4, "    ");
406 407

/* Glyph index number, same as uint16 (length = 16 bits) */
B
Behdad Esfahbod 已提交
408
typedef USHORT GlyphID;
409

410
/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
B
Behdad Esfahbod 已提交
411 412 413 414 415
typedef USHORT Offset;

/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
typedef ULONG LongOffset;

416 417

/* CheckSum */
B
Behdad Esfahbod 已提交
418 419 420 421
struct CheckSum : ULONG
{
  static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
  {
422
    uint32_t Sum = 0L;
B
Behdad Esfahbod 已提交
423
    ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::get_size ();
424 425 426 427 428 429

    while (Table < EndPtr)
      Sum += *Table++;
    return Sum;
  }
};
430
ASSERT_SIZE (CheckSum, 4);
431 432 433 434 435 436


/*
 * Version Numbers
 */

B
Behdad Esfahbod 已提交
437
struct FixedVersion
B
Behdad Esfahbod 已提交
438
{
B
Behdad Esfahbod 已提交
439
  inline operator uint32_t (void) const { return (major << 16) + minor; }
440

B
Behdad Esfahbod 已提交
441
  inline bool sanitize (SANITIZE_ARG_DEF) {
442
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
443 444 445
    return SANITIZE_SELF ();
  }

B
Behdad Esfahbod 已提交
446
  USHORT major;
B
Behdad Esfahbod 已提交
447
  USHORT minor;
448
};
B
Behdad Esfahbod 已提交
449
ASSERT_SIZE (FixedVersion, 4);
450

B
Behdad Esfahbod 已提交
451 452


B
Behdad Esfahbod 已提交
453
/*
B
Behdad Esfahbod 已提交
454 455
 * Template subclasses of Offset and LongOffset that do the dereferencing.
 * Use: (this+memberName)
B
Behdad Esfahbod 已提交
456 457
 */

B
Behdad Esfahbod 已提交
458 459 460
template <typename OffsetType, typename Type>
struct GenericOffsetTo : OffsetType
{
B
Behdad Esfahbod 已提交
461
  inline const Type& operator () (const void *base) const
B
Behdad Esfahbod 已提交
462 463 464
  {
    unsigned int offset = *this;
    if (HB_UNLIKELY (!offset)) return Null(Type);
B
Behdad Esfahbod 已提交
465
    return CONST_CAST(Type, *CONST_CHARP(base), offset);
B
Behdad Esfahbod 已提交
466 467
  }

B
Behdad Esfahbod 已提交
468
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
469
    TRACE_SANITIZE ();
470
    if (!SANITIZE_SELF ()) return false;
B
Behdad Esfahbod 已提交
471 472
    unsigned int offset = *this;
    if (HB_UNLIKELY (!offset)) return true;
B
Behdad Esfahbod 已提交
473
    return SANITIZE (CAST(Type, *DECONST_CHARP(base), offset)) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
B
Behdad Esfahbod 已提交
474
  }
B
Behdad Esfahbod 已提交
475
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
476
    TRACE_SANITIZE ();
477
    if (!SANITIZE_SELF ()) return false;
B
Behdad Esfahbod 已提交
478 479 480 481
    unsigned int offset = *this;
    if (HB_UNLIKELY (!offset)) return true;
    return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), base2) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
  }
B
Behdad Esfahbod 已提交
482
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
483
    TRACE_SANITIZE ();
484
    if (!SANITIZE_SELF ()) return false;
B
Behdad Esfahbod 已提交
485 486
    unsigned int offset = *this;
    if (HB_UNLIKELY (!offset)) return true;
B
Behdad Esfahbod 已提交
487
    return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), user_data) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
B
Behdad Esfahbod 已提交
488
  }
B
Behdad Esfahbod 已提交
489 490 491 492
};
template <typename Base, typename OffsetType, typename Type>
inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }

B
Behdad Esfahbod 已提交
493
template <typename Type>
B
Behdad Esfahbod 已提交
494 495 496 497
struct OffsetTo : GenericOffsetTo<Offset, Type> {};

template <typename Type>
struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
498 499


B
Behdad Esfahbod 已提交
500 501 502 503 504 505
/*
 * Array Types
 */

template <typename LenType, typename Type>
struct GenericArrayOf
B
Behdad Esfahbod 已提交
506
{
B
Behdad Esfahbod 已提交
507 508 509
  const Type *const_array(void) const { return CONST_ARRAY_AFTER (Type, len); }
  Type *array(void) { return ARRAY_AFTER (Type, len); }

B
Behdad Esfahbod 已提交
510 511 512 513 514 515 516 517 518 519 520 521
  const Type *const_sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
  {
    unsigned int count = len;
    if (HB_UNLIKELY (start_offset > count))
      count = 0;
    else
      count -= start_offset;
    count = MIN (count, *pcount);
    *pcount = count;
    return const_array() + start_offset;
  }

B
Behdad Esfahbod 已提交
522 523
  inline const Type& operator [] (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
524
    if (HB_UNLIKELY (i >= len)) return Null(Type);
B
Behdad Esfahbod 已提交
525
    return const_array()[i];
B
Behdad Esfahbod 已提交
526
  }
B
Behdad Esfahbod 已提交
527
  inline unsigned int get_size () const
B
Behdad Esfahbod 已提交
528
  { return len.get_size () + len * Type::get_size (); }
B
Behdad Esfahbod 已提交
529

B
Behdad Esfahbod 已提交
530
  inline bool sanitize (SANITIZE_ARG_DEF) {
531
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
532
    if (!SANITIZE_GET_SIZE()) return false;
B
Behdad Esfahbod 已提交
533 534 535 536
    /* Note: for structs that do not reference other structs,
     * we do not need to call their sanitize() as we already did
     * a bound check on the aggregate array size, hence the return.
     */
537
    return true;
B
Behdad Esfahbod 已提交
538 539 540
    /* We do keep this code though to make sure the structs pointed
     * to do have a simple sanitize(), ie. they do not reference
     * other structs. */
B
Behdad Esfahbod 已提交
541 542
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
543
      if (!SANITIZE (array()[i]))
B
Behdad Esfahbod 已提交
544
        return false;
B
Behdad Esfahbod 已提交
545
    return true;
B
Behdad Esfahbod 已提交
546
  }
B
Behdad Esfahbod 已提交
547
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
548
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
549
    if (!SANITIZE_GET_SIZE()) return false;
550 551
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
552
      if (!array()[i].sanitize (SANITIZE_ARG, base))
553
        return false;
B
Behdad Esfahbod 已提交
554
    return true;
555
  }
B
Behdad Esfahbod 已提交
556
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
557
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
558 559 560
    if (!SANITIZE_GET_SIZE()) return false;
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
561
      if (!array()[i].sanitize (SANITIZE_ARG, base, base2))
B
Behdad Esfahbod 已提交
562
        return false;
B
Behdad Esfahbod 已提交
563
    return true;
B
Behdad Esfahbod 已提交
564
  }
B
Behdad Esfahbod 已提交
565
  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
566
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
567 568 569
    if (!SANITIZE_GET_SIZE()) return false;
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
570
      if (!array()[i].sanitize (SANITIZE_ARG, base, user_data))
B
Behdad Esfahbod 已提交
571
        return false;
B
Behdad Esfahbod 已提交
572
    return true;
B
Behdad Esfahbod 已提交
573
  }
B
Behdad Esfahbod 已提交
574

B
Behdad Esfahbod 已提交
575
  LenType len;
B
Behdad Esfahbod 已提交
576
/*Type array[VAR];*/
B
Behdad Esfahbod 已提交
577 578
};

B
Behdad Esfahbod 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
/* An array with a USHORT number of elements. */
template <typename Type>
struct ArrayOf : GenericArrayOf<USHORT, Type> {};

/* An array with a ULONG number of elements. */
template <typename Type>
struct LongArrayOf : GenericArrayOf<ULONG, Type> {};

/* Array of Offset's */
template <typename Type>
struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};

/* Array of LongOffset's */
template <typename Type>
struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};

/* LongArray of LongOffset's */
template <typename Type>
struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};

B
Behdad Esfahbod 已提交
599 600 601 602 603 604 605
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
struct OffsetListOf : OffsetArrayOf<Type>
{
  inline const Type& operator [] (unsigned int i) const
  {
    if (HB_UNLIKELY (i >= this->len)) return Null(Type);
B
Behdad Esfahbod 已提交
606
    return this+this->const_array()[i];
B
Behdad Esfahbod 已提交
607 608 609
  }

  inline bool sanitize (SANITIZE_ARG_DEF) {
610
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
611 612 613
    return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this));
  }
  inline bool sanitize (SANITIZE_ARG_DEF, unsigned int user_data) {
614
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
615 616 617 618 619
    return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this), user_data);
  }
};


B
Behdad Esfahbod 已提交
620 621 622
/* An array with a USHORT number of elements,
 * starting at second element. */
template <typename Type>
B
Behdad Esfahbod 已提交
623 624
struct HeadlessArrayOf
{
B
Behdad Esfahbod 已提交
625 626 627
  const Type *const_array(void) const { return CONST_ARRAY_AFTER (Type, len); }
  Type *array(void) { return ARRAY_AFTER (Type, len); }

B
Behdad Esfahbod 已提交
628 629
  inline const Type& operator [] (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
630
    if (HB_UNLIKELY (i >= len || !i)) return Null(Type);
B
Behdad Esfahbod 已提交
631
    return const_array()[i-1];
B
Behdad Esfahbod 已提交
632
  }
B
Behdad Esfahbod 已提交
633
  inline unsigned int get_size () const
B
Behdad Esfahbod 已提交
634
  { return len.get_size () + (len ? len - 1 : 0) * Type::get_size (); }
B
Behdad Esfahbod 已提交
635

B
Behdad Esfahbod 已提交
636
  inline bool sanitize (SANITIZE_ARG_DEF) {
637
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
638
    if (!SANITIZE_GET_SIZE()) return false;
B
Behdad Esfahbod 已提交
639 640 641 642
    /* Note: for structs that do not reference other structs,
     * we do not need to call their sanitize() as we already did
     * a bound check on the aggregate array size, hence the return.
     */
643
    return true;
B
Behdad Esfahbod 已提交
644 645 646
    /* We do keep this code though to make sure the structs pointed
     * to do have a simple sanitize(), ie. they do not reference
     * other structs. */
B
Behdad Esfahbod 已提交
647
    unsigned int count = len ? len - 1 : 0;
B
Behdad Esfahbod 已提交
648
    Type *a = array();
B
Behdad Esfahbod 已提交
649
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
650
      if (!SANITIZE (a[i]))
B
Behdad Esfahbod 已提交
651
        return false;
B
Behdad Esfahbod 已提交
652
    return true;
B
Behdad Esfahbod 已提交
653 654
  }

B
Behdad Esfahbod 已提交
655
  USHORT len;
B
Behdad Esfahbod 已提交
656
/*Type array[VAR];*/
B
Behdad Esfahbod 已提交
657 658
};

659

B
Minor  
Behdad Esfahbod 已提交
660
#endif /* HB_OPEN_TYPE_PRIVATE_HH */