hb-open-type-private.hh revision 6faff8e4132197ba06f0e685b82efe35b546cf64
164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod/*
22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
30ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod * Copyright © 2012  Google, Inc.
464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
5c755cb3e3ac55156d0d2ec05adea7a650b97cc41Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
664aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
764aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * Permission is hereby granted, without written agreement and without
864aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
964aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * software and its documentation for any purpose, provided that the
1064aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
1164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * all copies of this software.
1264aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
1364aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1564aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1664aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1764aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * DAMAGE.
1864aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
1964aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
2064aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2264aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2364aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
2564aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
260ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod * Google Author(s): Behdad Esfahbod
2764aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod */
2864aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod
290f0cd9d361f1bb614aa3fd4616160d027062370eBehdad Esfahbod#ifndef HB_OPEN_TYPE_PRIVATE_HH
300f0cd9d361f1bb614aa3fd4616160d027062370eBehdad Esfahbod#define HB_OPEN_TYPE_PRIVATE_HH
3112c4568c680ea2b9b98a16a8b7402ca185c90ef6Behdad Esfahbod
32c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-private.hh"
3312c4568c680ea2b9b98a16a8b7402ca185c90ef6Behdad Esfahbod
34a16ecbf0564a6e2576da22c12827f3c0719da549Behdad Esfahbod
357c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbodnamespace OT {
367c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbod
37a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbod
3881822528efc63d867cb2343a8ff7af64fac1c70dBehdad Esfahbod
3981822528efc63d867cb2343a8ff7af64fac1c70dBehdad Esfahbod/*
40196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod * Casts
41196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod */
42196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod
43187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod/* Cast to struct T, reference to reference */
44a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbodtemplate<typename Type, typename TObject>
456faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline const Type& CastR(const TObject &X)
46a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbod{ return reinterpret_cast<const Type&> (X); }
47a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbodtemplate<typename Type, typename TObject>
486faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline Type& CastR(TObject &X)
49a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbod{ return reinterpret_cast<Type&> (X); }
50196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod
51187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod/* Cast to struct T, pointer to pointer */
52187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbodtemplate<typename Type, typename TObject>
536faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline const Type* CastP(const TObject *X)
54187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod{ return reinterpret_cast<const Type*> (X); }
55187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbodtemplate<typename Type, typename TObject>
566faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline Type* CastP(TObject *X)
57187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod{ return reinterpret_cast<Type*> (X); }
58187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod
5909766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
6009766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod * location pointed to by P plus Ofs bytes. */
6109766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbodtemplate<typename Type>
626faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline const Type& StructAtOffset(const void *P, unsigned int offset)
63a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
6409766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbodtemplate<typename Type>
656faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline Type& StructAtOffset(void *P, unsigned int offset)
66a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod{ return * reinterpret_cast<Type*> ((char *) P + offset); }
6770de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
682e2f43edf2f49f4047e28b1ce2ea95938536de9cBehdad Esfahbod/* StructAfter<T>(X) returns the struct T& that is placed after X.
6929c3f5e1b6212c775a7b911becd44ba093b7b0ebBehdad Esfahbod * Works with X of variable size also.  X must implement get_size() */
70e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbodtemplate<typename Type, typename TObject>
716faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline const Type& StructAfter(const TObject &X)
7209766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod{ return StructAtOffset<Type>(&X, X.get_size()); }
73e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbodtemplate<typename Type, typename TObject>
746faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline Type& StructAfter(TObject &X)
7509766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod{ return StructAtOffset<Type>(&X, X.get_size()); }
76a3263aa773ad7a914496792466c69047048b093cBehdad Esfahbod
77e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbod
78d3480ba37fbb5d4be75b094060f5b2f1ce98fb53Behdad Esfahbod
7970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod/*
80e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod * Size checking
81e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod */
82e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
83f679635893eebc13402c5ee51a6f106eed0c76beBehdad Esfahbod/* Check _assertion in a method environment */
84a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
85a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  inline void _instance_assertion_on_line_##_line (void) const \
86a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  { \
87a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod    ASSERT_STATIC (_assertion); \
88a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod    ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
89a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  }
90a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
91a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
92a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod
93f679635893eebc13402c5ee51a6f106eed0c76beBehdad Esfahbod/* Check that _code compiles in a method environment */
94a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
95a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  inline void _compiles_assertion_on_line_##_line (void) const \
96f679635893eebc13402c5ee51a6f106eed0c76beBehdad Esfahbod  { _code; }
97a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
98a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
990abcc3b48cfd51a22695c9e988938b2f45cb19d8Behdad Esfahbod
1000abcc3b48cfd51a22695c9e988938b2f45cb19d8Behdad Esfahbod
101e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod#define DEFINE_SIZE_STATIC(size) \
102a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
103e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  static const unsigned int static_size = (size); \
104e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  static const unsigned int min_size = (size)
105e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
106b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod/* Size signifying variable-sized array */
107b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod#define VAR 1
108b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod
109596e471aa5053d955fb5d5b5923088c8814469b1Behdad Esfahbod#define DEFINE_SIZE_UNION(size, _member) \
110a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
111596e471aa5053d955fb5d5b5923088c8814469b1Behdad Esfahbod  static const unsigned int min_size = (size)
112596e471aa5053d955fb5d5b5923088c8814469b1Behdad Esfahbod
113bea34c7cbb583cf7660776e95cab3171590b8427Behdad Esfahbod#define DEFINE_SIZE_MIN(size) \
114a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
115b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  static const unsigned int min_size = (size)
116b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod
1170eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod#define DEFINE_SIZE_ARRAY(size, array) \
118a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
119a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
120e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  static const unsigned int min_size = (size)
121e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
1220eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
123a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
124a00a63b5ef503fafa87e26b517732b2214e01719Behdad Esfahbod  DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
125e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  static const unsigned int min_size = (size)
126e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
127e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
128e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod
129e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod/*
130f0abcd69408a3af65207cdf8847575ade4579bd4Behdad Esfahbod * Null objects
131600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod */
132600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod
1338b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Global nul-content Null pool.  Enlarge as necessary. */
1340bb0f5d41976ae27c5c7a51cbb82144b48315a4bBehdad Esfahbod/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
135cf5585cfa6cac6fdf627a99941299e76af5ae0f7Behdad Esfahbodstatic const void *_NullPool[64 / sizeof (void *)];
1368b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
137d2c2ca8faf62fc380d4717d286556139a62d2356Behdad Esfahbod/* Generic nul-content Null objects. */
1388b8358033184198ff638ee1379093717596e162dBehdad Esfahbodtemplate <typename Type>
1397f97d2cd904ea999c099c73c52187c5d65aeec67Behdad Esfahbodstatic inline const Type& Null (void) {
140fd0de881f4fc004da6f36d50a91d0e62f8eb4d8cBehdad Esfahbod  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
141187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod  return *CastP<Type> (_NullPool);
1429d3677899f90abdc7fb3e3d854db654a8707a84bBehdad Esfahbod}
1438b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
1448b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
14565f46b00333e20ab8a52a4b350747507541ec1dbBehdad Esfahbod#define DEFINE_NULL_DATA(Type, data) \
146fd0de881f4fc004da6f36d50a91d0e62f8eb4d8cBehdad Esfahbodstatic const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
1478b8358033184198ff638ee1379093717596e162dBehdad Esfahbodtemplate <> \
1486faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod/*static*/ inline const Type& Null<Type> (void) { \
149187454c595559ce48d072fee6bccb51f3de283d4Behdad Esfahbod  return *CastP<Type> (_Null##Type); \
150565c80bd2960366ace2d10dd71beaaf2a80213c8Behdad Esfahbod} /* The following line really exists such that we end in a place needing semicolon */ \
151bea34c7cbb583cf7660776e95cab3171590b8427Behdad EsfahbodASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
1528b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
1538b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Accessor macro. */
1549d3677899f90abdc7fb3e3d854db654a8707a84bBehdad Esfahbod#define Null(Type) Null<Type>()
1558b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
1568b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
157600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod
158577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod/*
159577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod * Sanitize
160577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod */
161577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
16295e202403ffa543c817f45cca21fbc116eb8e807Behdad Esfahbod#ifndef HB_DEBUG_SANITIZE
16311e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
16495e202403ffa543c817f45cca21fbc116eb8e807Behdad Esfahbod#endif
16595e202403ffa543c817f45cca21fbc116eb8e807Behdad Esfahbod
16620e3dd5d292b65f70d2eae63b8d8713a1c889d47Behdad Esfahbod
167be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod#define TRACE_SANITIZE(this) \
168902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
1692c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
170902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod	 "");
171807c5b03a2251a3c29a520852639421783101b55Behdad Esfahbod
17207a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod/* This limits sanitizing time on really broken fonts. */
17307a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod#ifndef HB_SANITIZE_MAX_EDITS
17407a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod#define HB_SANITIZE_MAX_EDITS 100
17507a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod#endif
176b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod
1771376fb7bf9ef07970f0ba13dc64d6a8ab8252762Behdad Esfahbodstruct hb_sanitize_context_t
178577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod{
1792c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod  inline const char *get_name (void) { return "SANITIZE"; }
1802c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod  static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
1812c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod  typedef bool return_t;
1822c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod  template <typename T>
1839c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
1842c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod  static return_t default_return_value (void) { return true; }
1850beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod  bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
1862c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fefBehdad Esfahbod
18731f18abecb149f8888a72510f2660328dd6de16dBehdad Esfahbod  inline void init (hb_blob_t *b)
18898daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  {
18931f18abecb149f8888a72510f2660328dd6de16dBehdad Esfahbod    this->blob = hb_blob_reference (b);
1901c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod    this->writable = false;
1911c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod  }
1921c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod
193cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod  inline void start_processing (void)
1941c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod  {
1954101ca7dbbdf1438fa116fb8cad935501ac7cca8Behdad Esfahbod    this->start = hb_blob_get_data (this->blob, NULL);
1964101ca7dbbdf1438fa116fb8cad935501ac7cca8Behdad Esfahbod    this->end = this->start + hb_blob_get_length (this->blob);
19798daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod    this->edit_count = 0;
19820e3dd5d292b65f70d2eae63b8d8713a1c889d47Behdad Esfahbod    this->debug_depth = 0;
199577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
2001e08830b4fac3a60ae52349cab6e101d389d30cdBehdad Esfahbod    DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
201cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod		     "start [%p..%p] (%lu bytes)",
2021e08830b4fac3a60ae52349cab6e101d389d30cdBehdad Esfahbod		     this->start, this->end,
2031e08830b4fac3a60ae52349cab6e101d389d30cdBehdad Esfahbod		     (unsigned long) (this->end - this->start));
20498daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  }
2051376fb7bf9ef07970f0ba13dc64d6a8ab8252762Behdad Esfahbod
206cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod  inline void end_processing (void)
20798daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  {
2081e08830b4fac3a60ae52349cab6e101d389d30cdBehdad Esfahbod    DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
209cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod		     "end [%p..%p] %u edit requests",
2101e08830b4fac3a60ae52349cab6e101d389d30cdBehdad Esfahbod		     this->start, this->end, this->edit_count);
211577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
21298daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod    hb_blob_destroy (this->blob);
21398daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod    this->blob = NULL;
21498daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod    this->start = this->end = NULL;
21598daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  }
2164f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
2174ad2cc5dec6b0639da2b1846282bdd99d06d5ff1Behdad Esfahbod  inline bool check_range (const void *base, unsigned int len) const
21898daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  {
219a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod    const char *p = (const char *) base;
22098daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod
221902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
222902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod      (&this->debug_depth, "SANITIZE", this->blob, NULL,
223902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       "check_range [%p..%p] (%d bytes) in [%p..%p]",
224902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       p, p + len, len,
225902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       this->start, this->end);
22698daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod
227cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
22898daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  }
229577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
2301cd1e117d060d38e314618b627d7663cb01ed584Behdad Esfahbod  inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
23198daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  {
232a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod    const char *p = (const char *) base;
233080a0eb7d82d7195be72c16ece6e0a3ffed636b6Behdad Esfahbod    bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
23441895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod
235902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
236902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod      (&this->debug_depth, "SANITIZE", this->blob, NULL,
237902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
238902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
239902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       this->start, this->end);
240fa030175ca998b00cc42cbced6e98de323ec01ecBehdad Esfahbod
241cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
24298daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  }
243254933c397f1ce9796f59689a25f9fc2e58df4eaBehdad Esfahbod
244b157617644d1e38f680163889d1dc2e2f64d9ba3Behdad Esfahbod  template <typename Type>
245b157617644d1e38f680163889d1dc2e2f64d9ba3Behdad Esfahbod  inline bool check_struct (const Type *obj) const
246b157617644d1e38f680163889d1dc2e2f64d9ba3Behdad Esfahbod  {
24754842374c2b291ef208c51ae1d853ec0403ccf84Behdad Esfahbod    return likely (this->check_range (obj, obj->min_size));
248b157617644d1e38f680163889d1dc2e2f64d9ba3Behdad Esfahbod  }
249b157617644d1e38f680163889d1dc2e2f64d9ba3Behdad Esfahbod
250cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod  inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
25198daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  {
25207a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
25307a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod      return false;
25407a52b62115f10caea5c2d174a4272eb9ddb2284Behdad Esfahbod
255a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod    const char *p = (const char *) base;
25698daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod    this->edit_count++;
25798daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod
258902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
259902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod      (&this->debug_depth, "SANITIZE", this->blob, NULL,
260902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
261902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       this->edit_count,
262902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod       p, p + len, len,
263e77b4425746ac9eb407ca4e742d962f1955971b4Behdad Esfahbod       this->start, this->end,
264e77b4425746ac9eb407ca4e742d962f1955971b4Behdad Esfahbod       this->writable ? "GRANTED" : "DENIED");
26598daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod
266cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    return TRACE_RETURN (this->writable);
26798daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  }
26898daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod
269cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod  mutable unsigned int debug_depth;
27098daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  const char *start, *end;
27198daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  bool writable;
27298daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  unsigned int edit_count;
27398daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod  hb_blob_t *blob;
27498daaf183d6dbf2b68959da608cd9876ba55d7aaBehdad Esfahbod};
275815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod
276577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
277577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
2784e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod/* Template to sanitize an object. */
2794e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbodtemplate <typename Type>
2804e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbodstruct Sanitizer
2814e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod{
2824e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  static hb_blob_t *sanitize (hb_blob_t *blob) {
283d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod    hb_sanitize_context_t c[1] = {{0}};
2844e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    bool sane;
2854e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
286d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod    /* TODO is_sane() stuff */
2874e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
2881c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod    c->init (blob);
2891c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod
2904e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  retry:
291cc06c243d8be3ebb1190281653d2dba504c16c0fBehdad Esfahbod    DEBUG_MSG_FUNC (SANITIZE, blob, "start");
2924f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
293cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    c->start_processing ();
2944e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
295d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod    if (unlikely (!c->start)) {
296cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod      c->end_processing ();
29748146e5612f6d272d6962f6829c6d64a31edef89Behdad Esfahbod      return blob;
29848146e5612f6d272d6962f6829c6d64a31edef89Behdad Esfahbod    }
29948146e5612f6d272d6962f6829c6d64a31edef89Behdad Esfahbod
300d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod    Type *t = CastP<Type> (const_cast<char *> (c->start));
3014e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
302d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod    sane = t->sanitize (c);
3034e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    if (sane) {
304d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      if (c->edit_count) {
305cc06c243d8be3ebb1190281653d2dba504c16c0fBehdad Esfahbod	DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
306fa030175ca998b00cc42cbced6e98de323ec01ecBehdad Esfahbod
3078b5346130425c7c101f6ff2432874ba2fd372edcBehdad Esfahbod        /* sanitize again to ensure no toe-stepping */
308d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod        c->edit_count = 0;
309d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod	sane = t->sanitize (c);
310d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod	if (c->edit_count) {
311cc06c243d8be3ebb1190281653d2dba504c16c0fBehdad Esfahbod	  DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
3124e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod	  sane = false;
3134e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod	}
3144e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      }
3154e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    } else {
316d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      unsigned int edit_count = c->edit_count;
3171c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod      if (edit_count && !c->writable) {
3181c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod        c->start = hb_blob_get_data_writable (blob, NULL);
3191c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	c->end = c->start + hb_blob_get_length (blob);
3201c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod
3211c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	if (c->start) {
3221c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	  c->writable = true;
3231c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	  /* ok, we made it writable by relocating.  try again */
324cc06c243d8be3ebb1190281653d2dba504c16c0fBehdad Esfahbod	  DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
3251c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	  goto retry;
3261c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod	}
3274e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      }
3284e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    }
3294e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
330cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    c->end_processing ();
3314101ca7dbbdf1438fa116fb8cad935501ac7cca8Behdad Esfahbod
332cc06c243d8be3ebb1190281653d2dba504c16c0fBehdad Esfahbod    DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
3334e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    if (sane)
3344e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      return blob;
3354e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    else {
3364e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      hb_blob_destroy (blob);
3374911062d5be0d937ee8f1a70cc93e05d162f45b3Behdad Esfahbod      return hb_blob_get_empty ();
3384e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    }
3394e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  }
340b435ab7e29c388e3b100f729957319931625a3a8Behdad Esfahbod
341b435ab7e29c388e3b100f729957319931625a3a8Behdad Esfahbod  static const Type* lock_instance (hb_blob_t *blob) {
3421c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod    hb_blob_make_immutable (blob);
3431c9f8717eb12c37c219333cbb0d123e1d2da4896Behdad Esfahbod    const char *base = hb_blob_get_data (blob, NULL);
344b435ab7e29c388e3b100f729957319931625a3a8Behdad Esfahbod    return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
345b435ab7e29c388e3b100f729957319931625a3a8Behdad Esfahbod  }
3464e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod};
3474e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
3482d15e72c75931398db5e027e660f1320bb979117Behdad Esfahbod
349f0abcd69408a3af65207cdf8847575ade4579bd4Behdad Esfahbod
350e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod/*
351e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod * Serialize
352e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod */
353e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
354e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod#ifndef HB_DEBUG_SERIALIZE
355e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
356e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod#endif
357e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
358e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
359be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod#define TRACE_SERIALIZE(this) \
360902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
361902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
362902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod	 "");
363e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
364e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
365e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbodstruct hb_serialize_context_t
366e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod{
367fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline hb_serialize_context_t (void *start, unsigned int size)
368e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  {
369e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->start = (char *) start;
370e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->end = this->start + size;
371e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
372e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->ran_out_of_room = false;
373e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->head = this->start;
374e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->debug_depth = 0;
375fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  }
376e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
377fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  template <typename Type>
378fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline Type *start_serialize (void)
379fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  {
380e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
381e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod		     "start [%p..%p] (%lu bytes)",
382e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod		     this->start, this->end,
383e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod		     (unsigned long) (this->end - this->start));
384fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
385fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    return start_embed<Type> ();
386e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  }
387e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
388fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline void end_serialize (void)
389e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  {
390e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
391fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		     "end [%p..%p] serialized %d bytes; %s",
392e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod		     this->start, this->end,
393fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		     (int) (this->head - this->start),
394e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod		     this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
395e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
396fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  }
397fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
398fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  template <typename Type>
399fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline Type *copy (void)
400fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  {
401fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    assert (!this->ran_out_of_room);
402fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    unsigned int len = this->head - this->start;
403fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    void *p = malloc (len);
404fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    if (p)
405fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod      memcpy (p, this->start, len);
406fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    return reinterpret_cast<Type *> (p);
407e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  }
408e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
409e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  template <typename Type>
4104b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod  inline Type *allocate_size (unsigned int size)
411e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  {
41205d5d3cd63ba2fadfdb62190dd24ef80ee3df40cBehdad Esfahbod    if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
413e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod      this->ran_out_of_room = true;
414e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod      return NULL;
415e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    }
4164b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod    memset (this->head, 0, size);
4179f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod    char *ret = this->head;
418e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->head += size;
419e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    return reinterpret_cast<Type *> (ret);
420e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  }
421e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
422e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  template <typename Type>
4234b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod  inline Type *allocate_min (void)
4249f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  {
4254b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod    return this->allocate_size<Type> (Type::min_size);
4269f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  }
4279f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod
4289f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  template <typename Type>
429fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline Type *start_embed (void)
430fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  {
431fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    Type *ret = reinterpret_cast<Type *> (this->head);
432fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    return ret;
433fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  }
434fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
435fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  template <typename Type>
4364b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod  inline Type *embed (const Type &obj)
437e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  {
438bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    unsigned int size = obj.get_size ();
4394b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod    Type *ret = this->allocate_size<Type> (size);
440bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    if (unlikely (!ret)) return NULL;
441bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    memcpy (ret, obj, size);
442bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    return ret;
4439f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  }
4449f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod
4459f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  template <typename Type>
4464b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod  inline Type *extend_min (Type &obj)
4479f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  {
448bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    unsigned int size = obj.min_size;
449fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
450fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
4519f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod    return reinterpret_cast<Type *> (&obj);
4529f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  }
4539f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod
4549f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  template <typename Type>
4554b312fb288faa383a2c5bd3be0428f0e58e02699Behdad Esfahbod  inline Type *extend (Type &obj)
4569f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  {
457bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    unsigned int size = obj.get_size ();
458bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
459811eefe225d20b20f1de20c6e62a0ebd6d89102aBehdad Esfahbod    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
460bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod    return reinterpret_cast<Type *> (&obj);
461e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  }
462e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
463e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  inline void truncate (void *head)
464e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  {
465e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    assert (this->start < head && head <= this->head);
466e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod    this->head = (char *) head;
467e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  }
468e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
469e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  unsigned int debug_depth;
470e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  char *start, *end, *head;
471e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod  bool ran_out_of_room;
472e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod};
473e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
474a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbodtemplate <typename Type>
475a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbodstruct Supplier
476a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod{
477a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  inline Supplier (const Type *array, unsigned int len_)
478a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  {
479a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    head = array;
480a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    len = len_;
481a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  }
482a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  inline const Type operator [] (unsigned int i) const
483a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  {
484a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    if (unlikely (i >= len)) return Type ();
485a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    return head[i];
486a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  }
487a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod
488fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline void advance (unsigned int count)
489fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  {
490a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    if (unlikely (count > len))
491a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod      count = len;
492a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    len -= count;
493a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    head += count;
494a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  }
495a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod
496a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  private:
497fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline Supplier (const Supplier<Type> &); /* Disallow copy */
498fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
499fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
500a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  unsigned int len;
501a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  const Type *head;
502a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod};
503a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod
504a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod
505e901b954c6ec44ac3ae7fb3c326e6e7a40718e4bBehdad Esfahbod
506f0abcd69408a3af65207cdf8847575ade4579bd4Behdad Esfahbod
507b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod/*
508b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod *
509bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod * The OpenType Font File: Data Types
510b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod */
511b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
512b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
513b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod/* "The following data types are used in the OpenType font file.
514b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
515b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
5165f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod/*
5175f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod * Int types
5185f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod */
5195f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
5206b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
521d7bf473ef222ab420456ff155ffaa09bacb3a394Behdad Esfahbodtemplate <typename Type, int Bytes> struct BEInt;
522e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod
523e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbodtemplate <typename Type>
524d7bf473ef222ab420456ff155ffaa09bacb3a394Behdad Esfahbodstruct BEInt<Type, 2>
525e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod{
526e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod  public:
52781408cd51ce575891e79e6483be187130f864c28Behdad Esfahbod  inline void set (Type i) { hb_be_uint16_put (v,i); }
5287f97d2cd904ea999c099c73c52187c5d65aeec67Behdad Esfahbod  inline operator Type (void) const { return hb_be_uint16_get (v); }
529153142dac8dd9abaf164bb88af07c600c17fc3a1Behdad Esfahbod  inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
53001c01618e98283611628cd54d5ba4bf122f24cd9Behdad Esfahbod  inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
531e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod  private: uint8_t v[2];
532e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod};
533e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbodtemplate <typename Type>
534d7bf473ef222ab420456ff155ffaa09bacb3a394Behdad Esfahbodstruct BEInt<Type, 4>
535e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod{
536e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod  public:
53781408cd51ce575891e79e6483be187130f864c28Behdad Esfahbod  inline void set (Type i) { hb_be_uint32_put (v,i); }
5387f97d2cd904ea999c099c73c52187c5d65aeec67Behdad Esfahbod  inline operator Type (void) const { return hb_be_uint32_get (v); }
539153142dac8dd9abaf164bb88af07c600c17fc3a1Behdad Esfahbod  inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
54001c01618e98283611628cd54d5ba4bf122f24cd9Behdad Esfahbod  inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
541e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod  private: uint8_t v[4];
542e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod};
543bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtemplate <typename Type>
544bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodstruct BEInt<Type, 3>
545bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod{
546bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  public:
547bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline void set (Type i) { hb_be_uint24_put (v,i); }
548bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline operator Type (void) const { return hb_be_uint24_get (v); }
549bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); }
550bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
551bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  private: uint8_t v[3];
552bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod};
553e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod
5542467c669c2aee4de2a6621a9d06cba0262376d41Behdad Esfahbod/* Integer types in big-endian order and no alignment requirement */
555bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtemplate <typename Type, unsigned int Size>
556e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbodstruct IntType
557e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod{
55881408cd51ce575891e79e6483be187130f864c28Behdad Esfahbod  inline void set (Type i) { v.set (i); }
55901c01618e98283611628cd54d5ba4bf122f24cd9Behdad Esfahbod  inline operator Type(void) const { return v; }
560bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; }
561bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; }
562bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
563bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
5644e573715ae5f5ed486ad66382bb44c47a86591ffBehdad Esfahbod  inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
565d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
566be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
5670ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (likely (c->check_struct (this)));
568e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod  }
569a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod  protected:
570bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  BEInt<Type, Size> v;
571569da92bc6956f42d9b2d65c784e184fb6380efeBehdad Esfahbod  public:
572bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbod  DEFINE_SIZE_STATIC (Size);
573e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod};
574e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod
575bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtypedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
576bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtypedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
577bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtypedef IntType<uint32_t, 4> ULONG;	/* 32-bit unsigned integer. */
578bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtypedef IntType<int32_t,  4> LONG;	/* 32-bit signed integer. */
579bd61bc13ea8ff350ada5449b2cfeb612e66ecafaBehdad Esfahbodtypedef IntType<uint32_t, 3> UINT24;	/* 24-bit unsigned integer. */
580e032ed9f75d4a0f365649a25706871bbb5ae6651Behdad Esfahbod
581ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbod/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
582ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbodtypedef SHORT FWORD;
583ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbod
584ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbod/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
585ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbodtypedef USHORT UFWORD;
586ae9877dea6a1aed3566d9b87a75ede84259deacaBehdad Esfahbod
587e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod/* Date represented in number of seconds since 12:00 midnight, January 1,
588e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod * 1904. The value is represented as a signed 64-bit integer. */
589e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbodstruct LONGDATETIME
590e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod{
591e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
592be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
5930ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (likely (c->check_struct (this)));
594e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  }
5956775da3a7c07db6c032cf429dc199d471948db56Behdad Esfahbod  protected:
596e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  LONG major;
597e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  ULONG minor;
598e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  public:
599e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod  DEFINE_SIZE_STATIC (8);
600e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod};
601e29caf3f943b2b6f4997f469f7274252c82f465eBehdad Esfahbod
6026b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* Array of four uint8s (length = 32 bits) used to identify a script, language
6036b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod * system, feature, or baseline */
60420cc86b3592db33731de671f008d7d222776be49Behdad Esfahbodstruct Tag : ULONG
60560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
606befc022affd2386b3f46cd7d11e4262f6c8bce9fBehdad Esfahbod  /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
607a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod  inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
608a82ef7a893b773a17f7548375de9f588dfc83abaBehdad Esfahbod  inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
609b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
610b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  DEFINE_SIZE_STATIC (4);
6116b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
61265f46b00333e20ab8a52a4b350747507541ec1dbBehdad EsfahbodDEFINE_NULL_DATA (Tag, "    ");
6136b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6146b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* Glyph index number, same as uint16 (length = 16 bits) */
6156ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbodtypedef USHORT GlyphID;
6166b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
617b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad Esfahbod/* Script/language-system/feature index */
618b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad Esfahbodstruct Index : USHORT {
619b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad Esfahbod  static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
620b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad Esfahbod};
621b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad EsfahbodDEFINE_NULL_DATA (Index, "\xff\xff");
622b5db4f1e4eefa266a71a28b5496f47ff9d1a81e8Behdad Esfahbod
6231f437e6f47fb6c15761021bd2078f31778f2179cBehdad Esfahbod/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
624e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbodstruct Offset : USHORT
625e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod{
626e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  inline bool is_null (void) const { return 0 == *this; }
627e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  public:
628e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  DEFINE_SIZE_STATIC (2);
629e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod};
6306ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod
6316ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
632e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbodstruct LongOffset : ULONG
633e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod{
634e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  inline bool is_null (void) const { return 0 == *this; }
635e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  public:
636e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod  DEFINE_SIZE_STATIC (4);
637e95e031b5682809488cc965883e15404cb9cfb6aBehdad Esfahbod};
6386ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod
6396b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6406b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* CheckSum */
64160d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct CheckSum : ULONG
64260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
64305bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod  /* This is reference implementation from the spec. */
64405bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
64560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
6466b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    uint32_t Sum = 0L;
64705bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
6486b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6496b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    while (Table < EndPtr)
6506b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod      Sum += *Table++;
6516b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    return Sum;
6526b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod  }
65305bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod
65405bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod  /* Note: data should be 4byte aligned and have 4byte padding at the end. */
65505bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod  inline void set_for_data (const void *data, unsigned int length)
65605bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod  { set (CalcTableChecksum ((const ULONG *) data, length)); }
65705bad3b8c25a89bc0f20f99f9215e492f48f03feBehdad Esfahbod
658b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
659b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  DEFINE_SIZE_STATIC (4);
6606b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
6616b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6626b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6636b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/*
6646b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod * Version Numbers
6656b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod */
6666b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
66787fcdcbe3644da10154688765db2d62eb9ac079aBehdad Esfahbodstruct FixedVersion
66860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
6694f28fbdd804fabeec57a98fe267d892ab58b3a6dBehdad Esfahbod  inline uint32_t to_int (void) const { return (major << 16) + minor; }
67096908b898476ca5d7da5f386b15be76f9e83d76eBehdad Esfahbod
671d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
672be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
6730ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (c->check_struct (this));
674cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod  }
675cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod
6766ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod  USHORT major;
67787fcdcbe3644da10154688765db2d62eb9ac079aBehdad Esfahbod  USHORT minor;
678b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
679b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  DEFINE_SIZE_STATIC (4);
6806b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
6816b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
68292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
68392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
6845f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod/*
68592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod * Template subclasses of Offset and LongOffset that do the dereferencing.
686f0abcd69408a3af65207cdf8847575ade4579bd4Behdad Esfahbod * Use: (base+offset)
6875f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod */
6885f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
68992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename OffsetType, typename Type>
69092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct GenericOffsetTo : OffsetType
69192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod{
69200e23fcc6fd0eee5c582251bf3de6a2703fbbd3eBehdad Esfahbod  inline const Type& operator () (const void *base) const
69392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  {
69492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    unsigned int offset = *this;
69564d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (unlikely (!offset)) return Null(Type);
69609766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod    return StructAtOffset<Type> (base, offset);
69792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  }
698bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod
699abcc5ac1fde1c493e4055dd2f27b8aade7713156Behdad Esfahbod  inline Type& serialize (hb_serialize_context_t *c, void *base)
700bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod  {
701fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    Type *t = c->start_embed<Type> ();
7024912030dfba740c822e200d33cbb5c6dbbeaf79eBehdad Esfahbod    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
703abcc5ac1fde1c493e4055dd2f27b8aade7713156Behdad Esfahbod    return *t;
704bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbod  }
70592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
706d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
707be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
7080ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
70992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    unsigned int offset = *this;
7100ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!offset)) return TRACE_RETURN (true);
71109766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod    Type &obj = StructAtOffset<Type> (base, offset);
7120ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
71392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  }
7144a446ac35136eff23d55f47bdd7b40095ad707abBehdad Esfahbod  template <typename T>
715d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
716be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
7170ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
71842b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    unsigned int offset = *this;
7190ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!offset)) return TRACE_RETURN (true);
72009766b1ec5ec55a61edbcd7a89ed3613cc92d4cbBehdad Esfahbod    Type &obj = StructAtOffset<Type> (base, offset);
7210ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
722c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod  }
723c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod
7249b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod  inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) {
7259b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod    if (c->may_edit (this, this->static_size)) {
7269b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod      this->set (v);
7279b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod      return true;
7289b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod    }
7299b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod    return false;
7309b54562d63f1a9e0e5b33d71c32bd1588759ebf1Behdad Esfahbod  }
731c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod  /* Set the offset to Null */
732d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool neuter (hb_sanitize_context_t *c) {
733cf26e88a5ab477295479f5b9450c2019b6430eaaBehdad Esfahbod    if (c->may_edit (this, this->static_size)) {
734c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod      this->set (0); /* 0 is Null offset */
735c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod      return true;
736c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod    }
737c9f14687a30866181feb57ee2736a147ec9f25a1Behdad Esfahbod    return false;
73842b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod  }
73992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod};
74092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Base, typename OffsetType, typename Type>
7416faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
742bc5be24014371ceb811b9ffd37062ede63d87bb1Behdad Esfahbodtemplate <typename Base, typename OffsetType, typename Type>
7436faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodstatic inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
74492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
7455f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbodtemplate <typename Type>
74692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct OffsetTo : GenericOffsetTo<Offset, Type> {};
74792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
74892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
74992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
750bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
751bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
75292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/*
75392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod * Array Types
75492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod */
75592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
75692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename LenType, typename Type>
75792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct GenericArrayOf
75860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
7594f5f1c34dda1e0629bfa6d7b0ffa2e1ce003b7c7Behdad Esfahbod  const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
76048de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod  {
76148de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod    unsigned int count = len;
76264d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (unlikely (start_offset > count))
76348de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod      count = 0;
76448de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod    else
76548de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod      count -= start_offset;
76648de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod    count = MIN (count, *pcount);
76748de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod    *pcount = count;
768b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod    return array + start_offset;
76948de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod  }
77048de3730cdf91b9f6473509e22260a902ccec992Behdad Esfahbod
77160d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
77260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
77364d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (unlikely (i >= len)) return Null(Type);
774b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod    return array[i];
7755f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  }
7769f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  inline Type& operator [] (unsigned int i)
7779f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  {
7789f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod    return array[i];
7799f2348de58f0f85593027378169bc03c4dd64e59Behdad Esfahbod  }
7807f97d2cd904ea999c099c73c52187c5d65aeec67Behdad Esfahbod  inline unsigned int get_size (void) const
781e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  { return len.static_size + len * Type::static_size; }
782e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod
783c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod  inline bool serialize (hb_serialize_context_t *c,
7841f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod			 unsigned int items_len)
7851f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod  {
786be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SERIALIZE (this);
7871f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
7881f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod    len.set (items_len); /* TODO(serialize) Overflow? */
7891f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
7901f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod    return TRACE_RETURN (true);
7911f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod  }
7921f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod
7931f07e3382a1608b054cbf88b89fef74f6c485434Behdad Esfahbod  inline bool serialize (hb_serialize_context_t *c,
794a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod			 Supplier<Type> &items,
795c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod			 unsigned int items_len)
796c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod  {
797be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SERIALIZE (this);
798715e03bc21d6adaa8e1f647235843839dc47dad1Behdad Esfahbod    if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
799715e03bc21d6adaa8e1f647235843839dc47dad1Behdad Esfahbod    for (unsigned int i = 0; i < items_len; i++)
800fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod      array[i] = items[i];
801a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    items.advance (items_len);
802c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod    return TRACE_RETURN (true);
803c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod  }
804c61be03d6df122f18eebda3b29e42c9e768d45b9Behdad Esfahbod
805d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
806be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8070ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
80811e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod
80940d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod    /* Note: for structs that do not reference other structs,
81040d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod     * we do not need to call their sanitize() as we already did
81111e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * a bound check on the aggregate array size.  We just include
81211e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * a small unreachable expression to make sure the structs
81311e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * pointed to do have a simple sanitize(), ie. they do not
81411e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * reference other structs via offsets.
81540d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod     */
81611e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod    (void) (false && array[0].sanitize (c));
81711e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod
8180ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (true);
81970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
820d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
821be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8220ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
823e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod    unsigned int count = len;
824e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod    for (unsigned int i = 0; i < count; i++)
825d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      if (unlikely (!array[i].sanitize (c, base)))
8260ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod        return TRACE_RETURN (false);
8270ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (true);
828e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod  }
8294a446ac35136eff23d55f47bdd7b40095ad707abBehdad Esfahbod  template <typename T>
830d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
831be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8320ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
83342b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    unsigned int count = len;
83442b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
835d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      if (unlikely (!array[i].sanitize (c, base, user_data)))
8360ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod        return TRACE_RETURN (false);
8370ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (true);
83842b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod  }
83970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
84030fa2821c277df99a14089749313dfe2b541e2d0Behdad Esfahbod  private:
841d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
842be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8430ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
84430fa2821c277df99a14089749313dfe2b541e2d0Behdad Esfahbod  }
84530fa2821c277df99a14089749313dfe2b541e2d0Behdad Esfahbod
84630fa2821c277df99a14089749313dfe2b541e2d0Behdad Esfahbod  public:
84792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  LenType len;
848b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod  Type array[VAR];
849b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
8500eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
851e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod};
852e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod
85392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* An array with a USHORT number of elements. */
85492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
85592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct ArrayOf : GenericArrayOf<USHORT, Type> {};
85692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
85792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* An array with a ULONG number of elements. */
85892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
85992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongArrayOf : GenericArrayOf<ULONG, Type> {};
86092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
86192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* Array of Offset's */
86292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
86392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
86492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
86592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* Array of LongOffset's */
86692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
86792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
86892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
86992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* LongArray of LongOffset's */
87092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
87192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
87292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
87380e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod/* Array of offsets relative to the beginning of the array itself. */
87480e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbodtemplate <typename Type>
87580e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbodstruct OffsetListOf : OffsetArrayOf<Type>
87680e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod{
87780e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
87880e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  {
87964d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (unlikely (i >= this->len)) return Null(Type);
880b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod    return this+this->array[i];
88180e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
88280e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
883d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
884be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8850ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
88680e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
8874a446ac35136eff23d55f47bdd7b40095ad707abBehdad Esfahbod  template <typename T>
888d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
889be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
8900ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
89180e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
89280e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod};
89380e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
89480e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
895e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod/* An array with a USHORT number of elements,
896e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod * starting at second element. */
897e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbodtemplate <typename Type>
89860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct HeadlessArrayOf
89960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
90060d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
90160d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
90264d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (unlikely (i >= len || !i)) return Null(Type);
903b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod    return array[i-1];
904e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod  }
9057f97d2cd904ea999c099c73c52187c5d65aeec67Behdad Esfahbod  inline unsigned int get_size (void) const
906e45d3f86f9a5f3d29ca35a282de7f98e702878f9Behdad Esfahbod  { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
9075f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
908a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  inline bool serialize (hb_serialize_context_t *c,
909a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod			 Supplier<Type> &items,
910a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod			 unsigned int items_len)
911a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  {
912be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SERIALIZE (this);
913a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
914a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    len.set (items_len); /* TODO(serialize) Overflow? */
915a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    if (unlikely (!items_len)) return TRACE_RETURN (true);
916fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
917fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    for (unsigned int i = 0; i < items_len - 1; i++)
918fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod      array[i] = items[i];
919a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    items.advance (items_len - 1);
920a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod    return TRACE_RETURN (true);
921a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod  }
922a930c68e9c50aade78c1eb0eef075c9c117e4ef6Behdad Esfahbod
923d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
924d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod    return c->check_struct (this)
925d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod	&& c->check_array (this, Type::static_size, len);
926e5546a4352c54311ac4a9ef138b187378155ebe1Behdad Esfahbod  }
927e5546a4352c54311ac4a9ef138b187378155ebe1Behdad Esfahbod
928d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) {
929be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
9300ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
93111e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod
93240d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod    /* Note: for structs that do not reference other structs,
93340d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod     * we do not need to call their sanitize() as we already did
93411e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * a bound check on the aggregate array size.  We just include
93511e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * a small unreachable expression to make sure the structs
93611e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * pointed to do have a simple sanitize(), ie. they do not
93711e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod     * reference other structs via offsets.
93840d73bc68dd828cf68f90fde0f9499a6ce9fbb19Behdad Esfahbod     */
93911e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod    (void) (false && array[0].sanitize (c));
94011e3ec444a85fc72541823c2e98cc92c4ceb19afBehdad Esfahbod
9410ab8c8621712d33e1e91dfdb4ad0b335e3d2a3fbBehdad Esfahbod    return TRACE_RETURN (true);
94270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
94370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
9445f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  USHORT len;
945b961518b9611471ff7060e97686e5625974847ebBehdad Esfahbod  Type array[VAR];
946ed07422c33bbb52ff4d79e65986171e3f07697d8Behdad Esfahbod  public:
9470eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
9485f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod};
9495f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
9506b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
951cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod/* An array with sorted elements.  Supports binary searching. */
952cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbodtemplate <typename Type>
953cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbodstruct SortedArrayOf : ArrayOf<Type> {
954cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod
955cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod  template <typename SearchType>
9568659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod  inline int search (const SearchType &x) const
9578659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod  {
9588659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod    /* Hand-coded bsearch here since this is in the hot inner loop. */
9598659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod    int min = 0, max = (int) this->len - 1;
9608659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod    while (min <= max)
9618659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod    {
9628659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod      int mid = (min + max) / 2;
9638659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod      int c = this->array[mid].cmp (x);
9648659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod      if (c < 0)
9658659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod        max = mid - 1;
9668659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod      else if (c > 0)
9678659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod        min = mid + 1;
9688659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod      else
9698659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod        return mid;
97099159e52a3c9d5ae6c0fbdec64e7ed684fa70b61Behdad Esfahbod    }
9718659c636087e433f56da458351e8b4d85fdb347cBehdad Esfahbod    return -1;
972cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod  }
973cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod};
974cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod
975cc8a4abea68f2dba26feb5785f9e518e6853c744Behdad Esfahbod
9767d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod} /* namespace OT */
9777c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbod
978acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
9791e91434569a9e9535ef021ca52b60b2e2af75d19Behdad Esfahbod#endif /* HB_OPEN_TYPE_PRIVATE_HH */
980