blob: 107b2d18bb6d5eefbee5dc01cd25706885b4467b [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 Esfahbod187454c2010-04-23 16:35:01 -040044/* Cast to struct T, reference to reference */
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040045template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040046inline const Type& CastR(const TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040047{ return reinterpret_cast<const Type&> (X); }
48template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040049inline Type& CastR(TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040050{ return reinterpret_cast<Type&> (X); }
Behdad Esfahbod196598b2009-08-04 11:04:32 -040051
Behdad Esfahbod187454c2010-04-23 16:35:01 -040052/* Cast to struct T, pointer to pointer */
53template<typename Type, typename TObject>
54inline const Type* CastP(const TObject *X)
55{ return reinterpret_cast<const Type*> (X); }
56template<typename Type, typename TObject>
57inline Type* CastP(TObject *X)
58{ return reinterpret_cast<Type*> (X); }
59
Behdad Esfahbod09766b12010-05-10 17:36:03 -040060/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
61 * location pointed to by P plus Ofs bytes. */
62template<typename Type>
63inline const Type& StructAtOffset(const void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040064{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
Behdad Esfahbod09766b12010-05-10 17:36:03 -040065template<typename Type>
66inline Type& StructAtOffset(void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040067{ return * reinterpret_cast<Type*> ((char *) P + offset); }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040068
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -040069/* StructAfter<T>(X) returns the struct T& that is placed after X.
Behdad Esfahbod29c3f5e2010-04-21 23:01:00 -040070 * Works with X of variable size also. X must implement get_size() */
Behdad Esfahbode961c862010-04-21 15:56:11 -040071template<typename Type, typename TObject>
72inline const Type& StructAfter(const TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040073{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahbode961c862010-04-21 15:56:11 -040074template<typename Type, typename TObject>
75inline Type& StructAfter(TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040076{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040077
Behdad Esfahbode961c862010-04-21 15:56:11 -040078
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -050079
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040080/*
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040081 * Size checking
82 */
83
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -040084#define ASSERT_SIZE(_thing, _size) ASSERT_STATIC (sizeof (_thing) == (_size))
85
86#define _DEFINE_SIZE_ASSERTION(_size) \
87 inline void _size_assertion (void) const { ASSERT_SIZE (*this, _size); }
88
89
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040090#define DEFINE_SIZE_STATIC(size) \
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -040091 _DEFINE_SIZE_ASSERTION (size); \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040092 static const unsigned int static_size = (size); \
93 static const unsigned int min_size = (size)
94
Behdad Esfahbodb3651232010-05-10 16:57:29 -040095/* Size signifying variable-sized array */
96#define VAR 1
97#define VAR0 (VAR+0)
98
Behdad Esfahbodbea34c72010-05-10 17:28:16 -040099#define DEFINE_SIZE_MIN(size) \
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400100 static const unsigned int min_size = (size)
101
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400102#define DEFINE_SIZE_VAR(size, _var_type) \
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -0400103 _DEFINE_SIZE_ASSERTION ((size) + VAR0 * sizeof (_var_type)); \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400104 static const unsigned int min_size = (size)
105
Behdad Esfahbod569da922010-05-10 16:38:32 -0400106#define DEFINE_SIZE_VAR2(size, _var_type1, _var_type2) \
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -0400107 _DEFINE_SIZE_ASSERTION ((size) + VAR0 * sizeof (_var_type1) + VAR0 * sizeof (_var_type2)); \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400108 static const unsigned int min_size = (size)
109
110
111
112/*
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400113 * Null objects
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400114 */
115
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400116/* Global nul-content Null pool. Enlarge as necessary. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400117static const void *_NullPool[32 / sizeof (void *)];
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400118
119/* Generic template for nul-content sizeof-sized Null objects. */
120template <typename Type>
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400121static inline const Type& Null () {
Behdad Esfahboded074222010-05-10 18:08:46 -0400122 ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400123 return *CastP<Type> (_NullPool);
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400124}
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400125
126/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400127#define DEFINE_NULL_DATA(Type, data) \
128static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400129template <> \
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400130inline const Type& Null<Type> () { \
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400131 return *CastP<Type> (_Null##Type); \
Behdad Esfahbod565c80b2010-04-22 10:26:35 -0400132} /* The following line really exists such that we end in a place needing semicolon */ \
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400133ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400134
135/* Accessor macro. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400136#define Null(Type) Null<Type>()
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400137
138
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400139/*
Behdad Esfahboddfc8cbe2010-05-05 00:19:46 -0400140 * Trace
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400141 */
142
Behdad Esfahboddfc8cbe2010-05-05 00:19:46 -0400143
144template <int max_depth>
145struct hb_trace_t {
146 explicit hb_trace_t (unsigned int *pdepth) : pdepth(pdepth) { if (max_depth) ++*pdepth; }
147 ~hb_trace_t (void) { if (max_depth) --*pdepth; }
148
149 inline void log (const char *what, const char *function, const void *obj)
150 {
151 if (*pdepth < max_depth)
152 fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function);
153 }
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400154
155 private:
Behdad Esfahboddfc8cbe2010-05-05 00:19:46 -0400156 unsigned int *pdepth;
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400157};
Behdad Esfahboddfc8cbe2010-05-05 00:19:46 -0400158template <> /* Optimize when tracing is disabled */
159struct hb_trace_t<0> {
160 explicit hb_trace_t (unsigned int *p) {}
161 inline void log (const char *what, const char *function, const void *obj) {};
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400162};
163
164
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400165
166/*
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400167 * Sanitize
168 */
169
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400170#ifndef HB_DEBUG_SANITIZE
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400171#define HB_DEBUG_SANITIZE HB_DEBUG+0
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400172#endif
173
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400174
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400175#define TRACE_SANITIZE() \
Behdad Esfahboddfc8cbe2010-05-05 00:19:46 -0400176 hb_trace_t<HB_DEBUG_SANITIZE> trace (&context->debug_depth); \
177 trace.log ("SANITIZE", HB_FUNC, this);
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400178
179
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400180struct hb_sanitize_context_t
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400181{
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400182 inline void init (hb_blob_t *blob)
183 {
184 this->blob = hb_blob_reference (blob);
185 this->start = hb_blob_lock (blob);
186 this->end = this->start + hb_blob_get_length (blob);
187 this->writable = hb_blob_is_writable (blob);
188 this->edit_count = 0;
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400189 this->debug_depth = 0;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400190
191 if (HB_DEBUG_SANITIZE)
192 fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
193 this->blob, this->start, this->end, this->end - this->start);
194 }
195
196 inline void finish (void)
197 {
198 if (HB_DEBUG_SANITIZE)
199 fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
200 this->blob, this->start, this->end, this->edit_count);
201
202 hb_blob_unlock (this->blob);
203 hb_blob_destroy (this->blob);
204 this->blob = NULL;
205 this->start = this->end = NULL;
206 }
207
Behdad Esfahbod4ad2cc52010-05-06 09:24:24 -0400208 inline bool check_range (const void *base, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400209 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400210 const char *p = (const char *) base;
211 bool ret = this->start <= p &&
212 p <= this->end &&
213 (unsigned int) (this->end - p) >= len;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400214
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400215 if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE) \
Behdad Esfahbod4ad2cc52010-05-06 09:24:24 -0400216 fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400217 p,
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400218 this->debug_depth, this->debug_depth,
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400219 p, p + len, len,
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400220 this->start, this->end,
221 ret ? "pass" : "FAIL");
222
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400223 return likely (ret);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400224 }
225
Behdad Esfahbod1cd1e112010-05-05 20:15:14 -0400226 inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400227 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400228 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400229 bool overflows = len >= ((unsigned int) -1) / record_size;
230
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400231 if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400232 fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400233 p,
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400234 this->debug_depth, this->debug_depth,
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400235 p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400236 this->start, this->end,
237 !overflows ? "does not overflow" : "OVERFLOWS FAIL");
238
Behdad Esfahbod4ad2cc52010-05-06 09:24:24 -0400239 return likely (!overflows && this->check_range (base, record_size * len));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400240 }
241
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400242 template <typename Type>
243 inline bool check_struct (const Type *obj) const
244 {
Behdad Esfahbod54842372010-05-10 18:13:32 -0400245 return likely (this->check_range (obj, obj->min_size));
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400246 }
247
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400248 inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400249 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400250 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400251 this->edit_count++;
252
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400253 if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400254 fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400255 p,
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400256 this->debug_depth, this->debug_depth,
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400257 this->edit_count,
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400258 p, p + len, len,
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400259 this->start, this->end,
260 this->writable ? "granted" : "REJECTED");
261
262 return this->writable;
263 }
264
Behdad Esfahbod705e2152010-05-05 01:40:25 -0400265 unsigned int debug_depth;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400266 const char *start, *end;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400267 bool writable;
Behdad Esfahbod254933c2010-04-23 13:57:10 -0400268 unsigned int edit_count;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400269 hb_blob_t *blob;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400270};
271
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400272
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400273
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400274/* Template to sanitize an object. */
275template <typename Type>
276struct Sanitizer
277{
278 static hb_blob_t *sanitize (hb_blob_t *blob) {
Behdad Esfahbod705e2152010-05-05 01:40:25 -0400279 hb_sanitize_context_t context[1] = {{0}};
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400280 bool sane;
281
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400282 /* TODO is_sane() stuff */
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400283
284 retry:
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400285 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400286 fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400287
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400288 context->init (blob);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400289
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400290 Type *t = CastP<Type> (const_cast<char *> (context->start));
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400291
Behdad Esfahbod39840472010-05-05 00:23:19 -0400292 sane = t->sanitize (context);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400293 if (sane) {
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400294 if (context->edit_count) {
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400295 if (HB_DEBUG_SANITIZE)
296 fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n",
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400297 blob, context->edit_count, HB_FUNC);
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400298
Behdad Esfahbod8b534612009-08-19 18:16:50 -0400299 /* sanitize again to ensure no toe-stepping */
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400300 context->edit_count = 0;
Behdad Esfahbod39840472010-05-05 00:23:19 -0400301 sane = t->sanitize (context);
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400302 if (context->edit_count) {
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400303 if (HB_DEBUG_SANITIZE)
304 fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400305 blob, context->edit_count, HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400306 sane = false;
307 }
308 }
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400309 context->finish ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400310 } else {
Behdad Esfahbod27e302d2010-05-05 00:26:16 -0400311 unsigned int edit_count = context->edit_count;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400312 context->finish ();
Behdad Esfahbod977eeb72009-08-19 16:17:24 -0400313 if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
314 /* ok, we made it writable by relocating. try again */
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400315 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400316 fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400317 goto retry;
318 }
319 }
320
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400321 if (HB_DEBUG_SANITIZE)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400322 fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400323 if (sane)
324 return blob;
325 else {
326 hb_blob_destroy (blob);
327 return hb_blob_create_empty ();
328 }
329 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400330};
331
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400332
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400333
334
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500335/*
336 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400337 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500338 */
339
340
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500341/* "The following data types are used in the OpenType font file.
342 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500343
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400344/*
345 * Int types
346 */
347
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400348
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400349template <typename Type, int Bytes> class BEInt;
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500350
Behdad Esfahbodf1aaa2a2010-04-23 15:19:50 -0400351/* LONGTERMTODO: On machines allowing unaligned access, we can make the
352 * following tighter by using byteswap instructions on ints directly. */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400353template <typename Type>
354class BEInt<Type, 2>
355{
356 public:
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400357 inline class BEInt<Type,2>& operator = (Type i) { hb_be_uint16_put (v,i); return *this; }
358 inline operator Type () const { return hb_be_uint16_get (v); }
359 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); }
360 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400361 private: uint8_t v[2];
362};
363template <typename Type>
364class BEInt<Type, 4>
365{
366 public:
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400367 inline class BEInt<Type,4>& operator = (Type i) { hb_be_uint32_put (v,i); return *this; }
368 inline operator Type () const { return hb_be_uint32_get (v); }
369 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_cmp (v, o.v); }
370 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400371 private: uint8_t v[4];
372};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500373
Behdad Esfahbod2467c662010-04-21 23:11:45 -0400374/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400375template <typename Type>
376struct IntType
377{
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400378 inline void set (Type i) { v = i; }
379 inline operator Type(void) const { return v; }
380 inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
381 inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
Behdad Esfahbod39840472010-05-05 00:23:19 -0400382 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400383 TRACE_SANITIZE ();
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400384 return context->check_struct (this);
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400385 }
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400386 protected:
Behdad Esfahbod569da922010-05-10 16:38:32 -0400387 BEInt<Type, sizeof (Type)> v;
388 public:
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400389 DEFINE_SIZE_STATIC (sizeof (Type));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400390};
391
392typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
393typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
394typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
395typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
396
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500397/* Array of four uint8s (length = 32 bits) used to identify a script, language
398 * system, feature, or baseline */
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400399struct Tag : ULONG
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400400{
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500401 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400402 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
403 inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400404 public:
405 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500406};
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400407DEFINE_NULL_DATA (Tag, " ");
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500408
409/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400410typedef USHORT GlyphID;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500411
Behdad Esfahbod1f437e62008-01-23 04:36:40 -0500412/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400413typedef USHORT Offset;
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400414
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400415/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
416typedef ULONG LongOffset;
417
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500418
419/* CheckSum */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400420struct CheckSum : ULONG
421{
422 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
423 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500424 uint32_t Sum = 0L;
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400425 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500426
427 while (Table < EndPtr)
428 Sum += *Table++;
429 return Sum;
430 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400431 public:
432 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500433};
434
435
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500436/*
437 * Version Numbers
438 */
439
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400440struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400441{
Behdad Esfahbod09c292e2009-05-26 19:48:16 -0400442 inline operator uint32_t (void) const { return (major << 16) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400443
Behdad Esfahbod39840472010-05-05 00:23:19 -0400444 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400445 TRACE_SANITIZE ();
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400446 return context->check_struct (this);
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400447 }
448
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400449 USHORT major;
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400450 USHORT minor;
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400451 public:
452 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500453};
454
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400455
456
457/*
458 * Template subclasses of Offset and LongOffset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400459 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400460 */
461
462template <typename OffsetType, typename Type>
463struct GenericOffsetTo : OffsetType
464{
Behdad Esfahbod00e23fc2010-04-20 23:50:45 -0400465 inline const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400466 {
467 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400468 if (unlikely (!offset)) return Null(Type);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400469 return StructAtOffset<Type> (base, offset);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400470 }
471
Behdad Esfahbod39840472010-05-05 00:23:19 -0400472 inline bool sanitize (hb_sanitize_context_t *context, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400473 TRACE_SANITIZE ();
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400474 if (!context->check_struct (this)) return false;
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400475 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400476 if (unlikely (!offset)) return true;
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400477 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod39840472010-05-05 00:23:19 -0400478 return likely (obj.sanitize (context)) || neuter (context);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400479 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400480 template <typename T>
Behdad Esfahbod39840472010-05-05 00:23:19 -0400481 inline bool sanitize (hb_sanitize_context_t *context, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400482 TRACE_SANITIZE ();
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400483 if (!context->check_struct (this)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400484 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400485 if (unlikely (!offset)) return true;
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400486 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod39840472010-05-05 00:23:19 -0400487 return likely (obj.sanitize (context, user_data)) || neuter (context);
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400488 }
489
490 private:
491 /* Set the offset to Null */
Behdad Esfahbod39840472010-05-05 00:23:19 -0400492 inline bool neuter (hb_sanitize_context_t *context) {
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400493 if (context->can_edit (this, this->static_size)) {
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400494 this->set (0); /* 0 is Null offset */
495 return true;
496 }
497 return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400498 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400499};
500template <typename Base, typename OffsetType, typename Type>
501inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
502
503template <typename Type>
504struct OffsetTo : GenericOffsetTo<Offset, Type> {};
505
506template <typename Type>
507struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400508
509
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400510/*
511 * Array Types
512 */
513
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400514template <typename LenType, typename Type>
515struct GenericArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400516{
Behdad Esfahbod4f5f1c32010-04-22 00:27:39 -0400517 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500518 {
519 unsigned int count = len;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400520 if (unlikely (start_offset > count))
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500521 count = 0;
522 else
523 count -= start_offset;
524 count = MIN (count, *pcount);
525 *pcount = count;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400526 return array + start_offset;
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500527 }
528
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400529 inline const Type& operator [] (unsigned int i) const
530 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400531 if (unlikely (i >= len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400532 return array[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400533 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400534 inline unsigned int get_size () const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400535 { return len.static_size + len * Type::static_size; }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400536
Behdad Esfahbod39840472010-05-05 00:23:19 -0400537 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400538 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -0400539 if (!likely (sanitize_shallow (context))) return false;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400540 /* Note: for structs that do not reference other structs,
541 * we do not need to call their sanitize() as we already did
542 * a bound check on the aggregate array size, hence the return.
543 */
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400544 return true;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400545 /* We do keep this code though to make sure the structs pointed
546 * to do have a simple sanitize(), ie. they do not reference
547 * other structs. */
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400548 unsigned int count = len;
549 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400550 if (array[i].sanitize (context))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400551 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400552 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400553 }
Behdad Esfahbod39840472010-05-05 00:23:19 -0400554 inline bool sanitize (hb_sanitize_context_t *context, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400555 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -0400556 if (!likely (sanitize_shallow (context))) return false;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400557 unsigned int count = len;
558 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400559 if (!array[i].sanitize (context, base))
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400560 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400561 return true;
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400562 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400563 template <typename T>
Behdad Esfahbod39840472010-05-05 00:23:19 -0400564 inline bool sanitize (hb_sanitize_context_t *context, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400565 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -0400566 if (!likely (sanitize_shallow (context))) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400567 unsigned int count = len;
568 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400569 if (!array[i].sanitize (context, base, user_data))
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400570 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400571 return true;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400572 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400573
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400574 private:
Behdad Esfahbod39840472010-05-05 00:23:19 -0400575 inline bool sanitize_shallow (hb_sanitize_context_t *context) {
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400576 TRACE_SANITIZE ();
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400577 return context->check_struct (this)
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400578 && context->check_array (this, Type::static_size, len);
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400579 }
580
581 public:
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400582 LenType len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400583 Type array[VAR];
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400584 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400585 DEFINE_SIZE_VAR (sizeof (LenType), Type);
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400586};
587
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400588/* An array with a USHORT number of elements. */
589template <typename Type>
590struct ArrayOf : GenericArrayOf<USHORT, Type> {};
591
592/* An array with a ULONG number of elements. */
593template <typename Type>
594struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
595
596/* Array of Offset's */
597template <typename Type>
598struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
599
600/* Array of LongOffset's */
601template <typename Type>
602struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
603
604/* LongArray of LongOffset's */
605template <typename Type>
606struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
607
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400608/* Array of offsets relative to the beginning of the array itself. */
609template <typename Type>
610struct OffsetListOf : OffsetArrayOf<Type>
611{
612 inline const Type& operator [] (unsigned int i) const
613 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400614 if (unlikely (i >= this->len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400615 return this+this->array[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400616 }
617
Behdad Esfahbod39840472010-05-05 00:23:19 -0400618 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400619 TRACE_SANITIZE ();
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400620 return OffsetArrayOf<Type>::sanitize (context, this);
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400621 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400622 template <typename T>
Behdad Esfahbod39840472010-05-05 00:23:19 -0400623 inline bool sanitize (hb_sanitize_context_t *context, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400624 TRACE_SANITIZE ();
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400625 return OffsetArrayOf<Type>::sanitize (context, this, user_data);
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400626 }
627};
628
629
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400630/* An array with a USHORT number of elements,
631 * starting at second element. */
632template <typename Type>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400633struct HeadlessArrayOf
634{
635 inline const Type& operator [] (unsigned int i) const
636 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400637 if (unlikely (i >= len || !i)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400638 return array[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400639 }
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400640 inline unsigned int get_size () const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400641 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400642
Behdad Esfahbod39840472010-05-05 00:23:19 -0400643 inline bool sanitize_shallow (hb_sanitize_context_t *context) {
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400644 return context->check_struct (this)
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400645 && context->check_array (this, Type::static_size, len);
Behdad Esfahbode5546a42010-04-22 00:45:42 -0400646 }
647
Behdad Esfahbod39840472010-05-05 00:23:19 -0400648 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400649 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -0400650 if (!likely (sanitize_shallow (context))) return false;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400651 /* Note: for structs that do not reference other structs,
652 * we do not need to call their sanitize() as we already did
653 * a bound check on the aggregate array size, hence the return.
654 */
Behdad Esfahbod3564ee52009-08-14 18:32:56 -0400655 return true;
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400656 /* We do keep this code though to make sure the structs pointed
657 * to do have a simple sanitize(), ie. they do not reference
658 * other structs. */
Behdad Esfahbod15164d92009-08-04 13:57:41 -0400659 unsigned int count = len ? len - 1 : 0;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400660 Type *a = array;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400661 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4f252fe2010-05-06 13:30:23 -0400662 if (!a[i].sanitize (context))
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400663 return false;
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400664 return true;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400665 }
666
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400667 USHORT len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400668 Type array[VAR];
Behdad Esfahboded074222010-05-10 18:08:46 -0400669 public:
670 DEFINE_SIZE_VAR (sizeof (USHORT), Type);
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400671};
672
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500673
Behdad Esfahbod1e914342009-11-04 18:12:09 -0500674#endif /* HB_OPEN_TYPE_PRIVATE_HH */