2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OPEN_TYPE_PRIVATE_HH
30 #define HB_OPEN_TYPE_PRIVATE_HH
32 #include "hb-private.hh"
43 /* Cast to struct T, reference to reference */
44 template<typename Type
, typename TObject
>
45 static inline const Type
& CastR(const TObject
&X
)
46 { return reinterpret_cast<const Type
&> (X
); }
47 template<typename Type
, typename TObject
>
48 static inline Type
& CastR(TObject
&X
)
49 { return reinterpret_cast<Type
&> (X
); }
51 /* Cast to struct T, pointer to pointer */
52 template<typename Type
, typename TObject
>
53 static inline const Type
* CastP(const TObject
*X
)
54 { return reinterpret_cast<const Type
*> (X
); }
55 template<typename Type
, typename TObject
>
56 static inline Type
* CastP(TObject
*X
)
57 { return reinterpret_cast<Type
*> (X
); }
59 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
60 * location pointed to by P plus Ofs bytes. */
61 template<typename Type
>
62 static inline const Type
& StructAtOffset(const void *P
, unsigned int offset
)
63 { return * reinterpret_cast<const Type
*> ((const char *) P
+ offset
); }
64 template<typename Type
>
65 static inline Type
& StructAtOffset(void *P
, unsigned int offset
)
66 { return * reinterpret_cast<Type
*> ((char *) P
+ offset
); }
68 /* StructAfter<T>(X) returns the struct T& that is placed after X.
69 * Works with X of variable size also. X must implement get_size() */
70 template<typename Type
, typename TObject
>
71 static inline const Type
& StructAfter(const TObject
&X
)
72 { return StructAtOffset
<Type
>(&X
, X
.get_size()); }
73 template<typename Type
, typename TObject
>
74 static inline Type
& StructAfter(TObject
&X
)
75 { return StructAtOffset
<Type
>(&X
, X
.get_size()); }
83 /* Check _assertion in a method environment */
84 #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
85 inline void _instance_assertion_on_line_##_line (void) const \
87 ASSERT_STATIC (_assertion); \
88 ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
90 # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
91 # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
93 /* Check that _code compiles in a method environment */
94 #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
95 inline void _compiles_assertion_on_line_##_line (void) const \
97 # define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
98 # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
101 #define DEFINE_SIZE_STATIC(size) \
102 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
103 static const unsigned int static_size = (size); \
104 static const unsigned int min_size = (size)
106 /* Size signifying variable-sized array */
109 #define DEFINE_SIZE_UNION(size, _member) \
110 DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
111 static const unsigned int min_size = (size)
113 #define DEFINE_SIZE_MIN(size) \
114 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
115 static const unsigned int min_size = (size)
117 #define DEFINE_SIZE_ARRAY(size, array) \
118 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
119 DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
120 static const unsigned int min_size = (size)
122 #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
123 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
124 DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
125 static const unsigned int min_size = (size)
133 /* Global nul-content Null pool. Enlarge as necessary. */
134 /* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
135 static const void *_NullPool
[(256+8) / sizeof (void *)];
137 /* Generic nul-content Null objects. */
138 template <typename Type
>
139 static inline const Type
& Null (void) {
140 ASSERT_STATIC (sizeof (Type
) <= sizeof (_NullPool
));
141 return *CastP
<Type
> (_NullPool
);
144 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
145 #define DEFINE_NULL_DATA(Type, data) \
146 static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
148 /*static*/ inline const Type& Null<Type> (void) { \
149 return *CastP<Type> (_Null##Type); \
150 } /* The following line really exists such that we end in a place needing semicolon */ \
151 ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
153 /* Accessor macro. */
154 #define Null(Type) Null<Type>()
162 #ifndef HB_DEBUG_SANITIZE
163 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
167 #define TRACE_SANITIZE(this) \
168 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
169 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
172 /* This limits sanitizing time on really broken fonts. */
173 #ifndef HB_SANITIZE_MAX_EDITS
174 #define HB_SANITIZE_MAX_EDITS 100
177 struct hb_sanitize_context_t
179 inline const char *get_name (void) { return "SANITIZE"; }
180 static const unsigned int max_debug_depth
= HB_DEBUG_SANITIZE
;
181 typedef bool return_t
;
182 template <typename T
, typename F
>
183 inline bool may_dispatch (const T
*obj
, const F
*format
)
184 { return format
->sanitize (this); }
185 template <typename T
>
186 inline return_t
dispatch (const T
&obj
) { return obj
.sanitize (this); }
187 static return_t
default_return_value (void) { return true; }
188 bool stop_sublookup_iteration (const return_t r
) const { return !r
; }
190 inline void init (hb_blob_t
*b
)
192 this->blob
= hb_blob_reference (b
);
193 this->writable
= false;
196 inline void start_processing (void)
198 this->start
= hb_blob_get_data (this->blob
, NULL
);
199 this->end
= this->start
+ hb_blob_get_length (this->blob
);
200 assert (this->start
<= this->end
); /* Must not overflow. */
201 this->edit_count
= 0;
202 this->debug_depth
= 0;
204 DEBUG_MSG_LEVEL (SANITIZE
, start
, 0, +1,
205 "start [%p..%p] (%lu bytes)",
206 this->start
, this->end
,
207 (unsigned long) (this->end
- this->start
));
210 inline void end_processing (void)
212 DEBUG_MSG_LEVEL (SANITIZE
, this->start
, 0, -1,
213 "end [%p..%p] %u edit requests",
214 this->start
, this->end
, this->edit_count
);
216 hb_blob_destroy (this->blob
);
218 this->start
= this->end
= NULL
;
221 inline bool check_range (const void *base
, unsigned int len
) const
223 const char *p
= (const char *) base
;
224 bool ok
= this->start
<= p
&& p
<= this->end
&& (unsigned int) (this->end
- p
) >= len
;
226 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
227 "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
229 this->start
, this->end
,
230 ok
? "OK" : "OUT-OF-RANGE");
235 inline bool check_array (const void *base
, unsigned int record_size
, unsigned int len
) const
237 const char *p
= (const char *) base
;
238 bool overflows
= _hb_unsigned_int_mul_overflows (len
, record_size
);
239 unsigned int array_size
= record_size
* len
;
240 bool ok
= !overflows
&& this->check_range (base
, array_size
);
242 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
243 "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
244 p
, p
+ (record_size
* len
), record_size
, len
, (unsigned int) array_size
,
245 this->start
, this->end
,
246 overflows
? "OVERFLOWS" : ok
? "OK" : "OUT-OF-RANGE");
251 template <typename Type
>
252 inline bool check_struct (const Type
*obj
) const
254 return likely (this->check_range (obj
, obj
->min_size
));
257 inline bool may_edit (const void *base HB_UNUSED
, unsigned int len HB_UNUSED
)
259 if (this->edit_count
>= HB_SANITIZE_MAX_EDITS
)
262 const char *p
= (const char *) base
;
265 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
266 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
269 this->start
, this->end
,
270 this->writable
? "GRANTED" : "DENIED");
272 return this->writable
;
275 template <typename Type
, typename ValueType
>
276 inline bool try_set (const Type
*obj
, const ValueType
&v
) {
277 if (this->may_edit (obj
, obj
->static_size
)) {
278 const_cast<Type
*> (obj
)->set (v
);
284 mutable unsigned int debug_depth
;
285 const char *start
, *end
;
287 unsigned int edit_count
;
293 /* Template to sanitize an object. */
294 template <typename Type
>
297 static hb_blob_t
*sanitize (hb_blob_t
*blob
) {
298 hb_sanitize_context_t c
[1] = {{0, NULL
, NULL
, false, 0, NULL
}};
301 /* TODO is_sane() stuff */
306 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "start");
308 c
->start_processing ();
310 if (unlikely (!c
->start
)) {
311 c
->end_processing ();
315 Type
*t
= CastP
<Type
> (const_cast<char *> (c
->start
));
317 sane
= t
->sanitize (c
);
320 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "passed first round with %d edits; going for second round", c
->edit_count
);
322 /* sanitize again to ensure no toe-stepping */
324 sane
= t
->sanitize (c
);
326 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "requested %d edits in second round; FAILLING", c
->edit_count
);
331 unsigned int edit_count
= c
->edit_count
;
332 if (edit_count
&& !c
->writable
) {
333 c
->start
= hb_blob_get_data_writable (blob
, NULL
);
334 c
->end
= c
->start
+ hb_blob_get_length (blob
);
338 /* ok, we made it writable by relocating. try again */
339 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "retry");
345 c
->end_processing ();
347 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, sane
? "PASSED" : "FAILED");
351 hb_blob_destroy (blob
);
352 return hb_blob_get_empty ();
356 static const Type
* lock_instance (hb_blob_t
*blob
) {
357 hb_blob_make_immutable (blob
);
358 const char *base
= hb_blob_get_data (blob
, NULL
);
359 return unlikely (!base
) ? &Null(Type
) : CastP
<Type
> (base
);
369 #ifndef HB_DEBUG_SERIALIZE
370 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
374 #define TRACE_SERIALIZE(this) \
375 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
376 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
380 struct hb_serialize_context_t
382 inline hb_serialize_context_t (void *start
, unsigned int size
)
384 this->start
= (char *) start
;
385 this->end
= this->start
+ size
;
387 this->ran_out_of_room
= false;
388 this->head
= this->start
;
389 this->debug_depth
= 0;
392 template <typename Type
>
393 inline Type
*start_serialize (void)
395 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, +1,
396 "start [%p..%p] (%lu bytes)",
397 this->start
, this->end
,
398 (unsigned long) (this->end
- this->start
));
400 return start_embed
<Type
> ();
403 inline void end_serialize (void)
405 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, -1,
406 "end [%p..%p] serialized %d bytes; %s",
407 this->start
, this->end
,
408 (int) (this->head
- this->start
),
409 this->ran_out_of_room
? "RAN OUT OF ROOM" : "did not ran out of room");
413 template <typename Type
>
414 inline Type
*copy (void)
416 assert (!this->ran_out_of_room
);
417 unsigned int len
= this->head
- this->start
;
418 void *p
= malloc (len
);
420 memcpy (p
, this->start
, len
);
421 return reinterpret_cast<Type
*> (p
);
424 template <typename Type
>
425 inline Type
*allocate_size (unsigned int size
)
427 if (unlikely (this->ran_out_of_room
|| this->end
- this->head
< ptrdiff_t (size
))) {
428 this->ran_out_of_room
= true;
431 memset (this->head
, 0, size
);
432 char *ret
= this->head
;
434 return reinterpret_cast<Type
*> (ret
);
437 template <typename Type
>
438 inline Type
*allocate_min (void)
440 return this->allocate_size
<Type
> (Type::min_size
);
443 template <typename Type
>
444 inline Type
*start_embed (void)
446 Type
*ret
= reinterpret_cast<Type
*> (this->head
);
450 template <typename Type
>
451 inline Type
*embed (const Type
&obj
)
453 unsigned int size
= obj
.get_size ();
454 Type
*ret
= this->allocate_size
<Type
> (size
);
455 if (unlikely (!ret
)) return NULL
;
456 memcpy (ret
, obj
, size
);
460 template <typename Type
>
461 inline Type
*extend_min (Type
&obj
)
463 unsigned int size
= obj
.min_size
;
464 assert (this->start
<= (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
465 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
466 return reinterpret_cast<Type
*> (&obj
);
469 template <typename Type
>
470 inline Type
*extend (Type
&obj
)
472 unsigned int size
= obj
.get_size ();
473 assert (this->start
< (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
474 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
475 return reinterpret_cast<Type
*> (&obj
);
478 inline void truncate (void *head
)
480 assert (this->start
< head
&& head
<= this->head
);
481 this->head
= (char *) head
;
484 unsigned int debug_depth
;
485 char *start
, *end
, *head
;
486 bool ran_out_of_room
;
489 template <typename Type
>
492 inline Supplier (const Type
*array
, unsigned int len_
)
497 inline const Type
operator [] (unsigned int i
) const
499 if (unlikely (i
>= len
)) return Type ();
503 inline void advance (unsigned int count
)
505 if (unlikely (count
> len
))
512 inline Supplier (const Supplier
<Type
> &); /* Disallow copy */
513 inline Supplier
<Type
>& operator= (const Supplier
<Type
> &); /* Disallow copy */
524 * The OpenType Font File: Data Types
528 /* "The following data types are used in the OpenType font file.
529 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
536 template <typename Type
, int Bytes
> struct BEInt
;
538 template <typename Type
>
539 struct BEInt
<Type
, 2>
542 inline void set (Type V
)
544 v
[0] = (V
>> 8) & 0xFF;
547 inline operator Type (void) const
552 private: uint8_t v
[2];
554 template <typename Type
>
555 struct BEInt
<Type
, 3>
558 inline void set (Type V
)
560 v
[0] = (V
>> 16) & 0xFF;
561 v
[1] = (V
>> 8) & 0xFF;
564 inline operator Type (void) const
570 private: uint8_t v
[3];
572 template <typename Type
>
573 struct BEInt
<Type
, 4>
576 inline void set (Type V
)
578 v
[0] = (V
>> 24) & 0xFF;
579 v
[1] = (V
>> 16) & 0xFF;
580 v
[2] = (V
>> 8) & 0xFF;
583 inline operator Type (void) const
590 private: uint8_t v
[4];
593 /* Integer types in big-endian order and no alignment requirement */
594 template <typename Type
, unsigned int Size
>
597 inline void set (Type i
) { v
.set (i
); }
598 inline operator Type(void) const { return v
; }
599 inline bool operator == (const IntType
<Type
,Size
> &o
) const { return (Type
) v
== (Type
) o
.v
; }
600 inline bool operator != (const IntType
<Type
,Size
> &o
) const { return !(*this == o
); }
601 static inline int cmp (const IntType
<Type
,Size
> *a
, const IntType
<Type
,Size
> *b
) { return b
->cmp (*a
); }
602 inline int cmp (Type a
) const
605 if (sizeof (Type
) < sizeof (int))
606 return (int) a
- (int) b
;
608 return a
< b
? -1 : a
== b
? 0 : +1;
610 inline bool sanitize (hb_sanitize_context_t
*c
) const
612 TRACE_SANITIZE (this);
613 return TRACE_RETURN (likely (c
->check_struct (this)));
618 DEFINE_SIZE_STATIC (Size
);
621 typedef uint8_t BYTE
; /* 8-bit unsigned integer. */
622 typedef IntType
<uint16_t, 2> USHORT
; /* 16-bit unsigned integer. */
623 typedef IntType
<int16_t, 2> SHORT
; /* 16-bit signed integer. */
624 typedef IntType
<uint32_t, 4> ULONG
; /* 32-bit unsigned integer. */
625 typedef IntType
<int32_t, 4> LONG
; /* 32-bit signed integer. */
626 typedef IntType
<uint32_t, 3> UINT24
; /* 24-bit unsigned integer. */
628 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
631 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
632 typedef USHORT UFWORD
;
634 /* Date represented in number of seconds since 12:00 midnight, January 1,
635 * 1904. The value is represented as a signed 64-bit integer. */
638 inline bool sanitize (hb_sanitize_context_t
*c
) const
640 TRACE_SANITIZE (this);
641 return TRACE_RETURN (likely (c
->check_struct (this)));
647 DEFINE_SIZE_STATIC (8);
650 /* Array of four uint8s (length = 32 bits) used to identify a script, language
651 * system, feature, or baseline */
654 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
655 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v
); }
656 inline operator char* (void) { return reinterpret_cast<char *> (&this->v
); }
658 DEFINE_SIZE_STATIC (4);
660 DEFINE_NULL_DATA (Tag
, " ");
662 /* Glyph index number, same as uint16 (length = 16 bits) */
663 struct GlyphID
: USHORT
{
664 static inline int cmp (const GlyphID
*a
, const GlyphID
*b
) { return b
->USHORT::cmp (*a
); }
665 inline int cmp (hb_codepoint_t a
) const { return (int) a
- (int) *this; }
668 /* Script/language-system/feature index */
669 struct Index
: USHORT
{
670 static const unsigned int NOT_FOUND_INDEX
= 0xFFFFu
;
672 DEFINE_NULL_DATA (Index
, "\xff\xff");
674 /* Offset, Null offset = 0 */
675 template <typename Type
=USHORT
>
678 inline bool is_null (void) const { return 0 == *this; }
680 DEFINE_SIZE_STATIC (sizeof(Type
));
685 struct CheckSum
: ULONG
687 /* This is reference implementation from the spec. */
688 static inline uint32_t CalcTableChecksum (const ULONG
*Table
, uint32_t Length
)
691 const ULONG
*EndPtr
= Table
+((Length
+3) & ~3) / ULONG::static_size
;
693 while (Table
< EndPtr
)
698 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
699 inline void set_for_data (const void *data
, unsigned int length
)
700 { set (CalcTableChecksum ((const ULONG
*) data
, length
)); }
703 DEFINE_SIZE_STATIC (4);
713 inline uint32_t to_int (void) const { return (major
<< 16) + minor
; }
715 inline bool sanitize (hb_sanitize_context_t
*c
) const
717 TRACE_SANITIZE (this);
718 return TRACE_RETURN (c
->check_struct (this));
724 DEFINE_SIZE_STATIC (4);
730 * Template subclasses of Offset that do the dereferencing.
734 template <typename Type
, typename OffsetType
=USHORT
>
735 struct OffsetTo
: Offset
<OffsetType
>
737 inline const Type
& operator () (const void *base
) const
739 unsigned int offset
= *this;
740 if (unlikely (!offset
)) return Null(Type
);
741 return StructAtOffset
<Type
> (base
, offset
);
744 inline Type
& serialize (hb_serialize_context_t
*c
, const void *base
)
746 Type
*t
= c
->start_embed
<Type
> ();
747 this->set ((char *) t
- (char *) base
); /* TODO(serialize) Overflow? */
751 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
753 TRACE_SANITIZE (this);
754 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
755 unsigned int offset
= *this;
756 if (unlikely (!offset
)) return TRACE_RETURN (true);
757 const Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
758 return TRACE_RETURN (likely (obj
.sanitize (c
)) || neuter (c
));
760 template <typename T
>
761 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
, T user_data
) const
763 TRACE_SANITIZE (this);
764 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
765 unsigned int offset
= *this;
766 if (unlikely (!offset
)) return TRACE_RETURN (true);
767 const Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
768 return TRACE_RETURN (likely (obj
.sanitize (c
, user_data
)) || neuter (c
));
771 /* Set the offset to Null */
772 inline bool neuter (hb_sanitize_context_t
*c
) const {
773 return c
->try_set (this, 0);
775 DEFINE_SIZE_STATIC (sizeof(OffsetType
));
777 template <typename Base
, typename OffsetType
, typename Type
>
778 static inline const Type
& operator + (const Base
&base
, const OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
779 template <typename Base
, typename OffsetType
, typename Type
>
780 static inline Type
& operator + (Base
&base
, OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
787 /* An array with a number of elements. */
788 template <typename Type
, typename LenType
=USHORT
>
791 const Type
*sub_array (unsigned int start_offset
, unsigned int *pcount
/* IN/OUT */) const
793 unsigned int count
= len
;
794 if (unlikely (start_offset
> count
))
797 count
-= start_offset
;
798 count
= MIN (count
, *pcount
);
800 return array
+ start_offset
;
803 inline const Type
& operator [] (unsigned int i
) const
805 if (unlikely (i
>= len
)) return Null(Type
);
808 inline Type
& operator [] (unsigned int i
)
812 inline unsigned int get_size (void) const
813 { return len
.static_size
+ len
* Type::static_size
; }
815 inline bool serialize (hb_serialize_context_t
*c
,
816 unsigned int items_len
)
818 TRACE_SERIALIZE (this);
819 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
820 len
.set (items_len
); /* TODO(serialize) Overflow? */
821 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
822 return TRACE_RETURN (true);
825 inline bool serialize (hb_serialize_context_t
*c
,
826 Supplier
<Type
> &items
,
827 unsigned int items_len
)
829 TRACE_SERIALIZE (this);
830 if (unlikely (!serialize (c
, items_len
))) return TRACE_RETURN (false);
831 for (unsigned int i
= 0; i
< items_len
; i
++)
833 items
.advance (items_len
);
834 return TRACE_RETURN (true);
837 inline bool sanitize (hb_sanitize_context_t
*c
) const
839 TRACE_SANITIZE (this);
840 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
842 /* Note: for structs that do not reference other structs,
843 * we do not need to call their sanitize() as we already did
844 * a bound check on the aggregate array size. We just include
845 * a small unreachable expression to make sure the structs
846 * pointed to do have a simple sanitize(), ie. they do not
847 * reference other structs via offsets.
849 (void) (false && array
[0].sanitize (c
));
851 return TRACE_RETURN (true);
853 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
855 TRACE_SANITIZE (this);
856 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
857 unsigned int count
= len
;
858 for (unsigned int i
= 0; i
< count
; i
++)
859 if (unlikely (!array
[i
].sanitize (c
, base
)))
860 return TRACE_RETURN (false);
861 return TRACE_RETURN (true);
863 template <typename T
>
864 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
, T user_data
) const
866 TRACE_SANITIZE (this);
867 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
868 unsigned int count
= len
;
869 for (unsigned int i
= 0; i
< count
; i
++)
870 if (unlikely (!array
[i
].sanitize (c
, base
, user_data
)))
871 return TRACE_RETURN (false);
872 return TRACE_RETURN (true);
875 template <typename SearchType
>
876 inline int lsearch (const SearchType
&x
) const
878 unsigned int count
= len
;
879 for (unsigned int i
= 0; i
< count
; i
++)
880 if (!this->array
[i
].cmp (x
))
886 inline bool sanitize_shallow (hb_sanitize_context_t
*c
) const
888 TRACE_SANITIZE (this);
889 return TRACE_RETURN (c
->check_struct (this) && c
->check_array (this, Type::static_size
, len
));
896 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
899 /* Array of Offset's */
900 template <typename Type
>
901 struct OffsetArrayOf
: ArrayOf
<OffsetTo
<Type
> > {};
903 /* Array of offsets relative to the beginning of the array itself. */
904 template <typename Type
>
905 struct OffsetListOf
: OffsetArrayOf
<Type
>
907 inline const Type
& operator [] (unsigned int i
) const
909 if (unlikely (i
>= this->len
)) return Null(Type
);
910 return this+this->array
[i
];
913 inline bool sanitize (hb_sanitize_context_t
*c
) const
915 TRACE_SANITIZE (this);
916 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this));
918 template <typename T
>
919 inline bool sanitize (hb_sanitize_context_t
*c
, T user_data
) const
921 TRACE_SANITIZE (this);
922 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this, user_data
));
927 /* An array starting at second element. */
928 template <typename Type
, typename LenType
=USHORT
>
929 struct HeadlessArrayOf
931 inline const Type
& operator [] (unsigned int i
) const
933 if (unlikely (i
>= len
|| !i
)) return Null(Type
);
936 inline unsigned int get_size (void) const
937 { return len
.static_size
+ (len
? len
- 1 : 0) * Type::static_size
; }
939 inline bool serialize (hb_serialize_context_t
*c
,
940 Supplier
<Type
> &items
,
941 unsigned int items_len
)
943 TRACE_SERIALIZE (this);
944 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
945 len
.set (items_len
); /* TODO(serialize) Overflow? */
946 if (unlikely (!items_len
)) return TRACE_RETURN (true);
947 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
948 for (unsigned int i
= 0; i
< items_len
- 1; i
++)
950 items
.advance (items_len
- 1);
951 return TRACE_RETURN (true);
954 inline bool sanitize_shallow (hb_sanitize_context_t
*c
) const
956 return c
->check_struct (this)
957 && c
->check_array (this, Type::static_size
, len
);
960 inline bool sanitize (hb_sanitize_context_t
*c
) const
962 TRACE_SANITIZE (this);
963 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
965 /* Note: for structs that do not reference other structs,
966 * we do not need to call their sanitize() as we already did
967 * a bound check on the aggregate array size. We just include
968 * a small unreachable expression to make sure the structs
969 * pointed to do have a simple sanitize(), ie. they do not
970 * reference other structs via offsets.
972 (void) (false && array
[0].sanitize (c
));
974 return TRACE_RETURN (true);
980 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
984 /* An array with sorted elements. Supports binary searching. */
985 template <typename Type
, typename LenType
=USHORT
>
986 struct SortedArrayOf
: ArrayOf
<Type
, LenType
>
988 template <typename SearchType
>
989 inline int bsearch (const SearchType
&x
) const
991 /* Hand-coded bsearch here since this is in the hot inner loop. */
992 int min
= 0, max
= (int) this->len
- 1;
995 int mid
= (min
+ max
) / 2;
996 int c
= this->array
[mid
].cmp (x
);
1009 } /* namespace OT */
1012 #endif /* HB_OPEN_TYPE_PRIVATE_HH */