blob: caf685756558bced55427fde600f276ecfc63a36 [file] [log] [blame]
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05001/*
Behdad Esfahbodee58aae2009-05-17 05:14:33 -04002 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05003 *
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
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040027#ifndef HB_OPEN_TYPES_PRIVATE_HH
28#define HB_OPEN_TYPES_PRIVATE_HH
Behdad Esfahbod12c45682006-12-28 06:10:59 -050029
Behdad Esfahbod2098a022009-08-02 19:57:00 -040030#include "hb-private.h"
Behdad Esfahbod12c45682006-12-28 06:10:59 -050031
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040032#include "hb-blob.h"
33
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050034
Behdad Esfahbod706ab252008-01-28 05:58:50 -050035#define NO_INDEX ((unsigned int) 0xFFFF)
Behdad Esfahbod2e8fb6c2009-05-18 04:37:37 -040036#define NO_CONTEXT ((unsigned int) 0x110000)
37#define NOT_COVERED ((unsigned int) 0x110000)
38#define MAX_NESTING_LEVEL 8
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040039
Behdad Esfahbod706ab252008-01-28 05:58:50 -050040
Behdad Esfahbod196598b2009-08-04 11:04:32 -040041/*
42 * Casts
43 */
44
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -040045#define CONST_CHARP(X) (reinterpret_cast<const char *>(X))
46#define DECONST_CHARP(X) ((char *)reinterpret_cast<const char *>(X))
47#define CHARP(X) (reinterpret_cast<char *>(X))
48
49#define CONST_CAST(T,X,Ofs) (*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + Ofs)))
50#define DECONST_CAST(T,X,Ofs) (*(reinterpret_cast<T *>((char *)CONST_CHARP(&(X)) + Ofs)))
51#define CAST(T,X,Ofs) (*(reinterpret_cast<T *>(CHARP(&(X)) + Ofs)))
Behdad Esfahbod196598b2009-08-04 11:04:32 -040052
Behdad Esfahbod284899c2009-08-09 22:10:39 -040053#define CONST_NEXT(T,X) (*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + (X).get_size ())))
54#define NEXT(T,X) (*(reinterpret_cast<T *>(CHARP(&(X)) + (X).get_size ())))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040055
56/*
Behdad Esfahbod577c1112009-08-04 19:31:02 -040057 * Class features
58 */
59
60
61/* Null objects */
62
63/* Global nul-content Null pool. Enlarge as necessary. */
64static const char NullPool[16] = "";
65
66/* Generic template for nul-content sizeof-sized Null objects. */
67template <typename Type>
68struct Null
69{
70 ASSERT_STATIC (sizeof (Type) <= sizeof (NullPool));
71 static inline const Type &get () { return *(const Type*)NullPool; }
72};
73
74/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
75#define DEFINE_NULL_DATA(Type, size, data) \
76static const char _Null##Type[size] = data; \
77template <> \
78struct Null <Type> \
79{ \
80 static inline const Type &get () { return *(const Type*)_Null##Type; } \
81}
82
83/* Accessor macro. */
84#define Null(Type) (Null<Type>::get())
85
86
87#define ASSERT_SIZE_DATA(Type, size, data) \
88 ASSERT_SIZE (Type, size); \
89 DEFINE_NULL_DATA (Type, size, data)
90
91/* get_for_data() is a static class method returning a reference to an
92 * instance of Type located at the input data location. It's just a
93 * fancy, NULL-safe, cast! */
94#define STATIC_DEFINE_GET_FOR_DATA(Type) \
95 static inline const Type& get_for_data (const char *data) \
96 { \
97 if (HB_UNLIKELY (data == NULL)) return Null(Type); \
98 return *(const Type*)data; \
99 }
100/* Like get_for_data(), but checks major version first. */
101#define STATIC_DEFINE_GET_FOR_DATA_CHECK_MAJOR_VERSION(Type, MajorMin, MajorMax) \
102 static inline const Type& get_for_data (const char *data) \
103 { \
104 if (HB_UNLIKELY (data == NULL)) return Null(Type); \
105 const Type& t = *(const Type*)data; \
106 if (HB_UNLIKELY (t.version.major < MajorMin || t.version.major > MajorMax)) return Null(Type); \
107 return t; \
108 }
109
110
111/*
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400112 * Sanitize
113 */
114
Behdad Esfahbod9b76a292009-08-06 10:27:38 -0400115#if HB_DEBUG
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400116#define SANITIZE_DEBUG_ARG_DEF , unsigned int sanitize_depth
117#define SANITIZE_DEBUG_ARG , sanitize_depth + 1
Behdad Esfahbod9b76a292009-08-06 10:27:38 -0400118#define SANITIZE_DEBUG_ARG_INIT , 1
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400119#define SANITIZE_DEBUG() \
120 HB_STMT_START { \
Behdad Esfahbod9b76a292009-08-06 10:27:38 -0400121 if (sanitize_depth < HB_DEBUG) \
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400122 fprintf (stderr, "SANITIZE(%p) %-*d-> %s\n", \
123 (CONST_CHARP (this) == NullPool) ? 0 : this, \
Behdad Esfahbod9b76a292009-08-06 10:27:38 -0400124 sanitize_depth, sanitize_depth, \
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400125 __PRETTY_FUNCTION__); \
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400126 } HB_STMT_END
127#else
128#define SANITIZE_DEBUG_ARG_DEF
129#define SANITIZE_DEBUG_ARG
130#define SANITIZE_DEBUG_ARG_INIT
131#define SANITIZE_DEBUG() HB_STMT_START {} HB_STMT_END
132#endif
133
Behdad Esfahbod41895502009-08-14 16:25:33 -0400134#define SANITIZE_ARG_DEF \
135 hb_sanitize_context_t *context SANITIZE_DEBUG_ARG_DEF
136#define SANITIZE_ARG \
137 context SANITIZE_DEBUG_ARG
138#define SANITIZE_ARG_INIT \
139 &context SANITIZE_DEBUG_ARG_INIT
140
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400141typedef struct _hb_sanitize_context_t hb_sanitize_context_t;
142struct _hb_sanitize_context_t
143{
144 const char *start, *end;
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400145 int edit_count;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400146 hb_blob_t *blob;
147};
148
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400149static HB_GNUC_UNUSED void
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400150_hb_sanitize_init (hb_sanitize_context_t *context,
151 hb_blob_t *blob)
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400152{
153 context->blob = blob;
154 context->start = hb_blob_lock (blob);
155 context->end = context->start + hb_blob_get_length (blob);
156 context->edit_count = 0;
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400157
158#if HB_DEBUG
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400159 fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
Behdad Esfahbod7f96b392009-08-08 16:37:22 -0400160 context->blob, context->start, context->end, context->end - context->start);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400161#endif
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400162}
163
164static HB_GNUC_UNUSED void
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400165_hb_sanitize_fini (hb_sanitize_context_t *context,
166 bool unlock)
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400167{
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400168#if HB_DEBUG
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400169 fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
170 context->blob, context->start, context->end, context->edit_count);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400171#endif
172
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400173 if (unlock)
174 hb_blob_unlock (context->blob);
175}
176
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400177static HB_GNUC_UNUSED inline bool
Behdad Esfahbod41895502009-08-14 16:25:33 -0400178_hb_sanitize_check (SANITIZE_ARG_DEF,
179 const char *base,
180 unsigned int len)
181{
Behdad Esfahbodae728e52009-08-14 16:41:00 -0400182 bool ret = context->start <= base &&
183 base <= context->end &&
184 (unsigned int) (context->end - base) >= len;
185
186#if HB_DEBUG
187 if (sanitize_depth < HB_DEBUG) \
188 fprintf (stderr, "SANITIZE(%p) %-*d-> check [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
189 base,
190 sanitize_depth, sanitize_depth,
191 base, base+len, len,
192 context->start, context->end,
193 ret ? "pass" : "FAIL");
194#endif
195 return ret;
Behdad Esfahbod41895502009-08-14 16:25:33 -0400196}
197
198static HB_GNUC_UNUSED inline bool
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400199_hb_sanitize_array (SANITIZE_ARG_DEF,
200 const char *base,
201 unsigned int record_size,
202 unsigned int len)
203{
204 bool overflows = len >= ((unsigned int) -1) / record_size;
205
206#if HB_DEBUG
207 if (sanitize_depth < HB_DEBUG) \
208 fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
209 base,
210 sanitize_depth, sanitize_depth,
211 base, base + (record_size * len), record_size, len, (unsigned long) record_size * len,
212 context->start, context->end,
213 !overflows ? "does not overflow" : "OVERFLOWS FAIL");
214#endif
215 return HB_LIKELY (!overflows) && _hb_sanitize_check (SANITIZE_ARG, base, record_size * len);
216}
217
218static HB_GNUC_UNUSED inline bool
Behdad Esfahbod41895502009-08-14 16:25:33 -0400219_hb_sanitize_edit (SANITIZE_ARG_DEF,
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400220 const char *base HB_GNUC_UNUSED,
221 unsigned int len HB_GNUC_UNUSED)
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400222{
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400223 bool perm = hb_blob_try_writeable_inplace (context->blob);
Behdad Esfahbodf4b58d32009-08-04 21:47:29 -0400224 context->edit_count++;
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400225
226#if HB_DEBUG
Behdad Esfahbodae728e52009-08-14 16:41:00 -0400227 fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
228 base,
229 sanitize_depth, sanitize_depth,
230 context->edit_count,
231 base, base+len, len,
232 context->start, context->end,
233 perm ? "granted" : "REJECTED");
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400234#endif
235 return perm;
Behdad Esfahbodb1e187f2009-08-04 15:28:49 -0400236}
237
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400238#define SANITIZE(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG))
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400239#define SANITIZE2(X,Y) (SANITIZE (X) && SANITIZE (Y))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400240
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400241#define SANITIZE_THIS(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG, CONST_CHARP(this)))
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400242#define SANITIZE_THIS2(X,Y) (SANITIZE_THIS (X) && SANITIZE_THIS (Y))
243#define SANITIZE_THIS3(X,Y,Z) (SANITIZE_THIS (X) && SANITIZE_THIS (Y) && SANITIZE_THIS(Z))
244
245#define SANITIZE_BASE(X,B) HB_LIKELY ((X).sanitize (SANITIZE_ARG, B))
246#define SANITIZE_BASE2(X,Y,B) (SANITIZE_BASE (X,B) && SANITIZE_BASE (Y,B))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400247
248#define SANITIZE_SELF() SANITIZE_OBJ (*this)
249#define SANITIZE_OBJ(X) SANITIZE_MEM(&(X), sizeof (X))
Behdad Esfahboddc9c4d92009-08-04 12:26:26 -0400250#define SANITIZE_GET_SIZE() SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ())
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400251
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400252/* TODO Optimize this if L is fixed (gcc magic) */
Behdad Esfahbod41895502009-08-14 16:25:33 -0400253#define SANITIZE_MEM(B,L) HB_LIKELY (_hb_sanitize_check (SANITIZE_ARG, CONST_CHARP(B), (L)))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400254
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400255#define SANITIZE_ARRAY(A,S,L) HB_LIKELY (_hb_sanitize_array (SANITIZE_ARG, CONST_CHARP(A), S, L))
256
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400257#define NEUTER(Var, Val) \
258 (SANITIZE_OBJ (Var) && \
Behdad Esfahbod41895502009-08-14 16:25:33 -0400259 _hb_sanitize_edit (SANITIZE_ARG, CONST_CHARP(&(Var)), sizeof (Var)) && \
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400260 ((Var) = (Val), true))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400261
262
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400263/* Template to sanitize an object. */
264template <typename Type>
265struct Sanitizer
266{
267 static hb_blob_t *sanitize (hb_blob_t *blob) {
268 hb_sanitize_context_t context;
269 bool sane;
270
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400271 /* TODO is_sane() stuff */
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400272
273 retry:
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400274#if HB_DEBUG
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400275 fprintf (stderr, "Sanitizer %p start %s\n", blob, __PRETTY_FUNCTION__);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400276#endif
277
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400278 _hb_sanitize_init (&context, blob);
279
Behdad Esfahbod8cd6fa22009-08-04 22:55:44 -0400280 Type *t = &CAST (Type, *DECONST_CHARP(context.start), 0);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400281
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400282 sane = t->sanitize (SANITIZE_ARG_INIT);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400283 if (sane) {
284 if (context.edit_count) {
Behdad Esfahbod0d77ab82009-08-05 15:27:42 -0400285#if HB_DEBUG
286 fprintf (stderr, "Sanitizer %p passed first round with %d edits; going a second round %s\n",
287 blob, context.edit_count, __PRETTY_FUNCTION__);
288#endif
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400289 /* sanitize again to ensure not toe-stepping */
290 context.edit_count = 0;
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400291 sane = t->sanitize (SANITIZE_ARG_INIT);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400292 if (context.edit_count) {
Behdad Esfahbod0d77ab82009-08-05 15:27:42 -0400293#if HB_DEBUG
Behdad Esfahbodae728e52009-08-14 16:41:00 -0400294 fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
Behdad Esfahbod0d77ab82009-08-05 15:27:42 -0400295 blob, context.edit_count, __PRETTY_FUNCTION__);
296#endif
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400297 sane = false;
298 }
299 }
300 _hb_sanitize_fini (&context, true);
301 } else {
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400302 unsigned int edit_count = context.edit_count;
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400303 _hb_sanitize_fini (&context, true);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400304 if (edit_count && !hb_blob_is_writeable (blob) && hb_blob_try_writeable (blob)) {
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400305 /* ok, we made it writeable by relocating. try again */
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400306#if HB_DEBUG
Behdad Esfahbod7acb3892009-08-05 15:20:34 -0400307 fprintf (stderr, "Sanitizer %p retry %s\n", blob, __PRETTY_FUNCTION__);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400308#endif
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400309 goto retry;
310 }
311 }
312
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400313#if HB_DEBUG
Behdad Esfahbodae728e52009-08-14 16:41:00 -0400314 fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", __PRETTY_FUNCTION__);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400315#endif
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400316 if (sane)
317 return blob;
318 else {
319 hb_blob_destroy (blob);
320 return hb_blob_create_empty ();
321 }
322 }
323
Behdad Esfahbodd60bb8c2009-08-04 21:32:57 -0400324 static const Type& lock_instance (hb_blob_t *blob) {
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400325 return Type::get_for_data (hb_blob_lock (blob));
326 }
327};
328
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400329
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500330/*
331 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400332 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500333 */
334
335
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500336/* "The following data types are used in the OpenType font file.
337 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500338
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400339/*
340 * Int types
341 */
342
Behdad Esfahbod9e826ea2009-08-06 18:24:55 -0400343/* TODO On machines that allow unaligned access, use this version. */
344#define _DEFINE_INT_TYPE1_UNALIGNED(NAME, TYPE, BIG_ENDIAN, BYTES) \
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400345 struct NAME \
346 { \
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400347 inline NAME& operator = (TYPE i) { (TYPE&) v = BIG_ENDIAN (i); return *this; } \
348 inline operator TYPE(void) const { return BIG_ENDIAN ((TYPE&) v); } \
349 inline bool operator== (NAME o) const { return (TYPE&) v == (TYPE&) o.v; } \
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400350 inline bool sanitize (SANITIZE_ARG_DEF) { \
351 SANITIZE_DEBUG (); \
352 return SANITIZE_SELF (); \
353 } \
Behdad Esfahbod9e826ea2009-08-06 18:24:55 -0400354 private: unsigned char v[BYTES]; \
355 }; \
356 ASSERT_SIZE (NAME, BYTES)
357
358#define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN, BYTES) \
359 struct NAME \
360 { \
361 inline NAME& operator = (TYPE i) { BIG_ENDIAN##_put_unaligned(v, i); return *this; } \
362 inline operator TYPE(void) const { return BIG_ENDIAN##_get_unaligned (v); } \
363 inline bool operator== (NAME o) const { return BIG_ENDIAN##_cmp_unaligned (v, o.v); } \
364 inline bool sanitize (SANITIZE_ARG_DEF) { \
365 SANITIZE_DEBUG (); \
366 return SANITIZE_SELF (); \
367 } \
368 private: unsigned char v[BYTES]; \
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400369 }; \
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400370 ASSERT_SIZE (NAME, BYTES)
Behdad Esfahboddf660282009-08-01 20:46:02 -0400371#define DEFINE_INT_TYPE0(NAME, type, b) DEFINE_INT_TYPE1 (NAME, type##_t, hb_be_##type, b)
372#define DEFINE_INT_TYPE(NAME, u, w) DEFINE_INT_TYPE0 (NAME, u##int##w, (w / 8))
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400373
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500374
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400375DEFINE_INT_TYPE (USHORT, u, 16); /* 16-bit unsigned integer. */
376DEFINE_INT_TYPE (SHORT, , 16); /* 16-bit signed integer. */
377DEFINE_INT_TYPE (ULONG, u, 32); /* 32-bit unsigned integer. */
378DEFINE_INT_TYPE (LONG, , 32); /* 32-bit signed integer. */
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500379
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400380
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500381/* Array of four uint8s (length = 32 bits) used to identify a script, language
382 * system, feature, or baseline */
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400383struct Tag : ULONG
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400384{
Behdad Esfahbod4497af02009-05-25 03:20:18 -0400385 inline Tag (const Tag &o) { *(ULONG*)this = (ULONG&) o; }
386 inline Tag (uint32_t i) { *(ULONG*)this = i; }
387 inline Tag (const char *c) { *(ULONG*)this = *(ULONG*)c; }
388 inline bool operator== (const char *c) const { return *(ULONG*)this == *(ULONG*)c; }
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500389 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400390 inline operator const char* (void) const { return CONST_CHARP(this); }
391 inline operator char* (void) { return CHARP(this); }
Behdad Esfahbod738c54d2009-08-04 14:42:46 -0400392
393 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400394 SANITIZE_DEBUG ();
Behdad Esfahbod738c54d2009-08-04 14:42:46 -0400395 /* Note: Only accept ASCII-visible tags (mind DEL)
396 * This is one of the few times (only time?) we check
397 * for data integrity, as opposed o just boundary checks
398 */
399 return SANITIZE_SELF () && (((uint32_t) *this) & 0x80808080) == 0;
400 }
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500401};
Behdad Esfahbod303fe622008-01-23 00:20:48 -0500402ASSERT_SIZE (Tag, 4);
Behdad Esfahbodda1097b2009-05-17 19:31:18 -0400403#define _NULL_TAG_INIT {' ', ' ', ' ', ' '}
404DEFINE_NULL_DATA (Tag, 4, _NULL_TAG_INIT);
405#undef _NULL_TAG_INIT
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500406
407/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400408typedef USHORT GlyphID;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500409
Behdad Esfahbod1f437e62008-01-23 04:36:40 -0500410/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400411typedef USHORT Offset;
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400412
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400413/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
414typedef ULONG LongOffset;
415
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500416
417/* CheckSum */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400418struct CheckSum : ULONG
419{
420 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
421 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500422 uint32_t Sum = 0L;
Behdad Esfahbod01e4fcb2006-12-21 22:31:31 -0500423 ULONG *EndPtr = Table+((Length+3) & ~3) / sizeof(ULONG);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500424
425 while (Table < EndPtr)
426 Sum += *Table++;
427 return Sum;
428 }
429};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400430ASSERT_SIZE (CheckSum, 4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500431
432
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500433/*
434 * Version Numbers
435 */
436
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400437struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400438{
Behdad Esfahbod09c292e2009-05-26 19:48:16 -0400439 inline operator uint32_t (void) const { return (major << 16) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400440
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400441 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400442 SANITIZE_DEBUG ();
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400443 return SANITIZE_SELF ();
444 }
445
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400446 USHORT major;
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400447 USHORT minor;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500448};
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400449ASSERT_SIZE (FixedVersion, 4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500450
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400451
452
453/*
454 * Template subclasses of Offset and LongOffset that do the dereferencing.
455 * Use: (this+memberName)
456 */
457
458template <typename OffsetType, typename Type>
459struct GenericOffsetTo : OffsetType
460{
461 inline const Type& operator() (const void *base) const
462 {
463 unsigned int offset = *this;
464 if (HB_UNLIKELY (!offset)) return Null(Type);
Behdad Esfahbod95639fc2009-08-04 12:05:24 -0400465 return CONST_CAST(Type, *CONST_CHARP(base), offset);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400466 }
467
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400468 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400469 SANITIZE_DEBUG ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400470 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400471 unsigned int offset = *this;
472 if (HB_UNLIKELY (!offset)) return true;
Behdad Esfahbodac26e2a2009-08-04 14:10:39 -0400473 return SANITIZE (CAST(Type, *DECONST_CHARP(base), offset)) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400474 }
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400475 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400476 SANITIZE_DEBUG ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400477 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400478 unsigned int offset = *this;
479 if (HB_UNLIKELY (!offset)) return true;
480 return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), base2) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
481 }
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400482 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400483 SANITIZE_DEBUG ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400484 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400485 unsigned int offset = *this;
486 if (HB_UNLIKELY (!offset)) return true;
Behdad Esfahbodac26e2a2009-08-04 14:10:39 -0400487 return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), user_data) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400488 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400489};
490template <typename Base, typename OffsetType, typename Type>
491inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
492
493template <typename Type>
494struct OffsetTo : GenericOffsetTo<Offset, Type> {};
495
496template <typename Type>
497struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400498
499
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400500/*
501 * Array Types
502 */
503
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400504template <typename LenType, typename Type>
505struct GenericArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400506{
507 inline const Type& operator [] (unsigned int i) const
508 {
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400509 if (HB_UNLIKELY (i >= len)) return Null(Type);
510 return array[i];
511 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400512 inline unsigned int get_size () const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400513 { return sizeof (len) + len * sizeof (array[0]); }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400514
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400515 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400516 SANITIZE_DEBUG ();
Behdad Esfahboddc9c4d92009-08-04 12:26:26 -0400517 if (!SANITIZE_GET_SIZE()) return false;
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400518 /* Note:
519 * for non-recursive types, this is not much needed.
520 * But we keep the code to make sure the objects pointed to
521 * do have a simple sanitize(). */
522 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400523 unsigned int count = len;
524 for (unsigned int i = 0; i < count; i++)
525 if (!SANITIZE (array[i]))
526 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400527 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400528 }
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400529 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400530 SANITIZE_DEBUG ();
Behdad Esfahboddc9c4d92009-08-04 12:26:26 -0400531 if (!SANITIZE_GET_SIZE()) return false;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400532 unsigned int count = len;
533 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod95639fc2009-08-04 12:05:24 -0400534 if (!array[i].sanitize (SANITIZE_ARG, base))
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400535 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400536 return true;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400537 }
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400538 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400539 SANITIZE_DEBUG ();
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400540 if (!SANITIZE_GET_SIZE()) return false;
541 unsigned int count = len;
542 for (unsigned int i = 0; i < count; i++)
543 if (!array[i].sanitize (SANITIZE_ARG, base, base2))
544 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400545 return true;
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400546 }
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400547 inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400548 SANITIZE_DEBUG ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400549 if (!SANITIZE_GET_SIZE()) return false;
550 unsigned int count = len;
551 for (unsigned int i = 0; i < count; i++)
552 if (!array[i].sanitize (SANITIZE_ARG, base, user_data))
553 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400554 return true;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400555 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400556
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400557 LenType len;
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400558 Type array[];
559};
560
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400561/* An array with a USHORT number of elements. */
562template <typename Type>
563struct ArrayOf : GenericArrayOf<USHORT, Type> {};
564
565/* An array with a ULONG number of elements. */
566template <typename Type>
567struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
568
569/* Array of Offset's */
570template <typename Type>
571struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
572
573/* Array of LongOffset's */
574template <typename Type>
575struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
576
577/* LongArray of LongOffset's */
578template <typename Type>
579struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
580
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400581/* An array with a USHORT number of elements,
582 * starting at second element. */
583template <typename Type>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400584struct HeadlessArrayOf
585{
586 inline const Type& operator [] (unsigned int i) const
587 {
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400588 if (HB_UNLIKELY (i >= len || !i)) return Null(Type);
589 return array[i-1];
590 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400591 inline unsigned int get_size () const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400592 { return sizeof (len) + (len ? len - 1 : 0) * sizeof (array[0]); }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400593
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400594 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbodb28815c2009-08-04 22:35:36 -0400595 SANITIZE_DEBUG ();
Behdad Esfahboddc9c4d92009-08-04 12:26:26 -0400596 if (!SANITIZE_GET_SIZE()) return false;
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400597 /* Note:
598 * for non-recursive types, this is not much needed.
599 * But we keep the code to make sure the objects pointed to
600 * do have a simple sanitize(). */
601 return true;
Behdad Esfahbod15164d92009-08-04 13:57:41 -0400602 unsigned int count = len ? len - 1 : 0;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400603 for (unsigned int i = 0; i < count; i++)
604 if (!SANITIZE (array[i]))
605 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400606 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400607 }
608
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400609 USHORT len;
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400610 Type array[];
611};
612
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500613
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -0400614#endif /* HB_OPEN_TYPES_PRIVATE_HH */