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
, start
, 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->start
, 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
;
220 bool ok
= this->start
<= p
&& p
<= this->end
&& (unsigned int) (this->end
- p
) >= len
;
222 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
223 "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
225 this->start
, this->end
,
226 ok
? "OK" : "OUT-OF-RANGE");
231 inline bool check_array (const void *base
, unsigned int record_size
, unsigned int len
) const
233 const char *p
= (const char *) base
;
234 bool overflows
= _hb_unsigned_int_mul_overflows (len
, record_size
);
235 unsigned int array_size
= record_size
* len
;
236 bool ok
= !overflows
&& this->check_range (base
, array_size
);
238 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
239 "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
240 p
, p
+ (record_size
* len
), record_size
, len
, (unsigned int) array_size
,
241 this->start
, this->end
,
242 overflows
? "OVERFLOWS" : ok
? "OK" : "OUT-OF-RANGE");
247 template <typename Type
>
248 inline bool check_struct (const Type
*obj
) const
250 return likely (this->check_range (obj
, obj
->min_size
));
253 inline bool may_edit (const void *base HB_UNUSED
, unsigned int len HB_UNUSED
)
255 if (this->edit_count
>= HB_SANITIZE_MAX_EDITS
)
258 const char *p
= (const char *) base
;
261 DEBUG_MSG_LEVEL (SANITIZE
, p
, this->debug_depth
+1, 0,
262 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
265 this->start
, this->end
,
266 this->writable
? "GRANTED" : "DENIED");
268 return this->writable
;
271 template <typename Type
, typename ValueType
>
272 inline bool try_set (Type
*obj
, const ValueType
&v
) {
273 if (this->may_edit (obj
, obj
->static_size
)) {
280 mutable unsigned int debug_depth
;
281 const char *start
, *end
;
283 unsigned int edit_count
;
289 /* Template to sanitize an object. */
290 template <typename Type
>
293 static hb_blob_t
*sanitize (hb_blob_t
*blob
) {
294 hb_sanitize_context_t c
[1] = {{0, NULL
, NULL
, false, 0, NULL
}};
297 /* TODO is_sane() stuff */
302 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "start");
304 c
->start_processing ();
306 if (unlikely (!c
->start
)) {
307 c
->end_processing ();
311 Type
*t
= CastP
<Type
> (const_cast<char *> (c
->start
));
313 sane
= t
->sanitize (c
);
316 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "passed first round with %d edits; going for second round", c
->edit_count
);
318 /* sanitize again to ensure no toe-stepping */
320 sane
= t
->sanitize (c
);
322 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "requested %d edits in second round; FAILLING", c
->edit_count
);
327 unsigned int edit_count
= c
->edit_count
;
328 if (edit_count
&& !c
->writable
) {
329 c
->start
= hb_blob_get_data_writable (blob
, NULL
);
330 c
->end
= c
->start
+ hb_blob_get_length (blob
);
334 /* ok, we made it writable by relocating. try again */
335 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, "retry");
341 c
->end_processing ();
343 DEBUG_MSG_FUNC (SANITIZE
, c
->start
, sane
? "PASSED" : "FAILED");
347 hb_blob_destroy (blob
);
348 return hb_blob_get_empty ();
352 static const Type
* lock_instance (hb_blob_t
*blob
) {
353 hb_blob_make_immutable (blob
);
354 const char *base
= hb_blob_get_data (blob
, NULL
);
355 return unlikely (!base
) ? &Null(Type
) : CastP
<Type
> (base
);
365 #ifndef HB_DEBUG_SERIALIZE
366 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
370 #define TRACE_SERIALIZE(this) \
371 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
372 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
376 struct hb_serialize_context_t
378 inline hb_serialize_context_t (void *start
, unsigned int size
)
380 this->start
= (char *) start
;
381 this->end
= this->start
+ size
;
383 this->ran_out_of_room
= false;
384 this->head
= this->start
;
385 this->debug_depth
= 0;
388 template <typename Type
>
389 inline Type
*start_serialize (void)
391 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, +1,
392 "start [%p..%p] (%lu bytes)",
393 this->start
, this->end
,
394 (unsigned long) (this->end
- this->start
));
396 return start_embed
<Type
> ();
399 inline void end_serialize (void)
401 DEBUG_MSG_LEVEL (SERIALIZE
, this->start
, 0, -1,
402 "end [%p..%p] serialized %d bytes; %s",
403 this->start
, this->end
,
404 (int) (this->head
- this->start
),
405 this->ran_out_of_room
? "RAN OUT OF ROOM" : "did not ran out of room");
409 template <typename Type
>
410 inline Type
*copy (void)
412 assert (!this->ran_out_of_room
);
413 unsigned int len
= this->head
- this->start
;
414 void *p
= malloc (len
);
416 memcpy (p
, this->start
, len
);
417 return reinterpret_cast<Type
*> (p
);
420 template <typename Type
>
421 inline Type
*allocate_size (unsigned int size
)
423 if (unlikely (this->ran_out_of_room
|| this->end
- this->head
< ptrdiff_t (size
))) {
424 this->ran_out_of_room
= true;
427 memset (this->head
, 0, size
);
428 char *ret
= this->head
;
430 return reinterpret_cast<Type
*> (ret
);
433 template <typename Type
>
434 inline Type
*allocate_min (void)
436 return this->allocate_size
<Type
> (Type::min_size
);
439 template <typename Type
>
440 inline Type
*start_embed (void)
442 Type
*ret
= reinterpret_cast<Type
*> (this->head
);
446 template <typename Type
>
447 inline Type
*embed (const Type
&obj
)
449 unsigned int size
= obj
.get_size ();
450 Type
*ret
= this->allocate_size
<Type
> (size
);
451 if (unlikely (!ret
)) return NULL
;
452 memcpy (ret
, obj
, size
);
456 template <typename Type
>
457 inline Type
*extend_min (Type
&obj
)
459 unsigned int size
= obj
.min_size
;
460 assert (this->start
<= (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
461 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
462 return reinterpret_cast<Type
*> (&obj
);
465 template <typename Type
>
466 inline Type
*extend (Type
&obj
)
468 unsigned int size
= obj
.get_size ();
469 assert (this->start
< (char *) &obj
&& (char *) &obj
<= this->head
&& (char *) &obj
+ size
>= this->head
);
470 if (unlikely (!this->allocate_size
<Type
> (((char *) &obj
) + size
- this->head
))) return NULL
;
471 return reinterpret_cast<Type
*> (&obj
);
474 inline void truncate (void *head
)
476 assert (this->start
< head
&& head
<= this->head
);
477 this->head
= (char *) head
;
480 unsigned int debug_depth
;
481 char *start
, *end
, *head
;
482 bool ran_out_of_room
;
485 template <typename Type
>
488 inline Supplier (const Type
*array
, unsigned int len_
)
493 inline const Type
operator [] (unsigned int i
) const
495 if (unlikely (i
>= len
)) return Type ();
499 inline void advance (unsigned int count
)
501 if (unlikely (count
> len
))
508 inline Supplier (const Supplier
<Type
> &); /* Disallow copy */
509 inline Supplier
<Type
>& operator= (const Supplier
<Type
> &); /* Disallow copy */
520 * The OpenType Font File: Data Types
524 /* "The following data types are used in the OpenType font file.
525 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
532 template <typename Type
, int Bytes
> struct BEInt
;
534 template <typename Type
>
535 struct BEInt
<Type
, 2>
538 inline void set (Type V
)
540 v
[0] = (V
>> 8) & 0xFF;
543 inline operator Type (void) const
548 inline bool operator == (const BEInt
<Type
, 2>& o
) const
550 return v
[0] == o
.v
[0]
553 inline bool operator != (const BEInt
<Type
, 2>& o
) const { return !(*this == o
); }
554 private: uint8_t v
[2];
556 template <typename Type
>
557 struct BEInt
<Type
, 3>
560 inline void set (Type V
)
562 v
[0] = (V
>> 16) & 0xFF;
563 v
[1] = (V
>> 8) & 0xFF;
566 inline operator Type (void) const
572 inline bool operator == (const BEInt
<Type
, 3>& o
) const
574 return v
[0] == o
.v
[0]
578 inline bool operator != (const BEInt
<Type
, 3>& o
) const { return !(*this == o
); }
579 private: uint8_t v
[3];
581 template <typename Type
>
582 struct BEInt
<Type
, 4>
585 inline void set (Type V
)
587 v
[0] = (V
>> 24) & 0xFF;
588 v
[1] = (V
>> 16) & 0xFF;
589 v
[2] = (V
>> 8) & 0xFF;
592 inline operator Type (void) const
599 inline bool operator == (const BEInt
<Type
, 4>& o
) const
601 return v
[0] == o
.v
[0]
606 inline bool operator != (const BEInt
<Type
, 4>& o
) const { return !(*this == o
); }
607 private: uint8_t v
[4];
610 /* Integer types in big-endian order and no alignment requirement */
611 template <typename Type
, unsigned int Size
>
614 inline void set (Type i
) { v
.set (i
); }
615 inline operator Type(void) const { return v
; }
616 inline bool operator == (const IntType
<Type
,Size
> &o
) const { return v
== o
.v
; }
617 inline bool operator != (const IntType
<Type
,Size
> &o
) const { return v
!= o
.v
; }
618 static inline int cmp (const IntType
<Type
,Size
> *a
, const IntType
<Type
,Size
> *b
) { return b
->cmp (*a
); }
619 inline int cmp (IntType
<Type
,Size
> va
) const { Type a
= va
; Type b
= v
; return a
< b
? -1 : a
== b
? 0 : +1; }
620 inline int cmp (Type a
) const { Type b
= v
; return a
< b
? -1 : a
== b
? 0 : +1; }
621 inline bool sanitize (hb_sanitize_context_t
*c
) {
622 TRACE_SANITIZE (this);
623 return TRACE_RETURN (likely (c
->check_struct (this)));
628 DEFINE_SIZE_STATIC (Size
);
631 typedef uint8_t BYTE
; /* 8-bit unsigned integer. */
632 typedef IntType
<uint16_t, 2> USHORT
; /* 16-bit unsigned integer. */
633 typedef IntType
<int16_t, 2> SHORT
; /* 16-bit signed integer. */
634 typedef IntType
<uint32_t, 4> ULONG
; /* 32-bit unsigned integer. */
635 typedef IntType
<int32_t, 4> LONG
; /* 32-bit signed integer. */
636 typedef IntType
<uint32_t, 3> UINT24
; /* 24-bit unsigned integer. */
638 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
641 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
642 typedef USHORT UFWORD
;
644 /* Date represented in number of seconds since 12:00 midnight, January 1,
645 * 1904. The value is represented as a signed 64-bit integer. */
648 inline bool sanitize (hb_sanitize_context_t
*c
) {
649 TRACE_SANITIZE (this);
650 return TRACE_RETURN (likely (c
->check_struct (this)));
656 DEFINE_SIZE_STATIC (8);
659 /* Array of four uint8s (length = 32 bits) used to identify a script, language
660 * system, feature, or baseline */
663 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
664 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v
); }
665 inline operator char* (void) { return reinterpret_cast<char *> (&this->v
); }
667 DEFINE_SIZE_STATIC (4);
669 DEFINE_NULL_DATA (Tag
, " ");
671 /* Glyph index number, same as uint16 (length = 16 bits) */
672 typedef USHORT GlyphID
;
674 /* Script/language-system/feature index */
675 struct Index
: USHORT
{
676 static const unsigned int NOT_FOUND_INDEX
= 0xFFFFu
;
678 DEFINE_NULL_DATA (Index
, "\xff\xff");
680 /* Offset, Null offset = 0 */
681 template <typename Type
=USHORT
>
684 inline bool is_null (void) const { return 0 == *this; }
686 DEFINE_SIZE_STATIC (sizeof(Type
));
691 struct CheckSum
: ULONG
693 /* This is reference implementation from the spec. */
694 static inline uint32_t CalcTableChecksum (const ULONG
*Table
, uint32_t Length
)
697 const ULONG
*EndPtr
= Table
+((Length
+3) & ~3) / ULONG::static_size
;
699 while (Table
< EndPtr
)
704 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
705 inline void set_for_data (const void *data
, unsigned int length
)
706 { set (CalcTableChecksum ((const ULONG
*) data
, length
)); }
709 DEFINE_SIZE_STATIC (4);
719 inline uint32_t to_int (void) const { return (major
<< 16) + minor
; }
721 inline bool sanitize (hb_sanitize_context_t
*c
) {
722 TRACE_SANITIZE (this);
723 return TRACE_RETURN (c
->check_struct (this));
729 DEFINE_SIZE_STATIC (4);
735 * Template subclasses of Offset that do the dereferencing.
739 template <typename Type
, typename OffsetType
=USHORT
>
740 struct OffsetTo
: Offset
<OffsetType
>
742 inline const Type
& operator () (const void *base
) const
744 unsigned int offset
= *this;
745 if (unlikely (!offset
)) return Null(Type
);
746 return StructAtOffset
<Type
> (base
, offset
);
749 inline Type
& serialize (hb_serialize_context_t
*c
, void *base
)
751 Type
*t
= c
->start_embed
<Type
> ();
752 this->set ((char *) t
- (char *) base
); /* TODO(serialize) Overflow? */
756 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
757 TRACE_SANITIZE (this);
758 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
759 unsigned int offset
= *this;
760 if (unlikely (!offset
)) return TRACE_RETURN (true);
761 Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
762 return TRACE_RETURN (likely (obj
.sanitize (c
)) || neuter (c
));
764 template <typename T
>
765 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
, T user_data
) {
766 TRACE_SANITIZE (this);
767 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
768 unsigned int offset
= *this;
769 if (unlikely (!offset
)) return TRACE_RETURN (true);
770 Type
&obj
= StructAtOffset
<Type
> (base
, offset
);
771 return TRACE_RETURN (likely (obj
.sanitize (c
, user_data
)) || neuter (c
));
774 /* Set the offset to Null */
775 inline bool neuter (hb_sanitize_context_t
*c
) {
776 return c
->try_set (this, 0);
778 DEFINE_SIZE_STATIC (sizeof(OffsetType
));
780 template <typename Base
, typename OffsetType
, typename Type
>
781 static inline const Type
& operator + (const Base
&base
, const OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
782 template <typename Base
, typename OffsetType
, typename Type
>
783 static inline Type
& operator + (Base
&base
, OffsetTo
<Type
, OffsetType
> &offset
) { return offset (base
); }
790 /* An array with a number of elements. */
791 template <typename Type
, typename LenType
=USHORT
>
794 const Type
*sub_array (unsigned int start_offset
, unsigned int *pcount
/* IN/OUT */) const
796 unsigned int count
= len
;
797 if (unlikely (start_offset
> count
))
800 count
-= start_offset
;
801 count
= MIN (count
, *pcount
);
803 return array
+ start_offset
;
806 inline const Type
& operator [] (unsigned int i
) const
808 if (unlikely (i
>= len
)) return Null(Type
);
811 inline Type
& operator [] (unsigned int i
)
815 inline unsigned int get_size (void) const
816 { return len
.static_size
+ len
* Type::static_size
; }
818 inline bool serialize (hb_serialize_context_t
*c
,
819 unsigned int items_len
)
821 TRACE_SERIALIZE (this);
822 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
823 len
.set (items_len
); /* TODO(serialize) Overflow? */
824 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
825 return TRACE_RETURN (true);
828 inline bool serialize (hb_serialize_context_t
*c
,
829 Supplier
<Type
> &items
,
830 unsigned int items_len
)
832 TRACE_SERIALIZE (this);
833 if (unlikely (!serialize (c
, items_len
))) return TRACE_RETURN (false);
834 for (unsigned int i
= 0; i
< items_len
; i
++)
836 items
.advance (items_len
);
837 return TRACE_RETURN (true);
840 inline bool sanitize (hb_sanitize_context_t
*c
) {
841 TRACE_SANITIZE (this);
842 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
844 /* Note: for structs that do not reference other structs,
845 * we do not need to call their sanitize() as we already did
846 * a bound check on the aggregate array size. We just include
847 * a small unreachable expression to make sure the structs
848 * pointed to do have a simple sanitize(), ie. they do not
849 * reference other structs via offsets.
851 (void) (false && array
[0].sanitize (c
));
853 return TRACE_RETURN (true);
855 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
856 TRACE_SANITIZE (this);
857 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
858 unsigned int count
= len
;
859 for (unsigned int i
= 0; i
< count
; i
++)
860 if (unlikely (!array
[i
].sanitize (c
, base
)))
861 return TRACE_RETURN (false);
862 return TRACE_RETURN (true);
864 template <typename T
>
865 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
, T user_data
) {
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
) {
887 TRACE_SANITIZE (this);
888 return TRACE_RETURN (c
->check_struct (this) && c
->check_array (this, Type::static_size
, len
));
895 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
898 /* Array of Offset's */
899 template <typename Type
>
900 struct OffsetArrayOf
: ArrayOf
<OffsetTo
<Type
> > {};
902 /* Array of offsets relative to the beginning of the array itself. */
903 template <typename Type
>
904 struct OffsetListOf
: OffsetArrayOf
<Type
>
906 inline const Type
& operator [] (unsigned int i
) const
908 if (unlikely (i
>= this->len
)) return Null(Type
);
909 return this+this->array
[i
];
912 inline bool sanitize (hb_sanitize_context_t
*c
) {
913 TRACE_SANITIZE (this);
914 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this));
916 template <typename T
>
917 inline bool sanitize (hb_sanitize_context_t
*c
, T user_data
) {
918 TRACE_SANITIZE (this);
919 return TRACE_RETURN (OffsetArrayOf
<Type
>::sanitize (c
, this, user_data
));
924 /* An array starting at second element. */
925 template <typename Type
, typename LenType
=USHORT
>
926 struct HeadlessArrayOf
928 inline const Type
& operator [] (unsigned int i
) const
930 if (unlikely (i
>= len
|| !i
)) return Null(Type
);
933 inline unsigned int get_size (void) const
934 { return len
.static_size
+ (len
? len
- 1 : 0) * Type::static_size
; }
936 inline bool serialize (hb_serialize_context_t
*c
,
937 Supplier
<Type
> &items
,
938 unsigned int items_len
)
940 TRACE_SERIALIZE (this);
941 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
942 len
.set (items_len
); /* TODO(serialize) Overflow? */
943 if (unlikely (!items_len
)) return TRACE_RETURN (true);
944 if (unlikely (!c
->extend (*this))) return TRACE_RETURN (false);
945 for (unsigned int i
= 0; i
< items_len
- 1; i
++)
947 items
.advance (items_len
- 1);
948 return TRACE_RETURN (true);
951 inline bool sanitize_shallow (hb_sanitize_context_t
*c
) {
952 return c
->check_struct (this)
953 && c
->check_array (this, Type::static_size
, len
);
956 inline bool sanitize (hb_sanitize_context_t
*c
) {
957 TRACE_SANITIZE (this);
958 if (unlikely (!sanitize_shallow (c
))) return TRACE_RETURN (false);
960 /* Note: for structs that do not reference other structs,
961 * we do not need to call their sanitize() as we already did
962 * a bound check on the aggregate array size. We just include
963 * a small unreachable expression to make sure the structs
964 * pointed to do have a simple sanitize(), ie. they do not
965 * reference other structs via offsets.
967 (void) (false && array
[0].sanitize (c
));
969 return TRACE_RETURN (true);
975 DEFINE_SIZE_ARRAY (sizeof (LenType
), array
);
979 /* An array with sorted elements. Supports binary searching. */
980 template <typename Type
, typename LenType
=USHORT
>
981 struct SortedArrayOf
: ArrayOf
<Type
, LenType
>
983 template <typename SearchType
>
984 inline int bsearch (const SearchType
&x
) const
986 /* Hand-coded bsearch here since this is in the hot inner loop. */
987 int min
= 0, max
= (int) this->len
- 1;
990 int mid
= (min
+ max
) / 2;
991 int c
= this->array
[mid
].cmp (x
);
1004 } /* namespace OT */
1007 #endif /* HB_OPEN_TYPE_PRIVATE_HH */