blob: a240fdb0f8134a91f9e6c310b46a67d1c839fa28 [file] [log] [blame]
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05001/*
Behdad Esfahbodf9b37722010-04-20 15:51:53 -04002 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05003 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04004 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05005 *
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 Esfahbodc85c3622010-04-21 23:12:54 -040035/* Table/script/language-system/feature/... not found */
Behdad Esfahbod706ab252008-01-28 05:58:50 -050036#define NO_INDEX ((unsigned int) 0xFFFF)
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040037
Behdad Esfahbod706ab252008-01-28 05:58:50 -050038
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040039
Behdad Esfahbod196598b2009-08-04 11:04:32 -040040/*
41 * Casts
42 */
43
Behdad Esfahbod0dfcc132010-04-21 23:41:26 -040044/* Cast to "const char *" and "char *" */
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040045template <typename Type>
46inline const char * CharP (const Type* X)
47{ return reinterpret_cast<const char *>(X); }
48template <typename Type>
49inline char * CharP (Type* X)
50{ return reinterpret_cast<char *>(X); }
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -040051
Behdad Esfahbod187454c2010-04-23 16:35:01 -040052/* Cast to struct T, reference to reference */
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040053template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040054inline const Type& CastR(const TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040055{ return reinterpret_cast<const Type&> (X); }
56template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040057inline Type& CastR(TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040058{ return reinterpret_cast<Type&> (X); }
Behdad Esfahbod196598b2009-08-04 11:04:32 -040059
Behdad Esfahbod187454c2010-04-23 16:35:01 -040060/* Cast to struct T, pointer to pointer */
61template<typename Type, typename TObject>
62inline const Type* CastP(const TObject *X)
63{ return reinterpret_cast<const Type*> (X); }
64template<typename Type, typename TObject>
65inline Type* CastP(TObject *X)
66{ return reinterpret_cast<Type*> (X); }
67
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040068/* StructAtOffset<T>(X,Ofs) returns the struct T& that is placed at memory
69 * location of X plus Ofs bytes. */
70template<typename Type, typename TObject>
71inline const Type& StructAtOffset(const TObject &X, unsigned int offset)
Behdad Esfahbodd632ec42010-04-22 18:33:12 -040072{ return * reinterpret_cast<const Type*> (CharP(&X) + offset); }
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040073template<typename Type, typename TObject>
74inline Type& StructAtOffset(TObject &X, unsigned int offset)
Behdad Esfahbodd632ec42010-04-22 18:33:12 -040075{ return * reinterpret_cast<Type*> (CharP(&X) + offset); }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040076
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -040077/* StructAfter<T>(X) returns the struct T& that is placed after X.
Behdad Esfahbod29c3f5e2010-04-21 23:01:00 -040078 * Works with X of variable size also. X must implement get_size() */
Behdad Esfahbode961c862010-04-21 15:56:11 -040079template<typename Type, typename TObject>
80inline const Type& StructAfter(const TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040081{ return StructAtOffset<Type>(X, X.get_size()); }
Behdad Esfahbode961c862010-04-21 15:56:11 -040082template<typename Type, typename TObject>
83inline Type& StructAfter(TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040084{ return StructAtOffset<Type>(X, X.get_size()); }
85
Behdad Esfahbode961c862010-04-21 15:56:11 -040086
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -050087
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040088/*
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -040089 * Null objects
Behdad Esfahbod577c1112009-08-04 19:31:02 -040090 */
91
Behdad Esfahbod577c1112009-08-04 19:31:02 -040092/* Global nul-content Null pool. Enlarge as necessary. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -040093static const void *_NullPool[32 / sizeof (void *)];
Behdad Esfahbod577c1112009-08-04 19:31:02 -040094
95/* Generic template for nul-content sizeof-sized Null objects. */
96template <typename Type>
Behdad Esfahbod9d367782010-04-21 00:32:47 -040097static inline const Type& Null () {
98 ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
Behdad Esfahbod187454c2010-04-23 16:35:01 -040099 return *CastP<Type> (_NullPool);
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400100}
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400101
102/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
103#define DEFINE_NULL_DATA(Type, size, data) \
Behdad Esfahbod565c80b2010-04-22 10:26:35 -0400104static const char _Null##Type[size + 1] = data; /* +1 is for nul-termination in data */ \
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400105template <> \
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400106inline const Type& Null<Type> () { \
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400107 return *CastP<Type> (_Null##Type); \
Behdad Esfahbod565c80b2010-04-22 10:26:35 -0400108} /* The following line really exists such that we end in a place needing semicolon */ \
109ASSERT_STATIC (sizeof (Type) + 1 <= sizeof (_Null##Type))
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400110
111/* Accessor macro. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400112#define Null(Type) Null<Type>()
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400113
114
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400115
116/*
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400117 * Sanitize
118 */
119
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400120#ifndef HB_DEBUG_SANITIZE
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400121#define HB_DEBUG_SANITIZE HB_DEBUG+0
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400122#endif
123
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400124#define TRACE_SANITIZE() \
125 HB_STMT_START { \
126 if (HB_DEBUG_SANITIZE) \
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400127 _hb_trace ("SANITIZE", HB_FUNC, this, sanitize_depth, HB_DEBUG_SANITIZE); \
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400128 } HB_STMT_END
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400129
130
Behdad Esfahbod41895502009-08-14 16:25:33 -0400131#define SANITIZE_ARG_DEF \
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400132 hb_sanitize_context_t *context, \
Behdad Esfahbod33d13fd2010-04-29 13:56:44 -0400133 unsigned int sanitize_depth HB_UNUSED
Behdad Esfahbod41895502009-08-14 16:25:33 -0400134#define SANITIZE_ARG \
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400135 context, \
136 (HB_DEBUG_SANITIZE ? sanitize_depth + 1 : 0)
Behdad Esfahbod173fde72010-04-29 01:47:30 -0400137
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400138struct hb_sanitize_context_t
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400139{
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400140 inline void init (hb_blob_t *blob)
141 {
142 this->blob = hb_blob_reference (blob);
143 this->start = hb_blob_lock (blob);
144 this->end = this->start + hb_blob_get_length (blob);
145 this->writable = hb_blob_is_writable (blob);
146 this->edit_count = 0;
147
148 if (HB_DEBUG_SANITIZE)
149 fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
150 this->blob, this->start, this->end, this->end - this->start);
151 }
152
153 inline void finish (void)
154 {
155 if (HB_DEBUG_SANITIZE)
156 fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
157 this->blob, this->start, this->end, this->edit_count);
158
159 hb_blob_unlock (this->blob);
160 hb_blob_destroy (this->blob);
161 this->blob = NULL;
162 this->start = this->end = NULL;
163 }
164
165 inline bool check (unsigned int sanitize_depth,
166 const char *base,
167 unsigned int len) const
168 {
169 bool ret = this->start <= base &&
170 base <= this->end &&
171 (unsigned int) (this->end - base) >= len;
172
173 if (HB_DEBUG_SANITIZE && (int) sanitize_depth < (int) HB_DEBUG_SANITIZE) \
174 fprintf (stderr, "SANITIZE(%p) %-*d-> check [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
175 base,
176 sanitize_depth, sanitize_depth,
177 base, base+len, len,
178 this->start, this->end,
179 ret ? "pass" : "FAIL");
180
181 return ret;
182 }
183
184 inline bool check_array (unsigned int sanitize_depth,
185 const char *base,
186 unsigned int record_size,
187 unsigned int len) const
188 {
189 bool overflows = len >= ((unsigned int) -1) / record_size;
190
191
192 if (HB_DEBUG_SANITIZE && (int) sanitize_depth < (int) HB_DEBUG_SANITIZE)
193 fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
194 base,
195 sanitize_depth, sanitize_depth,
196 base, base + (record_size * len), record_size, len, (unsigned long) record_size * len,
197 this->start, this->end,
198 !overflows ? "does not overflow" : "OVERFLOWS FAIL");
199
200 return likely (!overflows) && this->check (sanitize_depth, base, record_size * len);
201 }
202
203 inline bool can_edit (unsigned int sanitize_depth,
204 const char *base HB_UNUSED,
205 unsigned int len HB_UNUSED)
206 {
207 this->edit_count++;
208
209 if (HB_DEBUG_SANITIZE && (int) sanitize_depth < (int) HB_DEBUG_SANITIZE)
210 fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
211 base,
212 sanitize_depth, sanitize_depth,
213 this->edit_count,
214 base, base+len, len,
215 this->start, this->end,
216 this->writable ? "granted" : "REJECTED");
217
218 return this->writable;
219 }
220
221 inline const char *get_start (void) const { return start; }
222 inline const char *get_end (void) const { return end; }
223 inline bool is_writable (void) const { return writable; }
224 inline unsigned int get_edit_count (void) const { return this->edit_count; }
225
226 inline void reset_edit_count (void) { this->edit_count = 0; }
227
228 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400229 const char *start, *end;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400230 bool writable;
Behdad Esfahbod254933c2010-04-23 13:57:10 -0400231 unsigned int edit_count;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400232 hb_blob_t *blob;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400233};
234
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400235
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400236#define SANITIZE(X) likely ((X).sanitize (SANITIZE_ARG))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400237
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400238#define SANITIZE_WITH_BASE(B,X) likely ((X).sanitize (SANITIZE_ARG, CharP(B)))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400239
Behdad Esfahbod89da1342010-05-04 15:01:45 -0400240#define SANITIZE_SELF() SANITIZE_MEM(this, sizeof (*this))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400241
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400242#define SANITIZE_MEM(B,L) likely (context->check (sanitize_depth, CharP(B), (L)))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400243
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400244#define SANITIZE_ARRAY(A,S,L) likely (context->check_array (sanitize_depth, CharP(A), S, L))
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400245
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400246
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400247/* Template to sanitize an object. */
248template <typename Type>
249struct Sanitizer
250{
251 static hb_blob_t *sanitize (hb_blob_t *blob) {
Behdad Esfahbod173fde72010-04-29 01:47:30 -0400252 hb_sanitize_context_t context[1];
253 unsigned int sanitize_depth = 0;
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400254 bool sane;
255
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400256 /* TODO is_sane() stuff */
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400257
258 retry:
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400259 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400260 fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400261
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400262 context->init (blob);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400263
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400264 Type *t = CastP<Type> (const_cast<char *> (context->get_start ()));
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400265
Behdad Esfahbod173fde72010-04-29 01:47:30 -0400266 sane = t->sanitize (SANITIZE_ARG);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400267 if (sane) {
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400268 if (context->get_edit_count ()) {
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400269 if (HB_DEBUG_SANITIZE)
270 fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n",
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400271 blob, context->get_edit_count (), HB_FUNC);
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400272
Behdad Esfahbod8b534612009-08-19 18:16:50 -0400273 /* sanitize again to ensure no toe-stepping */
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400274 context->reset_edit_count ();
Behdad Esfahbod173fde72010-04-29 01:47:30 -0400275 sane = t->sanitize (SANITIZE_ARG);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400276 if (context->get_edit_count ()) {
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400277 if (HB_DEBUG_SANITIZE)
278 fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400279 blob, context->get_edit_count (), HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400280 sane = false;
281 }
282 }
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400283 context->finish ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400284 } else {
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400285 unsigned int edit_count = context->get_edit_count ();
286 context->finish ();
Behdad Esfahbod977eeb72009-08-19 16:17:24 -0400287 if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
288 /* ok, we made it writable by relocating. try again */
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400289 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400290 fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400291 goto retry;
292 }
293 }
294
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400295 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400296 fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400297 if (sane)
298 return blob;
299 else {
300 hb_blob_destroy (blob);
301 return hb_blob_create_empty ();
302 }
303 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400304};
305
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400306
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400307
308
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500309/*
310 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400311 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500312 */
313
314
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500315/* "The following data types are used in the OpenType font file.
316 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500317
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400318/*
319 * Int types
320 */
321
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400322
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400323template <typename Type, int Bytes> class BEInt;
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500324
Behdad Esfahbodf1aaa2a2010-04-23 15:19:50 -0400325/* LONGTERMTODO: On machines allowing unaligned access, we can make the
326 * following tighter by using byteswap instructions on ints directly. */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400327template <typename Type>
328class BEInt<Type, 2>
329{
330 public:
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400331 inline class BEInt<Type,2>& operator = (Type i) { hb_be_uint16_put (v,i); return *this; }
332 inline operator Type () const { return hb_be_uint16_get (v); }
333 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); }
334 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400335 private: uint8_t v[2];
336};
337template <typename Type>
338class BEInt<Type, 4>
339{
340 public:
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400341 inline class BEInt<Type,4>& operator = (Type i) { hb_be_uint32_put (v,i); return *this; }
342 inline operator Type () const { return hb_be_uint32_get (v); }
343 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_cmp (v, o.v); }
344 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400345 private: uint8_t v[4];
346};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500347
Behdad Esfahbod2467c662010-04-21 23:11:45 -0400348/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400349template <typename Type>
350struct IntType
351{
352 static inline unsigned int get_size () { return sizeof (Type); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400353 inline void set (Type i) { v = i; }
354 inline operator Type(void) const { return v; }
355 inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
356 inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400357 inline bool sanitize (SANITIZE_ARG_DEF) {
358 TRACE_SANITIZE ();
359 return SANITIZE_SELF ();
360 }
361 private: BEInt<Type, sizeof (Type)> v;
362};
363
364typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
365typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
366typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
367typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
368
369ASSERT_SIZE (USHORT, 2);
370ASSERT_SIZE (SHORT, 2);
371ASSERT_SIZE (ULONG, 4);
372ASSERT_SIZE (LONG, 4);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400373
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500374/* Array of four uint8s (length = 32 bits) used to identify a script, language
375 * system, feature, or baseline */
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400376struct Tag : ULONG
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400377{
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500378 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahbod0dfcc132010-04-21 23:41:26 -0400379 inline operator const char* (void) const { return CharP(this); }
Behdad Esfahbod198facd2010-04-21 13:35:36 -0400380 inline operator char* (void) { return CharP(this); }
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500381};
Behdad Esfahbod303fe622008-01-23 00:20:48 -0500382ASSERT_SIZE (Tag, 4);
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400383DEFINE_NULL_DATA (Tag, 4, " ");
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500384
385/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400386typedef USHORT GlyphID;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500387
Behdad Esfahbod1f437e62008-01-23 04:36:40 -0500388/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400389typedef USHORT Offset;
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400390
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400391/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
392typedef ULONG LongOffset;
393
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500394
395/* CheckSum */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400396struct CheckSum : ULONG
397{
398 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
399 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500400 uint32_t Sum = 0L;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400401 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::get_size ();
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500402
403 while (Table < EndPtr)
404 Sum += *Table++;
405 return Sum;
406 }
407};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400408ASSERT_SIZE (CheckSum, 4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500409
410
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500411/*
412 * Version Numbers
413 */
414
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400415struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400416{
Behdad Esfahbod09c292e2009-05-26 19:48:16 -0400417 inline operator uint32_t (void) const { return (major << 16) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400418
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400419 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400420 TRACE_SANITIZE ();
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400421 return SANITIZE_SELF ();
422 }
423
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400424 USHORT major;
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400425 USHORT minor;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500426};
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400427ASSERT_SIZE (FixedVersion, 4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500428
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400429
430
431/*
432 * Template subclasses of Offset and LongOffset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400433 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400434 */
435
436template <typename OffsetType, typename Type>
437struct GenericOffsetTo : OffsetType
438{
Behdad Esfahbod00e23fc2010-04-20 23:50:45 -0400439 inline const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400440 {
441 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400442 if (unlikely (!offset)) return Null(Type);
Behdad Esfahboda3263aa2010-04-22 18:29:09 -0400443 return StructAtOffset<Type> (*CharP(base), offset);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400444 }
445
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400446 inline bool sanitize (SANITIZE_ARG_DEF, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400447 TRACE_SANITIZE ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400448 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400449 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400450 if (unlikely (!offset)) return true;
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400451 Type &obj = StructAtOffset<Type> (*CharP(base), offset);
452 return likely (obj.sanitize (SANITIZE_ARG)) || neuter (SANITIZE_ARG);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400453 }
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400454 inline bool sanitize (SANITIZE_ARG_DEF, void *base, void *base2) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400455 TRACE_SANITIZE ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400456 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400457 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400458 if (unlikely (!offset)) return true;
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400459 Type &obj = StructAtOffset<Type> (*CharP(base), offset);
460 return likely (obj.sanitize (SANITIZE_ARG, base2)) || neuter (SANITIZE_ARG);
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400461 }
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400462 inline bool sanitize (SANITIZE_ARG_DEF, void *base, unsigned int user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400463 TRACE_SANITIZE ();
Behdad Esfahbod95528132009-08-14 16:17:32 -0400464 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400465 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400466 if (unlikely (!offset)) return true;
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400467 Type &obj = StructAtOffset<Type> (*CharP(base), offset);
468 return likely (obj.sanitize (SANITIZE_ARG, user_data)) || neuter (SANITIZE_ARG);
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400469 }
470
471 private:
472 /* Set the offset to Null */
473 inline bool neuter (SANITIZE_ARG_DEF) {
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400474 if (context->can_edit (sanitize_depth, CharP(this), this->get_size ())) {
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400475 this->set (0); /* 0 is Null offset */
476 return true;
477 }
478 return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400479 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400480};
481template <typename Base, typename OffsetType, typename Type>
482inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
483
484template <typename Type>
485struct OffsetTo : GenericOffsetTo<Offset, Type> {};
486
487template <typename Type>
488struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400489
490
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400491/*
492 * Array Types
493 */
494
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400495template <typename LenType, typename Type>
496struct GenericArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400497{
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400498 const Type *array(void) const { return &StructAfter<Type> (len); }
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -0400499 Type *array(void) { return &StructAfter<Type> (len); }
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500500
Behdad Esfahbod4f5f1c32010-04-22 00:27:39 -0400501 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500502 {
503 unsigned int count = len;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400504 if (unlikely (start_offset > count))
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500505 count = 0;
506 else
507 count -= start_offset;
508 count = MIN (count, *pcount);
509 *pcount = count;
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400510 return array() + start_offset;
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500511 }
512
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400513 inline const Type& operator [] (unsigned int i) const
514 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400515 if (unlikely (i >= len)) return Null(Type);
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400516 return array()[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400517 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400518 inline unsigned int get_size () const
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400519 { return len.get_size () + len * Type::get_size (); }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400520
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400521 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400522 TRACE_SANITIZE ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400523 if (!likely (sanitize_shallow (SANITIZE_ARG))) return false;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400524 /* Note: for structs that do not reference other structs,
525 * we do not need to call their sanitize() as we already did
526 * a bound check on the aggregate array size, hence the return.
527 */
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400528 return true;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400529 /* We do keep this code though to make sure the structs pointed
530 * to do have a simple sanitize(), ie. they do not reference
531 * other structs. */
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400532 unsigned int count = len;
533 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500534 if (!SANITIZE (array()[i]))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400535 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400536 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400537 }
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400538 inline bool sanitize (SANITIZE_ARG_DEF, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400539 TRACE_SANITIZE ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400540 if (!likely (sanitize_shallow (SANITIZE_ARG))) return false;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400541 unsigned int count = len;
542 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500543 if (!array()[i].sanitize (SANITIZE_ARG, base))
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400544 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400545 return true;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400546 }
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400547 inline bool sanitize (SANITIZE_ARG_DEF, void *base, void *base2) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400548 TRACE_SANITIZE ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400549 if (!likely (sanitize_shallow (SANITIZE_ARG))) return false;
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400550 unsigned int count = len;
551 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500552 if (!array()[i].sanitize (SANITIZE_ARG, base, base2))
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400553 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400554 return true;
Behdad Esfahbodb508e5c2009-08-04 15:07:24 -0400555 }
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400556 inline bool sanitize (SANITIZE_ARG_DEF, void *base, unsigned int user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400557 TRACE_SANITIZE ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400558 if (!likely (sanitize_shallow (SANITIZE_ARG))) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400559 unsigned int count = len;
560 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500561 if (!array()[i].sanitize (SANITIZE_ARG, base, user_data))
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400562 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400563 return true;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400564 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400565
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400566 private:
567 inline bool sanitize_shallow (SANITIZE_ARG_DEF) {
568 TRACE_SANITIZE ();
569 return SANITIZE_SELF() && SANITIZE_ARRAY (this, Type::get_size (), len);
570 }
571
572 public:
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400573 LenType len;
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500574/*Type array[VAR];*/
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400575};
576
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400577/* An array with a USHORT number of elements. */
578template <typename Type>
579struct ArrayOf : GenericArrayOf<USHORT, Type> {};
580
581/* An array with a ULONG number of elements. */
582template <typename Type>
583struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
584
585/* Array of Offset's */
586template <typename Type>
587struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
588
589/* Array of LongOffset's */
590template <typename Type>
591struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
592
593/* LongArray of LongOffset's */
594template <typename Type>
595struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
596
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400597/* Array of offsets relative to the beginning of the array itself. */
598template <typename Type>
599struct OffsetListOf : OffsetArrayOf<Type>
600{
601 inline const Type& operator [] (unsigned int i) const
602 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400603 if (unlikely (i >= this->len)) return Null(Type);
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400604 return this+this->array()[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400605 }
606
607 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400608 TRACE_SANITIZE ();
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400609 return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CharP(this));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400610 }
611 inline bool sanitize (SANITIZE_ARG_DEF, unsigned int user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400612 TRACE_SANITIZE ();
Behdad Esfahbod62c0fd72010-04-21 23:30:48 -0400613 return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CharP(this), user_data);
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400614 }
615};
616
617
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400618/* An array with a USHORT number of elements,
619 * starting at second element. */
620template <typename Type>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400621struct HeadlessArrayOf
622{
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400623 const Type *array(void) const { return &StructAfter<Type> (len); }
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -0400624 Type *array(void) { return &StructAfter<Type> (len); }
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500625
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400626 inline const Type& operator [] (unsigned int i) const
627 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400628 if (unlikely (i >= len || !i)) return Null(Type);
Behdad Esfahbod2cb08452010-04-21 22:37:31 -0400629 return array()[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400630 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400631 inline unsigned int get_size () const
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400632 { return len.get_size () + (len ? len - 1 : 0) * Type::get_size (); }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400633
Behdad Esfahbode5546a42010-04-22 00:45:42 -0400634 inline bool sanitize_shallow (SANITIZE_ARG_DEF) {
635 TRACE_SANITIZE ();
636 return SANITIZE_SELF() && SANITIZE_ARRAY (this, Type::get_size (), len);
637 }
638
Behdad Esfahbod20b035d2009-08-10 19:00:36 -0400639 inline bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400640 TRACE_SANITIZE ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400641 if (!likely (sanitize_shallow (SANITIZE_ARG))) return false;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400642 /* Note: for structs that do not reference other structs,
643 * we do not need to call their sanitize() as we already did
644 * a bound check on the aggregate array size, hence the return.
645 */
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400646 return true;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400647 /* We do keep this code though to make sure the structs pointed
648 * to do have a simple sanitize(), ie. they do not reference
649 * other structs. */
Behdad Esfahbod15164d92009-08-04 13:57:41 -0400650 unsigned int count = len ? len - 1 : 0;
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500651 Type *a = array();
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400652 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500653 if (!SANITIZE (a[i]))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400654 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400655 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400656 }
657
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400658 USHORT len;
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500659/*Type array[VAR];*/
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400660};
661
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500662
Behdad Esfahbod1e914342009-11-04 18:12:09 -0500663#endif /* HB_OPEN_TYPE_PRIVATE_HH */