1 : /*
2 : * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 : *
4 : * This is part of HarfBuzz, a text shaping library.
5 : *
6 : * Permission is hereby granted, without written agreement and without
7 : * license or royalty fees, to use, copy, modify, and distribute this
8 : * software and its documentation for any purpose, provided that the
9 : * above copyright notice and the following two paragraphs appear in
10 : * all copies of this software.
11 : *
12 : * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 : * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 : * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 : * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 : * DAMAGE.
17 : *
18 : * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 : * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 : * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 : * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 : * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 : *
24 : * Red Hat Author(s): Behdad Esfahbod
25 : */
26 :
27 : #ifndef HB_OPEN_TYPE_PRIVATE_HH
28 : #define HB_OPEN_TYPE_PRIVATE_HH
29 :
30 : #include "hb-private.hh"
31 :
32 : #include "hb-blob.h"
33 :
34 :
35 :
36 : /*
37 : * Casts
38 : */
39 :
40 : /* Cast to struct T, reference to reference */
41 : template<typename Type, typename TObject>
42 0 : inline const Type& CastR(const TObject &X)
43 0 : { return reinterpret_cast<const Type&> (X); }
44 : template<typename Type, typename TObject>
45 0 : inline Type& CastR(TObject &X)
46 0 : { return reinterpret_cast<Type&> (X); }
47 :
48 : /* Cast to struct T, pointer to pointer */
49 : template<typename Type, typename TObject>
50 0 : inline const Type* CastP(const TObject *X)
51 0 : { return reinterpret_cast<const Type*> (X); }
52 : template<typename Type, typename TObject>
53 0 : inline Type* CastP(TObject *X)
54 0 : { return reinterpret_cast<Type*> (X); }
55 :
56 : /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
57 : * location pointed to by P plus Ofs bytes. */
58 : template<typename Type>
59 0 : inline const Type& StructAtOffset(const void *P, unsigned int offset)
60 0 : { return * reinterpret_cast<const Type*> ((const char *) P + offset); }
61 : template<typename Type>
62 0 : inline Type& StructAtOffset(void *P, unsigned int offset)
63 0 : { return * reinterpret_cast<Type*> ((char *) P + offset); }
64 :
65 : /* StructAfter<T>(X) returns the struct T& that is placed after X.
66 : * Works with X of variable size also. X must implement get_size() */
67 : template<typename Type, typename TObject>
68 0 : inline const Type& StructAfter(const TObject &X)
69 0 : { return StructAtOffset<Type>(&X, X.get_size()); }
70 : template<typename Type, typename TObject>
71 0 : inline Type& StructAfter(TObject &X)
72 0 : { return StructAtOffset<Type>(&X, X.get_size()); }
73 :
74 :
75 :
76 : /*
77 : * Size checking
78 : */
79 :
80 : /* Check _assertion in a method environment */
81 : #define _DEFINE_SIZE_ASSERTION(_assertion) \
82 : inline void _size_assertion (void) const \
83 : { ASSERT_STATIC (_assertion); }
84 : /* Check that _code compiles in a method environment */
85 : #define _DEFINE_COMPILES_ASSERTION(_code) \
86 : inline void _compiles_assertion (void) const \
87 : { _code; }
88 :
89 :
90 : #define DEFINE_SIZE_STATIC(size) \
91 : _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size)); \
92 : static const unsigned int static_size = (size); \
93 : static const unsigned int min_size = (size)
94 :
95 : /* Size signifying variable-sized array */
96 : #define VAR 1
97 :
98 : #define DEFINE_SIZE_UNION(size, _member) \
99 : _DEFINE_SIZE_ASSERTION (this->u._member.static_size == (size)); \
100 : static const unsigned int min_size = (size)
101 :
102 : #define DEFINE_SIZE_MIN(size) \
103 : _DEFINE_SIZE_ASSERTION (sizeof (*this) >= (size)); \
104 : static const unsigned int min_size = (size)
105 :
106 : #define DEFINE_SIZE_ARRAY(size, array) \
107 : _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
108 : _DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
109 : static const unsigned int min_size = (size)
110 :
111 : #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
112 : _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
113 : _DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
114 : static const unsigned int min_size = (size)
115 :
116 :
117 :
118 : /*
119 : * Null objects
120 : */
121 :
122 : /* Global nul-content Null pool. Enlarge as necessary. */
123 : static const void *_NullPool[64 / sizeof (void *)];
124 :
125 : /* Generic nul-content Null objects. */
126 : template <typename Type>
127 0 : static inline const Type& Null (void) {
128 : ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
129 0 : return *CastP<Type> (_NullPool);
130 : }
131 :
132 : /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
133 : #define DEFINE_NULL_DATA(Type, data) \
134 : static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
135 : template <> \
136 : inline const Type& Null<Type> (void) { \
137 : return *CastP<Type> (_Null##Type); \
138 : } /* The following line really exists such that we end in a place needing semicolon */ \
139 : ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
140 :
141 : /* Accessor macro. */
142 : #define Null(Type) Null<Type>()
143 :
144 :
145 :
146 : /*
147 : * Sanitize
148 : */
149 :
150 : #ifndef HB_DEBUG_SANITIZE
151 : #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
152 : #endif
153 :
154 :
155 : #define TRACE_SANITIZE() \
156 : hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, NULL, HB_FUNC);
157 :
158 :
159 : struct hb_sanitize_context_t
160 : {
161 0 : inline void init (hb_blob_t *b)
162 : {
163 0 : this->blob = hb_blob_reference (b);
164 0 : this->writable = false;
165 0 : }
166 :
167 0 : inline void setup (void)
168 : {
169 0 : this->start = hb_blob_get_data (this->blob, NULL);
170 0 : this->end = this->start + hb_blob_get_length (this->blob);
171 0 : this->edit_count = 0;
172 0 : this->debug_depth = 0;
173 :
174 : DEBUG_MSG (SANITIZE, this->blob,
175 : "init [%p..%p] (%lu bytes)",
176 : this->start, this->end,
177 0 : (unsigned long) (this->end - this->start));
178 0 : }
179 :
180 0 : inline void finish (void)
181 : {
182 : DEBUG_MSG (SANITIZE, this->blob,
183 : "fini [%p..%p] %u edit requests",
184 0 : this->start, this->end, this->edit_count);
185 :
186 0 : hb_blob_destroy (this->blob);
187 0 : this->blob = NULL;
188 0 : this->start = this->end = NULL;
189 0 : }
190 :
191 0 : inline bool check_range (const void *base, unsigned int len) const
192 : {
193 0 : const char *p = (const char *) base;
194 : bool ret = this->start <= p &&
195 : p <= this->end &&
196 0 : (unsigned int) (this->end - p) >= len;
197 :
198 : DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth,
199 : "%-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s",
200 : this->debug_depth, this->debug_depth,
201 : p, p + len, len,
202 : this->start, this->end,
203 0 : ret ? "pass" : "FAIL");
204 :
205 0 : return likely (ret);
206 : }
207 :
208 0 : inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
209 : {
210 0 : const char *p = (const char *) base;
211 0 : bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
212 :
213 : DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth,
214 : "%-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s",
215 : this->debug_depth, this->debug_depth,
216 : p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
217 : this->start, this->end,
218 0 : !overflows ? "does not overflow" : "OVERFLOWS FAIL");
219 :
220 0 : return likely (!overflows && this->check_range (base, record_size * len));
221 : }
222 :
223 : template <typename Type>
224 0 : inline bool check_struct (const Type *obj) const
225 : {
226 0 : return likely (this->check_range (obj, obj->min_size));
227 : }
228 :
229 0 : inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
230 : {
231 0 : const char *p = (const char *) base;
232 0 : this->edit_count++;
233 :
234 : DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth,
235 : "%-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
236 : this->debug_depth, this->debug_depth,
237 : this->edit_count,
238 : p, p + len, len,
239 : this->start, this->end,
240 0 : this->writable ? "granted" : "REJECTED");
241 :
242 0 : return this->writable;
243 : }
244 :
245 : unsigned int debug_depth;
246 : const char *start, *end;
247 : bool writable;
248 : unsigned int edit_count;
249 : hb_blob_t *blob;
250 : };
251 :
252 :
253 :
254 : /* Template to sanitize an object. */
255 : template <typename Type>
256 : struct Sanitizer
257 : {
258 0 : static hb_blob_t *sanitize (hb_blob_t *blob) {
259 0 : hb_sanitize_context_t c[1] = {{0}};
260 : bool sane;
261 :
262 : /* TODO is_sane() stuff */
263 :
264 0 : c->init (blob);
265 :
266 : retry:
267 0 : DEBUG_MSG_FUNC (SANITIZE, blob, "start");
268 :
269 0 : c->setup ();
270 :
271 0 : if (unlikely (!c->start)) {
272 0 : c->finish ();
273 0 : return blob;
274 : }
275 :
276 0 : Type *t = CastP<Type> (const_cast<char *> (c->start));
277 :
278 0 : sane = t->sanitize (c);
279 0 : if (sane) {
280 0 : if (c->edit_count) {
281 0 : DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
282 :
283 : /* sanitize again to ensure no toe-stepping */
284 0 : c->edit_count = 0;
285 0 : sane = t->sanitize (c);
286 0 : if (c->edit_count) {
287 0 : DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
288 0 : sane = false;
289 : }
290 : }
291 : } else {
292 0 : unsigned int edit_count = c->edit_count;
293 0 : if (edit_count && !c->writable) {
294 0 : c->start = hb_blob_get_data_writable (blob, NULL);
295 0 : c->end = c->start + hb_blob_get_length (blob);
296 :
297 0 : if (c->start) {
298 0 : c->writable = true;
299 : /* ok, we made it writable by relocating. try again */
300 0 : DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
301 0 : goto retry;
302 : }
303 : }
304 : }
305 :
306 0 : c->finish ();
307 :
308 0 : DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
309 0 : if (sane)
310 0 : return blob;
311 : else {
312 0 : hb_blob_destroy (blob);
313 0 : return hb_blob_get_empty ();
314 : }
315 : }
316 :
317 0 : static const Type* lock_instance (hb_blob_t *blob) {
318 0 : hb_blob_make_immutable (blob);
319 0 : const char *base = hb_blob_get_data (blob, NULL);
320 0 : return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
321 : }
322 : };
323 :
324 :
325 :
326 :
327 : /*
328 : *
329 : * The OpenType Font File: Data Types
330 : */
331 :
332 :
333 : /* "The following data types are used in the OpenType font file.
334 : * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
335 :
336 : /*
337 : * Int types
338 : */
339 :
340 :
341 : template <typename Type, int Bytes> struct BEInt;
342 :
343 : /* LONGTERMTODO: On machines allowing unaligned access, we can make the
344 : * following tighter by using byteswap instructions on ints directly. */
345 : template <typename Type>
346 : struct BEInt<Type, 2>
347 : {
348 : public:
349 0 : inline void set (Type i) { hb_be_uint16_put (v,i); }
350 0 : inline operator Type (void) const { return hb_be_uint16_get (v); }
351 : inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
352 : inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
353 : private: uint8_t v[2];
354 : };
355 : template <typename Type>
356 : struct BEInt<Type, 4>
357 : {
358 : public:
359 0 : inline void set (Type i) { hb_be_uint32_put (v,i); }
360 0 : inline operator Type (void) const { return hb_be_uint32_get (v); }
361 0 : inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
362 : inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
363 : private: uint8_t v[4];
364 : };
365 :
366 : /* Integer types in big-endian order and no alignment requirement */
367 : template <typename Type>
368 : struct IntType
369 : {
370 0 : inline void set (Type i) { v.set (i); }
371 0 : inline operator Type(void) const { return v; }
372 0 : 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; }
374 0 : inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
375 0 : inline bool sanitize (hb_sanitize_context_t *c) {
376 0 : TRACE_SANITIZE ();
377 0 : return likely (c->check_struct (this));
378 : }
379 : protected:
380 : BEInt<Type, sizeof (Type)> v;
381 : public:
382 : DEFINE_SIZE_STATIC (sizeof (Type));
383 : };
384 :
385 : /* Typedef these to avoid clash with windows.h */
386 : #define USHORT HB_USHORT
387 : #define SHORT HB_SHORT
388 : #define ULONG HB_ULONG
389 : #define LONG HB_LONG
390 : typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
391 : typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
392 : typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
393 : typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
394 :
395 : /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
396 : typedef SHORT FWORD;
397 :
398 : /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
399 : typedef USHORT UFWORD;
400 :
401 : /* Date represented in number of seconds since 12:00 midnight, January 1,
402 : * 1904. The value is represented as a signed 64-bit integer. */
403 : struct LONGDATETIME
404 : {
405 : inline bool sanitize (hb_sanitize_context_t *c) {
406 : TRACE_SANITIZE ();
407 : return likely (c->check_struct (this));
408 : }
409 : private:
410 : LONG major;
411 : ULONG minor;
412 : public:
413 : DEFINE_SIZE_STATIC (8);
414 : };
415 :
416 : /* Array of four uint8s (length = 32 bits) used to identify a script, language
417 : * system, feature, or baseline */
418 : struct Tag : ULONG
419 : {
420 : /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
421 : inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
422 : inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
423 : public:
424 : DEFINE_SIZE_STATIC (4);
425 : };
426 0 : DEFINE_NULL_DATA (Tag, " ");
427 :
428 : /* Glyph index number, same as uint16 (length = 16 bits) */
429 : typedef USHORT GlyphID;
430 :
431 : /* Script/language-system/feature index */
432 : struct Index : USHORT {
433 : static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
434 : };
435 0 : DEFINE_NULL_DATA (Index, "\xff\xff");
436 :
437 : /* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
438 : typedef USHORT Offset;
439 :
440 : /* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
441 : typedef ULONG LongOffset;
442 :
443 :
444 : /* CheckSum */
445 : struct CheckSum : ULONG
446 : {
447 : static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
448 : {
449 : uint32_t Sum = 0L;
450 : ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
451 :
452 : while (Table < EndPtr)
453 : Sum += *Table++;
454 : return Sum;
455 : }
456 : public:
457 : DEFINE_SIZE_STATIC (4);
458 : };
459 :
460 :
461 : /*
462 : * Version Numbers
463 : */
464 :
465 : struct FixedVersion
466 : {
467 0 : inline uint32_t to_int (void) const { return (major << 16) + minor; }
468 :
469 0 : inline bool sanitize (hb_sanitize_context_t *c) {
470 0 : TRACE_SANITIZE ();
471 0 : return c->check_struct (this);
472 : }
473 :
474 : USHORT major;
475 : USHORT minor;
476 : public:
477 : DEFINE_SIZE_STATIC (4);
478 : };
479 :
480 :
481 :
482 : /*
483 : * Template subclasses of Offset and LongOffset that do the dereferencing.
484 : * Use: (base+offset)
485 : */
486 :
487 : template <typename OffsetType, typename Type>
488 : struct GenericOffsetTo : OffsetType
489 : {
490 0 : inline const Type& operator () (const void *base) const
491 : {
492 0 : unsigned int offset = *this;
493 0 : if (unlikely (!offset)) return Null(Type);
494 0 : return StructAtOffset<Type> (base, offset);
495 : }
496 :
497 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base) {
498 0 : TRACE_SANITIZE ();
499 0 : if (unlikely (!c->check_struct (this))) return false;
500 0 : unsigned int offset = *this;
501 0 : if (unlikely (!offset)) return true;
502 0 : Type &obj = StructAtOffset<Type> (base, offset);
503 0 : return likely (obj.sanitize (c)) || neuter (c);
504 : }
505 : template <typename T>
506 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
507 0 : TRACE_SANITIZE ();
508 0 : if (unlikely (!c->check_struct (this))) return false;
509 0 : unsigned int offset = *this;
510 0 : if (unlikely (!offset)) return true;
511 0 : Type &obj = StructAtOffset<Type> (base, offset);
512 0 : return likely (obj.sanitize (c, user_data)) || neuter (c);
513 : }
514 :
515 : private:
516 : /* Set the offset to Null */
517 0 : inline bool neuter (hb_sanitize_context_t *c) {
518 0 : if (c->can_edit (this, this->static_size)) {
519 0 : this->set (0); /* 0 is Null offset */
520 0 : return true;
521 : }
522 0 : return false;
523 : }
524 : };
525 : template <typename Base, typename OffsetType, typename Type>
526 0 : inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
527 :
528 : template <typename Type>
529 : struct OffsetTo : GenericOffsetTo<Offset, Type> {};
530 :
531 : template <typename Type>
532 : struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
533 :
534 :
535 : /*
536 : * Array Types
537 : */
538 :
539 : template <typename LenType, typename Type>
540 : struct GenericArrayOf
541 : {
542 0 : const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
543 : {
544 0 : unsigned int count = len;
545 0 : if (unlikely (start_offset > count))
546 0 : count = 0;
547 : else
548 0 : count -= start_offset;
549 0 : count = MIN (count, *pcount);
550 0 : *pcount = count;
551 0 : return array + start_offset;
552 : }
553 :
554 0 : inline const Type& operator [] (unsigned int i) const
555 : {
556 0 : if (unlikely (i >= len)) return Null(Type);
557 0 : return array[i];
558 : }
559 0 : inline unsigned int get_size (void) const
560 0 : { return len.static_size + len * Type::static_size; }
561 :
562 0 : inline bool sanitize (hb_sanitize_context_t *c) {
563 0 : TRACE_SANITIZE ();
564 0 : if (unlikely (!sanitize_shallow (c))) return false;
565 :
566 : /* Note: for structs that do not reference other structs,
567 : * we do not need to call their sanitize() as we already did
568 : * a bound check on the aggregate array size. We just include
569 : * a small unreachable expression to make sure the structs
570 : * pointed to do have a simple sanitize(), ie. they do not
571 : * reference other structs via offsets.
572 : */
573 : (void) (false && array[0].sanitize (c));
574 :
575 0 : return true;
576 : }
577 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base) {
578 0 : TRACE_SANITIZE ();
579 0 : if (unlikely (!sanitize_shallow (c))) return false;
580 0 : unsigned int count = len;
581 0 : for (unsigned int i = 0; i < count; i++)
582 0 : if (unlikely (!array[i].sanitize (c, base)))
583 0 : return false;
584 0 : return true;
585 : }
586 : template <typename T>
587 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
588 0 : TRACE_SANITIZE ();
589 0 : if (unlikely (!sanitize_shallow (c))) return false;
590 0 : unsigned int count = len;
591 0 : for (unsigned int i = 0; i < count; i++)
592 0 : if (unlikely (!array[i].sanitize (c, base, user_data)))
593 0 : return false;
594 0 : return true;
595 : }
596 :
597 : private:
598 0 : inline bool sanitize_shallow (hb_sanitize_context_t *c) {
599 0 : TRACE_SANITIZE ();
600 : return c->check_struct (this)
601 0 : && c->check_array (this, Type::static_size, len);
602 : }
603 :
604 : public:
605 : LenType len;
606 : Type array[VAR];
607 : public:
608 : DEFINE_SIZE_ARRAY (sizeof (LenType), array);
609 : };
610 :
611 : /* An array with a USHORT number of elements. */
612 : template <typename Type>
613 : struct ArrayOf : GenericArrayOf<USHORT, Type> {};
614 :
615 : /* An array with a ULONG number of elements. */
616 : template <typename Type>
617 : struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
618 :
619 : /* Array of Offset's */
620 : template <typename Type>
621 : struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
622 :
623 : /* Array of LongOffset's */
624 : template <typename Type>
625 : struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
626 :
627 : /* LongArray of LongOffset's */
628 : template <typename Type>
629 : struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
630 :
631 : /* Array of offsets relative to the beginning of the array itself. */
632 : template <typename Type>
633 : struct OffsetListOf : OffsetArrayOf<Type>
634 : {
635 0 : inline const Type& operator [] (unsigned int i) const
636 : {
637 0 : if (unlikely (i >= this->len)) return Null(Type);
638 0 : return this+this->array[i];
639 : }
640 :
641 0 : inline bool sanitize (hb_sanitize_context_t *c) {
642 0 : TRACE_SANITIZE ();
643 0 : return OffsetArrayOf<Type>::sanitize (c, this);
644 : }
645 : template <typename T>
646 0 : inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
647 0 : TRACE_SANITIZE ();
648 0 : return OffsetArrayOf<Type>::sanitize (c, this, user_data);
649 : }
650 : };
651 :
652 :
653 : /* An array with a USHORT number of elements,
654 : * starting at second element. */
655 : template <typename Type>
656 : struct HeadlessArrayOf
657 : {
658 0 : inline const Type& operator [] (unsigned int i) const
659 : {
660 0 : if (unlikely (i >= len || !i)) return Null(Type);
661 0 : return array[i-1];
662 : }
663 0 : inline unsigned int get_size (void) const
664 0 : { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
665 :
666 0 : inline bool sanitize_shallow (hb_sanitize_context_t *c) {
667 : return c->check_struct (this)
668 0 : && c->check_array (this, Type::static_size, len);
669 : }
670 :
671 0 : inline bool sanitize (hb_sanitize_context_t *c) {
672 0 : TRACE_SANITIZE ();
673 0 : if (unlikely (!sanitize_shallow (c))) return false;
674 :
675 : /* Note: for structs that do not reference other structs,
676 : * we do not need to call their sanitize() as we already did
677 : * a bound check on the aggregate array size. We just include
678 : * a small unreachable expression to make sure the structs
679 : * pointed to do have a simple sanitize(), ie. they do not
680 : * reference other structs via offsets.
681 : */
682 : (void) (false && array[0].sanitize (c));
683 :
684 0 : return true;
685 : }
686 :
687 : USHORT len;
688 : Type array[VAR];
689 : public:
690 : DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
691 : };
692 :
693 :
694 : /* An array with sorted elements. Supports binary searching. */
695 : template <typename Type>
696 : struct SortedArrayOf : ArrayOf<Type> {
697 :
698 : template <typename SearchType>
699 0 : inline int search (const SearchType &x) const {
700 : struct Cmp {
701 0 : static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
702 : };
703 0 : const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
704 0 : return p ? p - this->array : -1;
705 : }
706 : };
707 :
708 :
709 :
710 : #endif /* HB_OPEN_TYPE_PRIVATE_HH */
|