OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. | 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. |
| 3 * Copyright © 2012 Google, Inc. |
3 * | 4 * |
4 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
5 * | 6 * |
6 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
7 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
8 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
9 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
10 * all copies of this software. | 11 * all copies of this software. |
11 * | 12 * |
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 15 * 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 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 * DAMAGE. | 17 * DAMAGE. |
17 * | 18 * |
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | 21 * 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 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 * | 24 * |
24 * Red Hat Author(s): Behdad Esfahbod | 25 * Red Hat Author(s): Behdad Esfahbod |
| 26 * Google Author(s): Behdad Esfahbod |
25 */ | 27 */ |
26 | 28 |
27 #ifndef HB_OPEN_TYPE_PRIVATE_HH | 29 #ifndef HB_OPEN_TYPE_PRIVATE_HH |
28 #define HB_OPEN_TYPE_PRIVATE_HH | 30 #define HB_OPEN_TYPE_PRIVATE_HH |
29 | 31 |
30 #include "hb-private.hh" | 32 #include "hb-private.hh" |
31 | 33 |
32 #include "hb-blob.h" | 34 #include "hb-blob.h" |
33 | 35 |
34 | 36 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 /* | 148 /* |
147 * Sanitize | 149 * Sanitize |
148 */ | 150 */ |
149 | 151 |
150 #ifndef HB_DEBUG_SANITIZE | 152 #ifndef HB_DEBUG_SANITIZE |
151 #define HB_DEBUG_SANITIZE (HB_DEBUG+0) | 153 #define HB_DEBUG_SANITIZE (HB_DEBUG+0) |
152 #endif | 154 #endif |
153 | 155 |
154 | 156 |
155 #define TRACE_SANITIZE() \ | 157 #define TRACE_SANITIZE() \ |
156 » hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", t
his, NULL, HB_FUNC); | 158 » hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", t
his, HB_FUNC, ""); |
157 | 159 |
158 | 160 |
159 struct hb_sanitize_context_t | 161 struct hb_sanitize_context_t |
160 { | 162 { |
161 inline void init (hb_blob_t *b) | 163 inline void init (hb_blob_t *b) |
162 { | 164 { |
163 this->blob = hb_blob_reference (b); | 165 this->blob = hb_blob_reference (b); |
164 this->writable = false; | 166 this->writable = false; |
165 } | 167 } |
166 | 168 |
167 inline void setup (void) | 169 inline void start_processing (void) |
168 { | 170 { |
169 this->start = hb_blob_get_data (this->blob, NULL); | 171 this->start = hb_blob_get_data (this->blob, NULL); |
170 this->end = this->start + hb_blob_get_length (this->blob); | 172 this->end = this->start + hb_blob_get_length (this->blob); |
171 this->edit_count = 0; | 173 this->edit_count = 0; |
172 this->debug_depth = 0; | 174 this->debug_depth = 0; |
173 | 175 |
174 DEBUG_MSG (SANITIZE, this->blob, | 176 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1, |
175 » "init [%p..%p] (%lu bytes)", | 177 » » "start [%p..%p] (%lu bytes)", |
176 » this->start, this->end, | 178 » » this->start, this->end, |
177 » (unsigned long) (this->end - this->start)); | 179 » » (unsigned long) (this->end - this->start)); |
178 } | 180 } |
179 | 181 |
180 inline void finish (void) | 182 inline void end_processing (void) |
181 { | 183 { |
182 DEBUG_MSG (SANITIZE, this->blob, | 184 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1, |
183 » "fini [%p..%p] %u edit requests", | 185 » » "end [%p..%p] %u edit requests", |
184 » this->start, this->end, this->edit_count); | 186 » » this->start, this->end, this->edit_count); |
185 | 187 |
186 hb_blob_destroy (this->blob); | 188 hb_blob_destroy (this->blob); |
187 this->blob = NULL; | 189 this->blob = NULL; |
188 this->start = this->end = NULL; | 190 this->start = this->end = NULL; |
189 } | 191 } |
190 | 192 |
191 inline bool check_range (const void *base, unsigned int len) const | 193 inline bool check_range (const void *base, unsigned int len) const |
192 { | 194 { |
193 const char *p = (const char *) base; | 195 const char *p = (const char *) base; |
194 bool ret = this->start <= p && | |
195 p <= this->end && | |
196 (unsigned int) (this->end - p) >= len; | |
197 | 196 |
198 DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, | 197 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", th
is->blob, NULL, |
199 » » "%-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s", | 198 » » » » » "check_range [%p..%p] (%d bytes) i
n [%p..%p]", |
200 » » this->debug_depth, this->debug_depth, | 199 » » » » » p, p + len, len, |
201 » » p, p + len, len, | 200 » » » » » this->start, this->end); |
202 » » this->start, this->end, | |
203 » » ret ? "pass" : "FAIL"); | |
204 | 201 |
205 return likely (ret); | 202 return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned
int) (this->end - p) >= len)); |
206 } | 203 } |
207 | 204 |
208 inline bool check_array (const void *base, unsigned int record_size, unsigned
int len) const | 205 inline bool check_array (const void *base, unsigned int record_size, unsigned
int len) const |
209 { | 206 { |
210 const char *p = (const char *) base; | 207 const char *p = (const char *) base; |
211 bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); | 208 bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); |
212 | 209 |
213 DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, | 210 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", th
is->blob, NULL, |
214 » » "%-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s"
, | 211 » » » » » "check_array [%p..%p] (%d*%d=%ld b
ytes) in [%p..%p]", |
215 » » this->debug_depth, this->debug_depth, | 212 » » » » » p, p + (record_size * len), record
_size, len, (unsigned long) record_size * len, |
216 » » p, p + (record_size * len), record_size, len, (unsigned lon
g) record_size * len, | 213 » » » » » this->start, this->end); |
217 » » this->start, this->end, | |
218 » » !overflows ? "does not overflow" : "OVERFLOWS FAIL"); | |
219 | 214 |
220 return likely (!overflows && this->check_range (base, record_size * len)); | 215 return TRACE_RETURN (likely (!overflows && this->check_range (base, record_s
ize * len))); |
221 } | 216 } |
222 | 217 |
223 template <typename Type> | 218 template <typename Type> |
224 inline bool check_struct (const Type *obj) const | 219 inline bool check_struct (const Type *obj) const |
225 { | 220 { |
226 return likely (this->check_range (obj, obj->min_size)); | 221 return likely (this->check_range (obj, obj->min_size)); |
227 } | 222 } |
228 | 223 |
229 inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) | 224 inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) |
230 { | 225 { |
231 const char *p = (const char *) base; | 226 const char *p = (const char *) base; |
232 this->edit_count++; | 227 this->edit_count++; |
233 | 228 |
234 DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, | 229 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", th
is->blob, NULL, |
235 » » "%-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", | 230 » » » » » "may_edit(%u) [%p..%p] (%d bytes)
in [%p..%p] -> %s", |
236 » » this->debug_depth, this->debug_depth, | 231 » » » » » this->edit_count, |
237 » » this->edit_count, | 232 » » » » » p, p + len, len, |
238 » » p, p + len, len, | 233 » » » » » this->start, this->end); |
239 » » this->start, this->end, | |
240 » » this->writable ? "granted" : "REJECTED"); | |
241 | 234 |
242 return this->writable; | 235 return TRACE_RETURN (this->writable); |
243 } | 236 } |
244 | 237 |
245 unsigned int debug_depth; | 238 mutable unsigned int debug_depth; |
246 const char *start, *end; | 239 const char *start, *end; |
247 bool writable; | 240 bool writable; |
248 unsigned int edit_count; | 241 unsigned int edit_count; |
249 hb_blob_t *blob; | 242 hb_blob_t *blob; |
250 }; | 243 }; |
251 | 244 |
252 | 245 |
253 | 246 |
254 /* Template to sanitize an object. */ | 247 /* Template to sanitize an object. */ |
255 template <typename Type> | 248 template <typename Type> |
256 struct Sanitizer | 249 struct Sanitizer |
257 { | 250 { |
258 static hb_blob_t *sanitize (hb_blob_t *blob) { | 251 static hb_blob_t *sanitize (hb_blob_t *blob) { |
259 hb_sanitize_context_t c[1] = {{0}}; | 252 hb_sanitize_context_t c[1] = {{0}}; |
260 bool sane; | 253 bool sane; |
261 | 254 |
262 /* TODO is_sane() stuff */ | 255 /* TODO is_sane() stuff */ |
263 | 256 |
264 c->init (blob); | 257 c->init (blob); |
265 | 258 |
266 retry: | 259 retry: |
267 DEBUG_MSG_FUNC (SANITIZE, blob, "start"); | 260 DEBUG_MSG_FUNC (SANITIZE, blob, "start"); |
268 | 261 |
269 c->setup (); | 262 c->start_processing (); |
270 | 263 |
271 if (unlikely (!c->start)) { | 264 if (unlikely (!c->start)) { |
272 c->finish (); | 265 c->end_processing (); |
273 return blob; | 266 return blob; |
274 } | 267 } |
275 | 268 |
276 Type *t = CastP<Type> (const_cast<char *> (c->start)); | 269 Type *t = CastP<Type> (const_cast<char *> (c->start)); |
277 | 270 |
278 sane = t->sanitize (c); | 271 sane = t->sanitize (c); |
279 if (sane) { | 272 if (sane) { |
280 if (c->edit_count) { | 273 if (c->edit_count) { |
281 DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going
for second round", c->edit_count); | 274 DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going
for second round", c->edit_count); |
282 | 275 |
(...skipping 13 matching lines...) Expand all Loading... |
296 | 289 |
297 if (c->start) { | 290 if (c->start) { |
298 c->writable = true; | 291 c->writable = true; |
299 /* ok, we made it writable by relocating. try again */ | 292 /* ok, we made it writable by relocating. try again */ |
300 DEBUG_MSG_FUNC (SANITIZE, blob, "retry"); | 293 DEBUG_MSG_FUNC (SANITIZE, blob, "retry"); |
301 goto retry; | 294 goto retry; |
302 } | 295 } |
303 } | 296 } |
304 } | 297 } |
305 | 298 |
306 c->finish (); | 299 c->end_processing (); |
307 | 300 |
308 DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED"); | 301 DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED"); |
309 if (sane) | 302 if (sane) |
310 return blob; | 303 return blob; |
311 else { | 304 else { |
312 hb_blob_destroy (blob); | 305 hb_blob_destroy (blob); |
313 return hb_blob_get_empty (); | 306 return hb_blob_get_empty (); |
314 } | 307 } |
315 } | 308 } |
316 | 309 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 template <typename Type> | 360 template <typename Type> |
368 struct IntType | 361 struct IntType |
369 { | 362 { |
370 inline void set (Type i) { v.set (i); } | 363 inline void set (Type i) { v.set (i); } |
371 inline operator Type(void) const { return v; } | 364 inline operator Type(void) const { return v; } |
372 inline bool operator == (const IntType<Type> &o) const { return v == o.v; } | 365 inline bool operator == (const IntType<Type> &o) const { return v == o.v; } |
373 inline bool operator != (const IntType<Type> &o) const { return v != o.v; } | 366 inline bool operator != (const IntType<Type> &o) const { return v != o.v; } |
374 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +
1; } | 367 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +
1; } |
375 inline bool sanitize (hb_sanitize_context_t *c) { | 368 inline bool sanitize (hb_sanitize_context_t *c) { |
376 TRACE_SANITIZE (); | 369 TRACE_SANITIZE (); |
377 return likely (c->check_struct (this)); | 370 return TRACE_RETURN (likely (c->check_struct (this))); |
378 } | 371 } |
379 protected: | 372 protected: |
380 BEInt<Type, sizeof (Type)> v; | 373 BEInt<Type, sizeof (Type)> v; |
381 public: | 374 public: |
382 DEFINE_SIZE_STATIC (sizeof (Type)); | 375 DEFINE_SIZE_STATIC (sizeof (Type)); |
383 }; | 376 }; |
384 | 377 |
385 /* Typedef these to avoid clash with windows.h */ | 378 /* Typedef these to avoid clash with windows.h */ |
386 #define USHORT HB_USHORT | 379 #define USHORT HB_USHORT |
387 #define SHORT HB_SHORT | 380 #define SHORT HB_SHORT |
388 #define ULONG HB_ULONG | 381 #define ULONG HB_ULONG |
389 #define LONG HB_LONG | 382 #define LONG HB_LONG |
390 typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ | 383 typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ |
391 typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ | 384 typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ |
392 typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ | 385 typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ |
393 typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ | 386 typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ |
394 | 387 |
395 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ | 388 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ |
396 typedef SHORT FWORD; | 389 typedef SHORT FWORD; |
397 | 390 |
398 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ | 391 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ |
399 typedef USHORT UFWORD; | 392 typedef USHORT UFWORD; |
400 | 393 |
401 /* Date represented in number of seconds since 12:00 midnight, January 1, | 394 /* Date represented in number of seconds since 12:00 midnight, January 1, |
402 * 1904. The value is represented as a signed 64-bit integer. */ | 395 * 1904. The value is represented as a signed 64-bit integer. */ |
403 struct LONGDATETIME | 396 struct LONGDATETIME |
404 { | 397 { |
405 inline bool sanitize (hb_sanitize_context_t *c) { | 398 inline bool sanitize (hb_sanitize_context_t *c) { |
406 TRACE_SANITIZE (); | 399 TRACE_SANITIZE (); |
407 return likely (c->check_struct (this)); | 400 return TRACE_RETURN (likely (c->check_struct (this))); |
408 } | 401 } |
409 private: | 402 private: |
410 LONG major; | 403 LONG major; |
411 ULONG minor; | 404 ULONG minor; |
412 public: | 405 public: |
413 DEFINE_SIZE_STATIC (8); | 406 DEFINE_SIZE_STATIC (8); |
414 }; | 407 }; |
415 | 408 |
416 /* Array of four uint8s (length = 32 bits) used to identify a script, language | 409 /* Array of four uint8s (length = 32 bits) used to identify a script, language |
417 * system, feature, or baseline */ | 410 * system, feature, or baseline */ |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 /* | 454 /* |
462 * Version Numbers | 455 * Version Numbers |
463 */ | 456 */ |
464 | 457 |
465 struct FixedVersion | 458 struct FixedVersion |
466 { | 459 { |
467 inline uint32_t to_int (void) const { return (major << 16) + minor; } | 460 inline uint32_t to_int (void) const { return (major << 16) + minor; } |
468 | 461 |
469 inline bool sanitize (hb_sanitize_context_t *c) { | 462 inline bool sanitize (hb_sanitize_context_t *c) { |
470 TRACE_SANITIZE (); | 463 TRACE_SANITIZE (); |
471 return c->check_struct (this); | 464 return TRACE_RETURN (c->check_struct (this)); |
472 } | 465 } |
473 | 466 |
474 USHORT major; | 467 USHORT major; |
475 USHORT minor; | 468 USHORT minor; |
476 public: | 469 public: |
477 DEFINE_SIZE_STATIC (4); | 470 DEFINE_SIZE_STATIC (4); |
478 }; | 471 }; |
479 | 472 |
480 | 473 |
481 | 474 |
482 /* | 475 /* |
483 * Template subclasses of Offset and LongOffset that do the dereferencing. | 476 * Template subclasses of Offset and LongOffset that do the dereferencing. |
484 * Use: (base+offset) | 477 * Use: (base+offset) |
485 */ | 478 */ |
486 | 479 |
487 template <typename OffsetType, typename Type> | 480 template <typename OffsetType, typename Type> |
488 struct GenericOffsetTo : OffsetType | 481 struct GenericOffsetTo : OffsetType |
489 { | 482 { |
490 inline const Type& operator () (const void *base) const | 483 inline const Type& operator () (const void *base) const |
491 { | 484 { |
492 unsigned int offset = *this; | 485 unsigned int offset = *this; |
493 if (unlikely (!offset)) return Null(Type); | 486 if (unlikely (!offset)) return Null(Type); |
494 return StructAtOffset<Type> (base, offset); | 487 return StructAtOffset<Type> (base, offset); |
495 } | 488 } |
496 | 489 |
497 inline bool sanitize (hb_sanitize_context_t *c, void *base) { | 490 inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
498 TRACE_SANITIZE (); | 491 TRACE_SANITIZE (); |
499 if (unlikely (!c->check_struct (this))) return false; | 492 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); |
500 unsigned int offset = *this; | 493 unsigned int offset = *this; |
501 if (unlikely (!offset)) return true; | 494 if (unlikely (!offset)) return TRACE_RETURN (true); |
502 Type &obj = StructAtOffset<Type> (base, offset); | 495 Type &obj = StructAtOffset<Type> (base, offset); |
503 return likely (obj.sanitize (c)) || neuter (c); | 496 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); |
504 } | 497 } |
505 template <typename T> | 498 template <typename T> |
506 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { | 499 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { |
507 TRACE_SANITIZE (); | 500 TRACE_SANITIZE (); |
508 if (unlikely (!c->check_struct (this))) return false; | 501 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); |
509 unsigned int offset = *this; | 502 unsigned int offset = *this; |
510 if (unlikely (!offset)) return true; | 503 if (unlikely (!offset)) return TRACE_RETURN (true); |
511 Type &obj = StructAtOffset<Type> (base, offset); | 504 Type &obj = StructAtOffset<Type> (base, offset); |
512 return likely (obj.sanitize (c, user_data)) || neuter (c); | 505 return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); |
513 } | 506 } |
514 | 507 |
515 private: | 508 private: |
516 /* Set the offset to Null */ | 509 /* Set the offset to Null */ |
517 inline bool neuter (hb_sanitize_context_t *c) { | 510 inline bool neuter (hb_sanitize_context_t *c) { |
518 if (c->can_edit (this, this->static_size)) { | 511 if (c->may_edit (this, this->static_size)) { |
519 this->set (0); /* 0 is Null offset */ | 512 this->set (0); /* 0 is Null offset */ |
520 return true; | 513 return true; |
521 } | 514 } |
522 return false; | 515 return false; |
523 } | 516 } |
524 }; | 517 }; |
525 template <typename Base, typename OffsetType, typename Type> | 518 template <typename Base, typename OffsetType, typename Type> |
526 inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Typ
e> offset) { return offset (base); } | 519 inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Typ
e> offset) { return offset (base); } |
527 | 520 |
528 template <typename Type> | 521 template <typename Type> |
(...skipping 25 matching lines...) Expand all Loading... |
554 inline const Type& operator [] (unsigned int i) const | 547 inline const Type& operator [] (unsigned int i) const |
555 { | 548 { |
556 if (unlikely (i >= len)) return Null(Type); | 549 if (unlikely (i >= len)) return Null(Type); |
557 return array[i]; | 550 return array[i]; |
558 } | 551 } |
559 inline unsigned int get_size (void) const | 552 inline unsigned int get_size (void) const |
560 { return len.static_size + len * Type::static_size; } | 553 { return len.static_size + len * Type::static_size; } |
561 | 554 |
562 inline bool sanitize (hb_sanitize_context_t *c) { | 555 inline bool sanitize (hb_sanitize_context_t *c) { |
563 TRACE_SANITIZE (); | 556 TRACE_SANITIZE (); |
564 if (unlikely (!sanitize_shallow (c))) return false; | 557 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
565 | 558 |
566 /* Note: for structs that do not reference other structs, | 559 /* Note: for structs that do not reference other structs, |
567 * we do not need to call their sanitize() as we already did | 560 * we do not need to call their sanitize() as we already did |
568 * a bound check on the aggregate array size. We just include | 561 * a bound check on the aggregate array size. We just include |
569 * a small unreachable expression to make sure the structs | 562 * a small unreachable expression to make sure the structs |
570 * pointed to do have a simple sanitize(), ie. they do not | 563 * pointed to do have a simple sanitize(), ie. they do not |
571 * reference other structs via offsets. | 564 * reference other structs via offsets. |
572 */ | 565 */ |
573 (void) (false && array[0].sanitize (c)); | 566 (void) (false && array[0].sanitize (c)); |
574 | 567 |
575 return true; | 568 return TRACE_RETURN (true); |
576 } | 569 } |
577 inline bool sanitize (hb_sanitize_context_t *c, void *base) { | 570 inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
578 TRACE_SANITIZE (); | 571 TRACE_SANITIZE (); |
579 if (unlikely (!sanitize_shallow (c))) return false; | 572 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
580 unsigned int count = len; | 573 unsigned int count = len; |
581 for (unsigned int i = 0; i < count; i++) | 574 for (unsigned int i = 0; i < count; i++) |
582 if (unlikely (!array[i].sanitize (c, base))) | 575 if (unlikely (!array[i].sanitize (c, base))) |
583 return false; | 576 return TRACE_RETURN (false); |
584 return true; | 577 return TRACE_RETURN (true); |
585 } | 578 } |
586 template <typename T> | 579 template <typename T> |
587 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { | 580 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { |
588 TRACE_SANITIZE (); | 581 TRACE_SANITIZE (); |
589 if (unlikely (!sanitize_shallow (c))) return false; | 582 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
590 unsigned int count = len; | 583 unsigned int count = len; |
591 for (unsigned int i = 0; i < count; i++) | 584 for (unsigned int i = 0; i < count; i++) |
592 if (unlikely (!array[i].sanitize (c, base, user_data))) | 585 if (unlikely (!array[i].sanitize (c, base, user_data))) |
593 return false; | 586 return TRACE_RETURN (false); |
594 return true; | 587 return TRACE_RETURN (true); |
595 } | 588 } |
596 | 589 |
597 private: | 590 private: |
598 inline bool sanitize_shallow (hb_sanitize_context_t *c) { | 591 inline bool sanitize_shallow (hb_sanitize_context_t *c) { |
599 TRACE_SANITIZE (); | 592 TRACE_SANITIZE (); |
600 return c->check_struct (this) | 593 return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::s
tatic_size, len)); |
601 » && c->check_array (this, Type::static_size, len); | |
602 } | 594 } |
603 | 595 |
604 public: | 596 public: |
605 LenType len; | 597 LenType len; |
606 Type array[VAR]; | 598 Type array[VAR]; |
607 public: | 599 public: |
608 DEFINE_SIZE_ARRAY (sizeof (LenType), array); | 600 DEFINE_SIZE_ARRAY (sizeof (LenType), array); |
609 }; | 601 }; |
610 | 602 |
611 /* An array with a USHORT number of elements. */ | 603 /* An array with a USHORT number of elements. */ |
(...skipping 21 matching lines...) Expand all Loading... |
633 struct OffsetListOf : OffsetArrayOf<Type> | 625 struct OffsetListOf : OffsetArrayOf<Type> |
634 { | 626 { |
635 inline const Type& operator [] (unsigned int i) const | 627 inline const Type& operator [] (unsigned int i) const |
636 { | 628 { |
637 if (unlikely (i >= this->len)) return Null(Type); | 629 if (unlikely (i >= this->len)) return Null(Type); |
638 return this+this->array[i]; | 630 return this+this->array[i]; |
639 } | 631 } |
640 | 632 |
641 inline bool sanitize (hb_sanitize_context_t *c) { | 633 inline bool sanitize (hb_sanitize_context_t *c) { |
642 TRACE_SANITIZE (); | 634 TRACE_SANITIZE (); |
643 return OffsetArrayOf<Type>::sanitize (c, this); | 635 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this)); |
644 } | 636 } |
645 template <typename T> | 637 template <typename T> |
646 inline bool sanitize (hb_sanitize_context_t *c, T user_data) { | 638 inline bool sanitize (hb_sanitize_context_t *c, T user_data) { |
647 TRACE_SANITIZE (); | 639 TRACE_SANITIZE (); |
648 return OffsetArrayOf<Type>::sanitize (c, this, user_data); | 640 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data)); |
649 } | 641 } |
650 }; | 642 }; |
651 | 643 |
652 | 644 |
653 /* An array with a USHORT number of elements, | 645 /* An array with a USHORT number of elements, |
654 * starting at second element. */ | 646 * starting at second element. */ |
655 template <typename Type> | 647 template <typename Type> |
656 struct HeadlessArrayOf | 648 struct HeadlessArrayOf |
657 { | 649 { |
658 inline const Type& operator [] (unsigned int i) const | 650 inline const Type& operator [] (unsigned int i) const |
659 { | 651 { |
660 if (unlikely (i >= len || !i)) return Null(Type); | 652 if (unlikely (i >= len || !i)) return Null(Type); |
661 return array[i-1]; | 653 return array[i-1]; |
662 } | 654 } |
663 inline unsigned int get_size (void) const | 655 inline unsigned int get_size (void) const |
664 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } | 656 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } |
665 | 657 |
666 inline bool sanitize_shallow (hb_sanitize_context_t *c) { | 658 inline bool sanitize_shallow (hb_sanitize_context_t *c) { |
667 return c->check_struct (this) | 659 return c->check_struct (this) |
668 && c->check_array (this, Type::static_size, len); | 660 && c->check_array (this, Type::static_size, len); |
669 } | 661 } |
670 | 662 |
671 inline bool sanitize (hb_sanitize_context_t *c) { | 663 inline bool sanitize (hb_sanitize_context_t *c) { |
672 TRACE_SANITIZE (); | 664 TRACE_SANITIZE (); |
673 if (unlikely (!sanitize_shallow (c))) return false; | 665 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
674 | 666 |
675 /* Note: for structs that do not reference other structs, | 667 /* Note: for structs that do not reference other structs, |
676 * we do not need to call their sanitize() as we already did | 668 * we do not need to call their sanitize() as we already did |
677 * a bound check on the aggregate array size. We just include | 669 * a bound check on the aggregate array size. We just include |
678 * a small unreachable expression to make sure the structs | 670 * a small unreachable expression to make sure the structs |
679 * pointed to do have a simple sanitize(), ie. they do not | 671 * pointed to do have a simple sanitize(), ie. they do not |
680 * reference other structs via offsets. | 672 * reference other structs via offsets. |
681 */ | 673 */ |
682 (void) (false && array[0].sanitize (c)); | 674 (void) (false && array[0].sanitize (c)); |
683 | 675 |
684 return true; | 676 return TRACE_RETURN (true); |
685 } | 677 } |
686 | 678 |
687 USHORT len; | 679 USHORT len; |
688 Type array[VAR]; | 680 Type array[VAR]; |
689 public: | 681 public: |
690 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); | 682 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); |
691 }; | 683 }; |
692 | 684 |
693 | 685 |
694 /* An array with sorted elements. Supports binary searching. */ | 686 /* An array with sorted elements. Supports binary searching. */ |
695 template <typename Type> | 687 template <typename Type> |
696 struct SortedArrayOf : ArrayOf<Type> { | 688 struct SortedArrayOf : ArrayOf<Type> { |
697 | 689 |
698 template <typename SearchType> | 690 template <typename SearchType> |
699 inline int search (const SearchType &x) const { | 691 inline int search (const SearchType &x) const { |
700 struct Cmp { | 692 struct Cmp { |
701 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a);
} | 693 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a);
} |
702 }; | 694 }; |
703 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (
this->array[0]), (hb_compare_func_t) Cmp::cmp); | 695 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (
this->array[0]), (hb_compare_func_t) Cmp::cmp); |
704 return p ? p - this->array : -1; | 696 return p ? p - this->array : -1; |
705 } | 697 } |
706 }; | 698 }; |
707 | 699 |
708 | 700 |
709 | 701 |
710 #endif /* HB_OPEN_TYPE_PRIVATE_HH */ | 702 #endif /* HB_OPEN_TYPE_PRIVATE_HH */ |
OLD | NEW |