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
>
183 inline return_t
dispatch (const T
&obj
) { return obj
.sanitize (this); }
184 static return_t
default_return_value (void) { return true; }
185 bool stop_sublookup_iteration (const return_t r HB_UNUSED
) const { return false; }
187 inline void init (hb_blob_t
*b
)
189 this->blob
= hb_blob_reference (b
);
190 this->writable
= false;
193 inline void start_processing (void)
195 this->start
= hb_blob_get_data (this->blob
, NULL
);
196 this->end
= this->start
+ hb_blob_get_length (this->blob
);
197 this->edit_count
= 0;
198 this->debug_depth
= 0;
200 DEBUG_MSG_LEVEL (SANITIZE
, this->blob
, 0, +1,
201 "start [%p..%p] (%lu bytes)",
202 this->start
, this->end
,
203 (unsigned long) (this->end
- this->start
));
206 inline void end_processing (void)
208 DEBUG_MSG_LEVEL (SANITIZE
, this->blob
, 0, -1,
209 "end [%p..%p] %u edit requests",
210 this->start
, this->end
, this->edit_count
);
212 hb_blob_destroy (this->blob
);
214 this->start
= this->end
= NULL
;
217 inline bool check_range (const void *base
, unsigned int len
) const
219 const char *p
= (const char *) base
;
221 hb_auto_trace_t
<HB_DEBUG_SANITIZE
, bool> trace
222 (&this->debug_depth
, "SANITIZE", this->blob
, NULL
,
223 "check_range [%p..%p] (%d bytes) in [%p..%p]",
225 this->start
, this->end
);
227 return TRACE_RETURN (likely (this->start
<= p
&& p
<= this->end
&& (unsigned int) (this->end
- p
) >= len
));
230 inline bool check_array (const void *base
, unsigned int record_size
, unsigned int len
) const
232 const char *p
= (const char *) base
;
233 bool overflows
= _hb_unsigned_int_mul_overflows (len
, record_size
);
235 hb_auto_trace_t
<HB_DEBUG_SANITIZE
, bool> trace
236 (&this->debug_depth
, "SANITIZE", this->blob
, NULL
,
237 "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
238 p
, p
+ (record_size
* len
), record_size
, len
, (unsigned long) record_size
* len
,
239 this->start
, this->end
);
241 return TRACE_RETURN (likely (!overflows
&& this->check_range (base
, record_size
* len
)));
244 template <typename Type
>
245 inline bool check_struct (const Type
*obj
) const
247 return likely (this->check_range (obj
, obj
->min_size
));
250 inline bool may_edit (const void *base HB_UNUSED
, unsigned int len HB_UNUSED
)
252 if (this->edit_count
>= HB_SANITIZE_MAX_EDITS
)
255 const char *p
= (const char *) base
;
258 hb_auto_trace_t
<HB_DEBUG_SANITIZE
, bool> trace
259 (&this->debug_depth
, "SANITIZE", this->blob
, NULL
,
260 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
263 this->start
, this->end
,
264 this->writable
? "GRANTED" : "DENIED");
266 return TRACE_RETURN (this->writable
);
269 template <typename Type
, typename ValueType
>
270 inline bool try_set (Type
*obj
, const ValueType
&v
) {
271 if (this->may_edit (obj
, obj
->static_size
)) {
278 mutable unsigned int debug_depth
;
279 const char *start
, *end
;
281 unsigned int edit_count
;
287 /* Template to sanitize an object. */
288 template <typename Type
>
291 static hb_blob_t
*sanitize (hb_blob_t
*blob
) {
292 hb_sanitize_context_t c
[1] = {{0, NULL
, NULL
, false, 0, NULL
}};
295 /* TODO is_sane() stuff */
300 DEBUG_MSG_FUNC (SANITIZE
, blob
, "start");
302 c
->start_processing ();
304 if (unlikely (!c
->start
)) {
305 c
->end_processing ();
309 Type
*t
= CastP
<Type
> (const_cast<char *> (c
->start
));
311 sane
= t
->sanitize (c
);
314 DEBUG_MSG_FUNC (SANITIZE
, blob
, "passed first round with %d edits; going for second round", c
->edit_count
);
316 /* sanitize again to ensure no toe-stepping */
318 sane
= t
->sanitize (c
);
320 DEBUG_MSG_FUNC (SANITIZE
, blob
, "requested %d edits in second round; FAILLING", c
->edit_count
);
325 unsigned int edit_count
= c
->edit_count
;
326 if (edit_count
&& !c
->writable
) {
327 c
->start
= hb_blob_get_data_writable (blob
, NULL
);
328 c
->end
= c
->start
+ hb_blob_get_length (blob
);
332 /* ok, we made it writable by relocating. try again */
333 DEBUG_MSG_FUNC (SANITIZE
, blob
, "retry");
339 c
->end_processing ();
341 DEBUG_MSG_FUNC (SANITIZE
, blob
, sane
? "PASSED" : "FAILED");
345 hb_blob_destroy (blob
);
346 return hb_blob_get_empty ();
350 static const Type
* lock_instance (hb_blob_t
*blob
) {
351 hb_blob_make_immutable (blob
);
352 const char *base
= hb_blob_get_data (blob
, NULL
);
353 return unlikely (!base
) ? &Null(Type
) : CastP
<Type
> (base
);
363 #ifndef HB_DEBUG_SERIALIZE
364 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
368 #define TRACE_SERIALIZE(this) \
369 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
370 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
374 struct hb_serialize_context_t
376 inline hb_serialize_context_t (void *start
, unsigned int size
)
378 this->start
= (char *) start
;
379 this->end
= this->start
+ size
;
381 this->ran_out_of_room
= false;
382 this->head
= this->start
;
383 this->debug_depth
= 0;
386 template <typename Type
>
387 inline Type
*start_serialize (void)
389 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, +1,
390 "start [%p..%p] (%lu bytes)",
391 this->start
, this->end
,
392 (unsigned long) (this->end
- this->start
));
394 return start_embed
<Type
> ();
397 inline void end_serialize (void)
399 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, -1,
400 "end [%p..%p] serialized %d bytes; %s",
401 this->start
, this->end
,
402 (int) (this->head
- this->start
),
403 this->ran_out_of_room
? "RAN OUT OF ROOM" : "did not ran out of room");
407 template <typename Type
>
408 inline Type
*copy (void)
410 assert (!this->ran_out_of_room
);
411 unsigned int len
= this->head
- this->start
;
412 void *p
= malloc (len
);
414 memcpy (p
, this->start
, len
);
415 return reinterpret_cast<Type
*> (p
);
418 template <typename Type
>
419 inline Type
*allocate_size (unsigned int size
)
421 if (unlikely (this->ran_out_of_room
|| this->end
- this->head
< ptrdiff_t (size
))) {
422 this->ran_out_of_room
= true;
425 memset (this->head
, 0, size
);
426 char *ret
= this->head
;
428 return reinterpret_cast<Type
*> (ret
);
431 template <typename Type
>
432 inline Type
*allocate_min (void)
434 return this->allocate_size
<Type
> (Type::min_size
);
437 template <typename Type
>
438 inline Type
*start_embed (void)
440 Type
*ret
= reinterpret_cast<Type
*> (this->head
);
444 template <typename Type
>
445 inline Type
*embed (const Type
&obj
)
447 unsigned int size
= obj
.get_size ();
448 Type
*ret
= this->allocate_size
<Type
> (size
);
449 if (unlikely (!ret
)) return NULL
;
450 memcpy (ret
, obj
, size
);
454 template <typename Type
>
455 inline Type
*extend_min (Type
&obj
)
457 unsigned int size
= obj
.min_size
;
458 assert (this->start
<= (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
459 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
460 return reinterpret_cast<Type
*> (&obj
);
463 template <typename Type
>
464 inline Type
*extend (Type
&obj
)
466 unsigned int size
= obj
.get_size ();
467 assert (this->start
< (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
468 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
469 return reinterpret_cast<Type
*> (&obj
);
472 inline void truncate (void *head
)
474 assert (this->start
< head
&& head
<= this->head
);
475 this->head
= (char *) head
;
478 unsigned int debug_depth
;
479 char *start
, *end
, *head
;
480 bool ran_out_of_room
;
483 template <typename Type
>
486 inline Supplier (const Type
*array
, unsigned int len_
)
491 inline const Type
operator [] (unsigned int i
) const
493 if (unlikely (i
>= len
)) return Type ();
497 inline void advance (unsigned int count
)
499 if (unlikely (count
> len
))
506 inline Supplier (const Supplier
<Type
> &); /* Disallow copy */
507 inline Supplier
<Type
>& operator= (const Supplier
<Type
> &); /* Disallow copy */
518 * The OpenType Font File: Data Types
522 /* "The following data types are used in the OpenType font file.
523 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
530 template <typename Type
, int Bytes
> struct BEInt
;
532 template <typename Type
>
533 struct BEInt
<Type
, 2>
536 inline void set (Type i
) { hb_be_uint16_put (v
,i
); }
537 inline operator Type (void) const { return hb_be_uint16_get (v
); }
538 inline bool operator == (const BEInt
<Type
, 2>& o
) const { return hb_be_uint16_eq (v
, o
.v
); }
539 inline bool operator != (const BEInt
<Type
, 2>& o
) const { return !(*this == o
); }
540 private: uint8_t v
[2];
542 template <typename Type
>
543 struct BEInt
<Type
, 4>
546 inline void set (Type i
) { hb_be_uint32_put (v
,i
); }
547 inline operator Type (void) const { return hb_be_uint32_get (v
); }
548 inline bool operator == (const BEInt
<Type
, 4>& o
) const { return hb_be_uint32_eq (v
, o
.v
); }
549 inline bool operator != (const BEInt
<Type
, 4>& o
) const { return !(*this == o
); }
550 private: uint8_t v
[4];
552 template <typename Type
>
553 struct BEInt
<Type
, 3>
556 inline void set (Type i
) { hb_be_uint24_put (v
,i
); }
557 inline operator Type (void) const { return hb_be_uint24_get (v
); }
558 inline bool operator == (const BEInt
<Type
, 3>& o
) const { return hb_be_uint24_eq (v
, o
.v
); }
559 inline bool operator != (const BEInt
<Type
, 3>& o
) const { return !(*this == o
); }
560 private: uint8_t v
[3];
563 /* Integer types in big-endian order and no alignment requirement */
564 template <typename Type
, unsigned int Size
>
567 inline void set (Type i
) { v
.set (i
); }
568 inline operator Type(void) const { return v
; }
569 inline bool operator == (const IntType
<Type
,Size
> &o
) const { return v
== o
.v
; }
570 inline bool operator != (const IntType
<Type
,Size
> &o
) const { return v
!= o
.v
; }
571 static inline int cmp (const IntType
<Type
,Size
> *a
, const IntType
<Type
,Size
> *b
) { return b
->cmp (*a
); }
572 inline int cmp (IntType
<Type
,Size
> va
) const { Type a
= va
; Type b
= v
; return a
< b
? -1 : a
== b
? 0 : +1; }
573 inline int cmp (Type a
) const { Type b
= v
; return a
< b
? -1 : a
== b
? 0 : +1; }
574 inline bool sanitize (hb_sanitize_context_t
*c
) {
575 TRACE_SANITIZE (this);
576 return TRACE_RETURN (likely (c
->check_struct (this)));
581 DEFINE_SIZE_STATIC (Size
);
584 typedef uint8_t BYTE
; /* 8-bit unsigned integer. */
585 typedef IntType
<uint16_t, 2> USHORT
; /* 16-bit unsigned integer. */
586 typedef IntType
<int16_t, 2> SHORT
; /* 16-bit signed integer. */
587 typedef IntType
<uint32_t, 4> ULONG
; /* 32-bit unsigned integer. */
588 typedef IntType
<int32_t, 4> LONG
; /* 32-bit signed integer. */
589 typedef IntType
<uint32_t, 3> UINT24
; /* 24-bit unsigned integer. */
591 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
594 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
595 typedef USHORT UFWORD
;
597 /* Date represented in number of seconds since 12:00 midnight, January 1,
598 * 1904. The value is represented as a signed 64-bit integer. */
601 inline bool sanitize (hb_sanitize_context_t
*c
) {
602 TRACE_SANITIZE (this);
603 return TRACE_RETURN (likely (c
->check_struct (this)));
609 DEFINE_SIZE_STATIC (8);
612 /* Array of four uint8s (length = 32 bits) used to identify a script, language
613 * system, feature, or baseline */
616 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
617 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v
); }
618 inline operator char* (void) { return reinterpret_cast<char *> (&this->v
); }
620 DEFINE_SIZE_STATIC (4);
622 DEFINE_NULL_DATA (Tag
, " ");
624 /* Glyph index number, same as uint16 (length = 16 bits) */
625 typedef USHORT GlyphID
;
627 /* Script/language-system/feature index */
628 struct Index
: USHORT
{
629 static const unsigned int NOT_FOUND_INDEX
= 0xFFFFu
;
631 DEFINE_NULL_DATA (Index
, "\xff\xff");
633 /* Offset, Null offset = 0 */
634 template <typename Type
=USHORT
>
637 inline bool is_null (void) const { return 0 == *this; }
639 DEFINE_SIZE_STATIC (sizeof(Type
));
644 struct CheckSum
: ULONG
646 /* This is reference implementation from the spec. */
647 static inline uint32_t CalcTableChecksum (const ULONG
*Table
, uint32_t Length
)
650 const ULONG
*EndPtr
= Table
+((Length
+3) & ~3) / ULONG::static_size
;
652 while (Table
< EndPtr
)
657 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
658 inline void set_for_data (const void *data
, unsigned int length
)
659 { set (CalcTableChecksum ((const ULONG
*) data
, length
)); }
662 DEFINE_SIZE_STATIC (4);
672 inline uint32_t to_int (void) const { return (major
<< 16) + minor
; }
674 inline bool sanitize (hb_sanitize_context_t
*c
) {
675 TRACE_SANITIZE (this);
676 return TRACE_RETURN (c
->check_struct (this));
682 DEFINE_SIZE_STATIC (4);
688 * Template subclasses of Offset that do the dereferencing.
692 template <typename Type
, typename OffsetType
=USHORT
>
693 struct OffsetTo
: Offset
<OffsetType
>
695 inline const Type
& operator () (const void *base
) const
697 unsigned int offset
= *this;
698 if (unlikely (!offset
)) return Null(Type
);
699 return StructAtOffset
<Type
> (base
, offset
);
702 inline Type
& serialize (hb_serialize_context_t
*c
, void *base
)
704 Type
*t
= c
->start_embed
<Type
> ();
705 this->set ((char *) t
- (char *) base
); /* TODO(serialize) Overflow? */
709 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
710 TRACE_SANITIZE (this);
711 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
712 unsigned int offset
= *this;
713 if (unlikely (!offset
)) return TRACE_RETURN (true);
714 Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
715 return TRACE_RETURN (likely (obj
.sanitize (c
)) || neuter (c
));
717 template <typename T
>
718 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
, T user_data
) {
719 TRACE_SANITIZE (this);
720 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
721 unsigned int offset
= *this;
722 if (unlikely (!offset
)) return TRACE_RETURN (true);
723 Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
724 return TRACE_RETURN (likely (obj
.sanitize (c
, user_data
)) || neuter (c
));
727 /* Set the offset to Null */
728 inline bool neuter (hb_sanitize_context_t
*c
) {
729 return c
->try_set (this, 0);
731 DEFINE_SIZE_STATIC (sizeof(OffsetType
));
733 template <typename Base
, typename OffsetType
, typename Type
>
734 static inline const Type
& operator + (const Base
&base
, const OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
735 template <typename Base
, typename OffsetType
, typename Type
>
736 static inline Type
& operator + (Base
&base
, OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
743 /* An array with a number of elements. */
744 template <typename Type
, typename LenType
=USHORT
>
747 const Type
*sub_array (unsigned int start_offset
, unsigned int *pcount
/* IN/OUT */) const
749 unsigned int count
= len
;
750 if (unlikely (start_offset
> count
))
753 count
-= start_offset
;
754 count
= MIN (count
, *pcount
);
756 return array
+ start_offset
;
759 inline const Type
& operator [] (unsigned int i
) const
761 if (unlikely (i
>= len
)) return Null(Type
);
764 inline Type
& operator [] (unsigned int i
)
768 inline unsigned int get_size (void) const
769 { return len
.static_size
+ len
* Type::static_size
; }
771 inline bool serialize (hb_serialize_context_t
*c
,
772 unsigned int items_len
)
774 TRACE_SERIALIZE (this);
775 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
776 len
.set (items_len
); /* TODO(serialize) Overflow? */
777 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
778 return TRACE_RETURN (true);
781 inline bool serialize (hb_serialize_context_t
*c
,
782 Supplier
<Type
> &items
,
783 unsigned int items_len
)
785 TRACE_SERIALIZE (this);
786 if (unlikely (!serialize (c
, items_len
))) return TRACE_RETURN (false);
787 for (unsigned int i
= 0; i
< items_len
; i
++)
789 items
.advance (items_len
);
790 return TRACE_RETURN (true);
793 inline bool sanitize (hb_sanitize_context_t
*c
) {
794 TRACE_SANITIZE (this);
795 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
797 /* Note: for structs that do not reference other structs,
798 * we do not need to call their sanitize() as we already did
799 * a bound check on the aggregate array size. We just include
800 * a small unreachable expression to make sure the structs
801 * pointed to do have a simple sanitize(), ie. they do not
802 * reference other structs via offsets.
804 (void) (false && array
[0].sanitize (c
));
806 return TRACE_RETURN (true);
808 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
809 TRACE_SANITIZE (this);
810 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
811 unsigned int count
= len
;
812 for (unsigned int i
= 0; i
< count
; i
++)
813 if (unlikely (!array
[i
].sanitize (c
, base
)))
814 return TRACE_RETURN (false);
815 return TRACE_RETURN (true);
817 template <typename T
>
818 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
, T user_data
) {
819 TRACE_SANITIZE (this);
820 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
821 unsigned int count
= len
;
822 for (unsigned int i
= 0; i
< count
; i
++)
823 if (unlikely (!array
[i
].sanitize (c
, base
, user_data
)))
824 return TRACE_RETURN (false);
825 return TRACE_RETURN (true);
828 template <typename SearchType
>
829 inline int lsearch (const SearchType
&x
) const
831 unsigned int count
= len
;
832 for (unsigned int i
= 0; i
< count
; i
++)
833 if (!this->array
[i
].cmp (x
))
839 inline bool sanitize_shallow (hb_sanitize_context_t
*c
) {
840 TRACE_SANITIZE (this);
841 return TRACE_RETURN (c
->check_struct (this) && c
->check_array (this, Type::static_size
, len
));
848 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
851 /* Array of Offset's */
852 template <typename Type
>
853 struct OffsetArrayOf
: ArrayOf
<OffsetTo
<Type
> > {};
855 /* Array of offsets relative to the beginning of the array itself. */
856 template <typename Type
>
857 struct OffsetListOf
: OffsetArrayOf
<Type
>
859 inline const Type
& operator [] (unsigned int i
) const
861 if (unlikely (i
>= this->len
)) return Null(Type
);
862 return this+this->array
[i
];
865 inline bool sanitize (hb_sanitize_context_t
*c
) {
866 TRACE_SANITIZE (this);
867 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this));
869 template <typename T
>
870 inline bool sanitize (hb_sanitize_context_t
*c
, T user_data
) {
871 TRACE_SANITIZE (this);
872 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this, user_data
));
877 /* An array starting at second element. */
878 template <typename Type
, typename LenType
=USHORT
>
879 struct HeadlessArrayOf
881 inline const Type
& operator [] (unsigned int i
) const
883 if (unlikely (i
>= len
|| !i
)) return Null(Type
);
886 inline unsigned int get_size (void) const
887 { return len
.static_size
+ (len
? len
- 1 : 0) * Type::static_size
; }
889 inline bool serialize (hb_serialize_context_t
*c
,
890 Supplier
<Type
> &items
,
891 unsigned int items_len
)
893 TRACE_SERIALIZE (this);
894 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
895 len
.set (items_len
); /* TODO(serialize) Overflow? */
896 if (unlikely (!items_len
)) return TRACE_RETURN (true);
897 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
898 for (unsigned int i
= 0; i
< items_len
- 1; i
++)
900 items
.advance (items_len
- 1);
901 return TRACE_RETURN (true);
904 inline bool sanitize_shallow (hb_sanitize_context_t
*c
) {
905 return c
->check_struct (this)
906 && c
->check_array (this, Type::static_size
, len
);
909 inline bool sanitize (hb_sanitize_context_t
*c
) {
910 TRACE_SANITIZE (this);
911 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
913 /* Note: for structs that do not reference other structs,
914 * we do not need to call their sanitize() as we already did
915 * a bound check on the aggregate array size. We just include
916 * a small unreachable expression to make sure the structs
917 * pointed to do have a simple sanitize(), ie. they do not
918 * reference other structs via offsets.
920 (void) (false && array
[0].sanitize (c
));
922 return TRACE_RETURN (true);
928 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
932 /* An array with sorted elements. Supports binary searching. */
933 template <typename Type
, typename LenType
=USHORT
>
934 struct SortedArrayOf
: ArrayOf
<Type
, LenType
>
936 template <typename SearchType
>
937 inline int bsearch (const SearchType
&x
) const
939 /* Hand-coded bsearch here since this is in the hot inner loop. */
940 int min
= 0, max
= (int) this->len
- 1;
943 int mid
= (min
+ max
) / 2;
944 int c
= this->array
[mid
].cmp (x
);
960 #endif /* HB_OPEN_TYPE_PRIVATE_HH */