blob: 2e03dc3d0caba50eedd6b445a8f34fc26e667b79 [file] [log] [blame]
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02003 * Copyright © 2012 Google, Inc.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05006 *
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.
12 *
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
17 * DAMAGE.
18 *
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.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +020026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -050027 */
28
Behdad Esfahbod0f0cd9d2010-06-09 06:32:56 -040029#ifndef HB_OPEN_TYPE_PRIVATE_HH
30#define HB_OPEN_TYPE_PRIVATE_HH
Behdad Esfahbod12c45682006-12-28 06:10:59 -050031
Behdad Esfahbodc57d4542011-04-20 18:50:27 -040032#include "hb-private.hh"
Behdad Esfahbod12c45682006-12-28 06:10:59 -050033
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040034#include "hb-blob.h"
35
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050036
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040037namespace OT {
38
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040039
Behdad Esfahbod196598b2009-08-04 11:04:32 -040040/*
41 * Casts
42 */
43
Behdad Esfahbod187454c2010-04-23 16:35:01 -040044/* Cast to struct T, reference to reference */
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040045template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040046inline const Type& CastR(const TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040047{ return reinterpret_cast<const Type&> (X); }
48template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040049inline Type& CastR(TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040050{ return reinterpret_cast<Type&> (X); }
Behdad Esfahbod196598b2009-08-04 11:04:32 -040051
Behdad Esfahbod187454c2010-04-23 16:35:01 -040052/* Cast to struct T, pointer to pointer */
53template<typename Type, typename TObject>
54inline const Type* CastP(const TObject *X)
55{ return reinterpret_cast<const Type*> (X); }
56template<typename Type, typename TObject>
57inline Type* CastP(TObject *X)
58{ return reinterpret_cast<Type*> (X); }
59
Behdad Esfahbod09766b12010-05-10 17:36:03 -040060/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
61 * location pointed to by P plus Ofs bytes. */
62template<typename Type>
63inline const Type& StructAtOffset(const void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040064{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
Behdad Esfahbod09766b12010-05-10 17:36:03 -040065template<typename Type>
66inline Type& StructAtOffset(void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040067{ return * reinterpret_cast<Type*> ((char *) P + offset); }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040068
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -040069/* StructAfter<T>(X) returns the struct T& that is placed after X.
Behdad Esfahbod29c3f5e2010-04-21 23:01:00 -040070 * Works with X of variable size also. X must implement get_size() */
Behdad Esfahbode961c862010-04-21 15:56:11 -040071template<typename Type, typename TObject>
72inline const Type& StructAfter(const TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040073{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahbode961c862010-04-21 15:56:11 -040074template<typename Type, typename TObject>
75inline Type& StructAfter(TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040076{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040077
Behdad Esfahbode961c862010-04-21 15:56:11 -040078
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -050079
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040080/*
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040081 * Size checking
82 */
83
Behdad Esfahbodf6796352010-05-13 13:34:17 -040084/* Check _assertion in a method environment */
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040085#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
86 inline void _instance_assertion_on_line_##_line (void) const \
87 { \
88 ASSERT_STATIC (_assertion); \
89 ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
90 }
91# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
92# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
93
Behdad Esfahbodf6796352010-05-13 13:34:17 -040094/* Check that _code compiles in a method environment */
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040095#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
96 inline void _compiles_assertion_on_line_##_line (void) const \
Behdad Esfahbodf6796352010-05-13 13:34:17 -040097 { _code; }
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040098# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
99# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -0400100
101
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400102#define DEFINE_SIZE_STATIC(size) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400103 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400104 static const unsigned int static_size = (size); \
105 static const unsigned int min_size = (size)
106
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400107/* Size signifying variable-sized array */
108#define VAR 1
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400109
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400110#define DEFINE_SIZE_UNION(size, _member) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400111 DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400112 static const unsigned int min_size = (size)
113
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400114#define DEFINE_SIZE_MIN(size) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400115 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400116 static const unsigned int min_size = (size)
117
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400118#define DEFINE_SIZE_ARRAY(size, array) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400119 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
120 DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400121 static const unsigned int min_size = (size)
122
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400123#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400124 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
125 DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400126 static const unsigned int min_size = (size)
127
128
129
130/*
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400131 * Null objects
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400132 */
133
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400134/* Global nul-content Null pool. Enlarge as necessary. */
Behdad Esfahbod0bb0f5d2012-06-07 17:42:48 -0400135/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
Behdad Esfahbodcf5585c2010-05-19 12:03:35 -0400136static const void *_NullPool[64 / sizeof (void *)];
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400137
Behdad Esfahbodd2c2ca82010-05-10 19:58:25 -0400138/* Generic nul-content Null objects. */
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400139template <typename Type>
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400140static inline const Type& Null (void) {
Behdad Esfahbodfd0de882012-11-15 10:47:14 -0800141 ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400142 return *CastP<Type> (_NullPool);
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400143}
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400144
145/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400146#define DEFINE_NULL_DATA(Type, data) \
Behdad Esfahbodfd0de882012-11-15 10:47:14 -0800147static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400148template <> \
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400149inline const Type& Null<Type> (void) { \
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400150 return *CastP<Type> (_Null##Type); \
Behdad Esfahbod565c80b2010-04-22 10:26:35 -0400151} /* The following line really exists such that we end in a place needing semicolon */ \
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400152ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400153
154/* Accessor macro. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400155#define Null(Type) Null<Type>()
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400156
157
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400158
159/*
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400160 * Sanitize
161 */
162
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400163#ifndef HB_DEBUG_SANITIZE
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400164#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400165#endif
166
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400167
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400168#define TRACE_SANITIZE() \
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200169 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400170
171
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400172struct hb_sanitize_context_t
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400173{
Behdad Esfahbod31f18ab2011-06-15 09:49:58 -0400174 inline void init (hb_blob_t *b)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400175 {
Behdad Esfahbod31f18ab2011-06-15 09:49:58 -0400176 this->blob = hb_blob_reference (b);
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400177 this->writable = false;
178 }
179
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200180 inline void start_processing (void)
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400181 {
Behdad Esfahbod4101ca72011-05-11 14:30:56 -0400182 this->start = hb_blob_get_data (this->blob, NULL);
183 this->end = this->start + hb_blob_get_length (this->blob);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400184 this->edit_count = 0;
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400185 this->debug_depth = 0;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400186
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200187 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200188 "start [%p..%p] (%lu bytes)",
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200189 this->start, this->end,
190 (unsigned long) (this->end - this->start));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400191 }
192
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200193 inline void end_processing (void)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400194 {
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200195 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200196 "end [%p..%p] %u edit requests",
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200197 this->start, this->end, this->edit_count);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400198
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400199 hb_blob_destroy (this->blob);
200 this->blob = NULL;
201 this->start = this->end = NULL;
202 }
203
Behdad Esfahbod4ad2cc52010-05-06 09:24:24 -0400204 inline bool check_range (const void *base, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400205 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400206 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400207
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200208 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
209 "check_range [%p..%p] (%d bytes) in [%p..%p]",
210 p, p + len, len,
211 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400212
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200213 return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400214 }
215
Behdad Esfahbod1cd1e112010-05-05 20:15:14 -0400216 inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400217 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400218 const char *p = (const char *) base;
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400219 bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400220
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200221 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
222 "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
223 p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
224 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400225
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200226 return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400227 }
228
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400229 template <typename Type>
230 inline bool check_struct (const Type *obj) const
231 {
Behdad Esfahbod54842372010-05-10 18:13:32 -0400232 return likely (this->check_range (obj, obj->min_size));
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400233 }
234
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200235 inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400236 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400237 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400238 this->edit_count++;
239
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200240 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
241 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
242 this->edit_count,
243 p, p + len, len,
244 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400245
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200246 return TRACE_RETURN (this->writable);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400247 }
248
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200249 mutable unsigned int debug_depth;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400250 const char *start, *end;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400251 bool writable;
Behdad Esfahbod254933c2010-04-23 13:57:10 -0400252 unsigned int edit_count;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400253 hb_blob_t *blob;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400254};
255
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400256
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400257
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400258/* Template to sanitize an object. */
259template <typename Type>
260struct Sanitizer
261{
262 static hb_blob_t *sanitize (hb_blob_t *blob) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400263 hb_sanitize_context_t c[1] = {{0}};
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400264 bool sane;
265
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400266 /* TODO is_sane() stuff */
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400267
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400268 c->init (blob);
269
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400270 retry:
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400271 DEBUG_MSG_FUNC (SANITIZE, blob, "start");
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400272
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200273 c->start_processing ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400274
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400275 if (unlikely (!c->start)) {
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200276 c->end_processing ();
Behdad Esfahbod48146e52010-05-10 20:07:56 -0400277 return blob;
278 }
279
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400280 Type *t = CastP<Type> (const_cast<char *> (c->start));
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400281
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400282 sane = t->sanitize (c);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400283 if (sane) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400284 if (c->edit_count) {
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400285 DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
Behdad Esfahbodfa030172010-04-29 13:48:26 -0400286
Behdad Esfahbod8b534612009-08-19 18:16:50 -0400287 /* sanitize again to ensure no toe-stepping */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400288 c->edit_count = 0;
289 sane = t->sanitize (c);
290 if (c->edit_count) {
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400291 DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400292 sane = false;
293 }
294 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400295 } else {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400296 unsigned int edit_count = c->edit_count;
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400297 if (edit_count && !c->writable) {
298 c->start = hb_blob_get_data_writable (blob, NULL);
299 c->end = c->start + hb_blob_get_length (blob);
300
301 if (c->start) {
302 c->writable = true;
303 /* ok, we made it writable by relocating. try again */
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400304 DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400305 goto retry;
306 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400307 }
308 }
309
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200310 c->end_processing ();
Behdad Esfahbod4101ca72011-05-11 14:30:56 -0400311
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400312 DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400313 if (sane)
314 return blob;
315 else {
316 hb_blob_destroy (blob);
Behdad Esfahbod49110622011-05-02 19:36:39 -0400317 return hb_blob_get_empty ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400318 }
319 }
Behdad Esfahbodb435ab72010-05-10 19:51:57 -0400320
321 static const Type* lock_instance (hb_blob_t *blob) {
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400322 hb_blob_make_immutable (blob);
323 const char *base = hb_blob_get_data (blob, NULL);
Behdad Esfahbodb435ab72010-05-10 19:51:57 -0400324 return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
325 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400326};
327
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400328
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400329
Behdad Esfahbode901b952012-08-29 20:26:08 -0400330/*
331 * Serialize
332 */
333
334#ifndef HB_DEBUG_SERIALIZE
335#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
336#endif
337
338
339#define TRACE_SERIALIZE() \
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400340 hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE", c, HB_FUNC, "");
Behdad Esfahbode901b952012-08-29 20:26:08 -0400341
342
343struct hb_serialize_context_t
344{
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400345 inline hb_serialize_context_t (void *start, unsigned int size)
Behdad Esfahbode901b952012-08-29 20:26:08 -0400346 {
347 this->start = (char *) start;
348 this->end = this->start + size;
Behdad Esfahbode901b952012-08-29 20:26:08 -0400349
Behdad Esfahbode901b952012-08-29 20:26:08 -0400350 this->ran_out_of_room = false;
351 this->head = this->start;
352 this->debug_depth = 0;
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400353 }
Behdad Esfahbode901b952012-08-29 20:26:08 -0400354
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400355 template <typename Type>
356 inline Type *start_serialize (void)
357 {
Behdad Esfahbode901b952012-08-29 20:26:08 -0400358 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
359 "start [%p..%p] (%lu bytes)",
360 this->start, this->end,
361 (unsigned long) (this->end - this->start));
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400362
363 return start_embed<Type> ();
Behdad Esfahbode901b952012-08-29 20:26:08 -0400364 }
365
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400366 inline void end_serialize (void)
Behdad Esfahbode901b952012-08-29 20:26:08 -0400367 {
368 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400369 "end [%p..%p] serialized %d bytes; %s",
Behdad Esfahbode901b952012-08-29 20:26:08 -0400370 this->start, this->end,
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400371 (int) (this->head - this->start),
Behdad Esfahbode901b952012-08-29 20:26:08 -0400372 this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
373
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400374 }
375
376 template <typename Type>
377 inline Type *copy (void)
378 {
379 assert (!this->ran_out_of_room);
380 unsigned int len = this->head - this->start;
381 void *p = malloc (len);
382 if (p)
383 memcpy (p, this->start, len);
384 return reinterpret_cast<Type *> (p);
Behdad Esfahbode901b952012-08-29 20:26:08 -0400385 }
386
387 template <typename Type>
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400388 inline Type *allocate_size (unsigned int size)
Behdad Esfahbode901b952012-08-29 20:26:08 -0400389 {
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400390 if (unlikely (this->ran_out_of_room || this->end - this->head < size)) {
Behdad Esfahbode901b952012-08-29 20:26:08 -0400391 this->ran_out_of_room = true;
392 return NULL;
393 }
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400394 memset (this->head, 0, size);
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400395 char *ret = this->head;
Behdad Esfahbode901b952012-08-29 20:26:08 -0400396 this->head += size;
397 return reinterpret_cast<Type *> (ret);
398 }
399
400 template <typename Type>
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400401 inline Type *allocate_min (void)
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400402 {
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400403 return this->allocate_size<Type> (Type::min_size);
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400404 }
405
406 template <typename Type>
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400407 inline Type *start_embed (void)
408 {
409 Type *ret = reinterpret_cast<Type *> (this->head);
410 return ret;
411 }
412
413 template <typename Type>
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400414 inline Type *embed (const Type &obj)
Behdad Esfahbode901b952012-08-29 20:26:08 -0400415 {
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400416 unsigned int size = obj.get_size ();
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400417 Type *ret = this->allocate_size<Type> (size);
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400418 if (unlikely (!ret)) return NULL;
419 memcpy (ret, obj, size);
420 return ret;
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400421 }
422
423 template <typename Type>
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400424 inline Type *extend_min (Type &obj)
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400425 {
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400426 unsigned int size = obj.min_size;
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400427 assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
428 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400429 return reinterpret_cast<Type *> (&obj);
430 }
431
432 template <typename Type>
Behdad Esfahbod4b312fb2012-09-01 21:56:06 -0400433 inline Type *extend (Type &obj)
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400434 {
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400435 unsigned int size = obj.get_size ();
436 assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
Behdad Esfahbod811eefe2012-09-10 09:56:27 -0400437 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400438 return reinterpret_cast<Type *> (&obj);
Behdad Esfahbode901b952012-08-29 20:26:08 -0400439 }
440
441 inline void truncate (void *head)
442 {
443 assert (this->start < head && head <= this->head);
444 this->head = (char *) head;
445 }
446
447 unsigned int debug_depth;
448 char *start, *end, *head;
449 bool ran_out_of_room;
450};
451
Behdad Esfahboda930c682012-09-04 18:17:57 -0400452template <typename Type>
453struct Supplier
454{
Behdad Esfahboda930c682012-09-04 18:17:57 -0400455 inline Supplier (const Type *array, unsigned int len_)
456 {
457 head = array;
458 len = len_;
459 }
460 inline const Type operator [] (unsigned int i) const
461 {
462 if (unlikely (i >= len)) return Type ();
463 return head[i];
464 }
465
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400466 inline void advance (unsigned int count)
467 {
Behdad Esfahboda930c682012-09-04 18:17:57 -0400468 if (unlikely (count > len))
469 count = len;
470 len -= count;
471 head += count;
472 }
473
474 private:
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400475 inline Supplier (const Supplier<Type> &); /* Disallow copy */
476 inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
477
Behdad Esfahboda930c682012-09-04 18:17:57 -0400478 unsigned int len;
479 const Type *head;
480};
481
482
Behdad Esfahbode901b952012-08-29 20:26:08 -0400483
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400484
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500485/*
486 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400487 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500488 */
489
490
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500491/* "The following data types are used in the OpenType font file.
492 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500493
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400494/*
495 * Int types
496 */
497
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400498
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400499template <typename Type, int Bytes> struct BEInt;
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500500
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400501template <typename Type>
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400502struct BEInt<Type, 2>
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400503{
504 public:
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400505 inline void set (Type i) { hb_be_uint16_put (v,i); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400506 inline operator Type (void) const { return hb_be_uint16_get (v); }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400507 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400508 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400509 private: uint8_t v[2];
510};
511template <typename Type>
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400512struct BEInt<Type, 4>
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400513{
514 public:
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400515 inline void set (Type i) { hb_be_uint32_put (v,i); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400516 inline operator Type (void) const { return hb_be_uint32_get (v); }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400517 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400518 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400519 private: uint8_t v[4];
520};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500521
Behdad Esfahbod2467c662010-04-21 23:11:45 -0400522/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400523template <typename Type>
524struct IntType
525{
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400526 inline void set (Type i) { v.set (i); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400527 inline operator Type(void) const { return v; }
528 inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
529 inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400530 static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { return b->cmp (*a); }
531 inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
Behdad Esfahbod4e573712010-09-28 16:23:58 -0400532 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400533 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400534 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200535 return TRACE_RETURN (likely (c->check_struct (this)));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400536 }
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400537 protected:
Behdad Esfahbod569da922010-05-10 16:38:32 -0400538 BEInt<Type, sizeof (Type)> v;
539 public:
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400540 DEFINE_SIZE_STATIC (sizeof (Type));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400541};
542
543typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
544typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
545typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
546typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
547
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200548/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
549typedef SHORT FWORD;
550
551/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
552typedef USHORT UFWORD;
553
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400554/* Date represented in number of seconds since 12:00 midnight, January 1,
555 * 1904. The value is represented as a signed 64-bit integer. */
556struct LONGDATETIME
557{
558 inline bool sanitize (hb_sanitize_context_t *c) {
559 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200560 return TRACE_RETURN (likely (c->check_struct (this)));
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400561 }
562 private:
563 LONG major;
564 ULONG minor;
565 public:
566 DEFINE_SIZE_STATIC (8);
567};
568
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500569/* Array of four uint8s (length = 32 bits) used to identify a script, language
570 * system, feature, or baseline */
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400571struct Tag : ULONG
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400572{
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500573 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400574 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
575 inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400576 public:
577 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500578};
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400579DEFINE_NULL_DATA (Tag, " ");
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500580
581/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400582typedef USHORT GlyphID;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500583
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400584/* Script/language-system/feature index */
585struct Index : USHORT {
586 static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
587};
588DEFINE_NULL_DATA (Index, "\xff\xff");
589
Behdad Esfahbod1f437e62008-01-23 04:36:40 -0500590/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400591typedef USHORT Offset;
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400592
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400593/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
594typedef ULONG LongOffset;
595
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500596
597/* CheckSum */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400598struct CheckSum : ULONG
599{
600 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
601 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500602 uint32_t Sum = 0L;
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400603 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500604
605 while (Table < EndPtr)
606 Sum += *Table++;
607 return Sum;
608 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400609 public:
610 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500611};
612
613
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500614/*
615 * Version Numbers
616 */
617
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400618struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400619{
Behdad Esfahbod4f28fbd2011-05-31 12:33:11 -0400620 inline uint32_t to_int (void) const { return (major << 16) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400621
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400622 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400623 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200624 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400625 }
626
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400627 USHORT major;
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400628 USHORT minor;
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400629 public:
630 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500631};
632
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400633
634
635/*
636 * Template subclasses of Offset and LongOffset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400637 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400638 */
639
640template <typename OffsetType, typename Type>
641struct GenericOffsetTo : OffsetType
642{
Behdad Esfahbod00e23fc2010-04-20 23:50:45 -0400643 inline const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400644 {
645 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400646 if (unlikely (!offset)) return Null(Type);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400647 return StructAtOffset<Type> (base, offset);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400648 }
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400649 inline Type& operator () (void *base)
650 {
651 unsigned int offset = *this;
652 return StructAtOffset<Type> (base, offset);
653 }
654
Behdad Esfahbodabcc5ac2012-09-01 21:30:17 -0400655 inline Type& serialize (hb_serialize_context_t *c, void *base)
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400656 {
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400657 Type *t = c->start_embed<Type> ();
Behdad Esfahbod49120302012-09-03 20:58:03 -0400658 this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
Behdad Esfahbodabcc5ac2012-09-01 21:30:17 -0400659 return *t;
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400660 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400661
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400662 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400663 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200664 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400665 unsigned int offset = *this;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200666 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400667 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200668 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400669 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400670 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400671 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400672 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200673 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400674 unsigned int offset = *this;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200675 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400676 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200677 return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400678 }
679
680 private:
681 /* Set the offset to Null */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400682 inline bool neuter (hb_sanitize_context_t *c) {
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200683 if (c->may_edit (this, this->static_size)) {
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400684 this->set (0); /* 0 is Null offset */
685 return true;
686 }
687 return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400688 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400689};
690template <typename Base, typename OffsetType, typename Type>
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400691inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
692template <typename Base, typename OffsetType, typename Type>
693inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400694
695template <typename Type>
696struct OffsetTo : GenericOffsetTo<Offset, Type> {};
697
698template <typename Type>
699struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400700
701
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400702/*
703 * Array Types
704 */
705
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400706template <typename LenType, typename Type>
707struct GenericArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400708{
Behdad Esfahbod4f5f1c32010-04-22 00:27:39 -0400709 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500710 {
711 unsigned int count = len;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400712 if (unlikely (start_offset > count))
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500713 count = 0;
714 else
715 count -= start_offset;
716 count = MIN (count, *pcount);
717 *pcount = count;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400718 return array + start_offset;
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500719 }
720
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400721 inline const Type& operator [] (unsigned int i) const
722 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400723 if (unlikely (i >= len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400724 return array[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400725 }
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400726 inline Type& operator [] (unsigned int i)
727 {
728 return array[i];
729 }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400730 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400731 { return len.static_size + len * Type::static_size; }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400732
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400733 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400734 unsigned int items_len)
735 {
736 TRACE_SERIALIZE ();
737 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
738 len.set (items_len); /* TODO(serialize) Overflow? */
739 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
740 return TRACE_RETURN (true);
741 }
742
743 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400744 Supplier<Type> &items,
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400745 unsigned int items_len)
746 {
747 TRACE_SERIALIZE ();
Behdad Esfahbod715e03b2012-09-04 20:10:17 -0400748 if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
749 for (unsigned int i = 0; i < items_len; i++)
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400750 array[i] = items[i];
Behdad Esfahboda930c682012-09-04 18:17:57 -0400751 items.advance (items_len);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400752 return TRACE_RETURN (true);
753 }
754
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400755 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400756 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200757 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400758
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400759 /* Note: for structs that do not reference other structs,
760 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400761 * a bound check on the aggregate array size. We just include
762 * a small unreachable expression to make sure the structs
763 * pointed to do have a simple sanitize(), ie. they do not
764 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400765 */
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400766 (void) (false && array[0].sanitize (c));
767
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200768 return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400769 }
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400770 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400771 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200772 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400773 unsigned int count = len;
774 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400775 if (unlikely (!array[i].sanitize (c, base)))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200776 return TRACE_RETURN (false);
777 return TRACE_RETURN (true);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400778 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400779 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400780 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400781 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200782 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400783 unsigned int count = len;
784 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400785 if (unlikely (!array[i].sanitize (c, base, user_data)))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200786 return TRACE_RETURN (false);
787 return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400788 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400789
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400790 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400791 inline bool sanitize_shallow (hb_sanitize_context_t *c) {
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400792 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200793 return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400794 }
795
796 public:
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400797 LenType len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400798 Type array[VAR];
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400799 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400800 DEFINE_SIZE_ARRAY (sizeof (LenType), array);
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400801};
802
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400803/* An array with a USHORT number of elements. */
804template <typename Type>
805struct ArrayOf : GenericArrayOf<USHORT, Type> {};
806
807/* An array with a ULONG number of elements. */
808template <typename Type>
809struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
810
811/* Array of Offset's */
812template <typename Type>
813struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
814
815/* Array of LongOffset's */
816template <typename Type>
817struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
818
819/* LongArray of LongOffset's */
820template <typename Type>
821struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
822
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400823/* Array of offsets relative to the beginning of the array itself. */
824template <typename Type>
825struct OffsetListOf : OffsetArrayOf<Type>
826{
827 inline const Type& operator [] (unsigned int i) const
828 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400829 if (unlikely (i >= this->len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400830 return this+this->array[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400831 }
832
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400833 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400834 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200835 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400836 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400837 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400838 inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400839 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200840 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400841 }
842};
843
844
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400845/* An array with a USHORT number of elements,
846 * starting at second element. */
847template <typename Type>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400848struct HeadlessArrayOf
849{
850 inline const Type& operator [] (unsigned int i) const
851 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400852 if (unlikely (i >= len || !i)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400853 return array[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400854 }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400855 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400856 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400857
Behdad Esfahboda930c682012-09-04 18:17:57 -0400858 inline bool serialize (hb_serialize_context_t *c,
859 Supplier<Type> &items,
860 unsigned int items_len)
861 {
862 TRACE_SERIALIZE ();
863 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
864 len.set (items_len); /* TODO(serialize) Overflow? */
Behdad Esfahboda930c682012-09-04 18:17:57 -0400865 if (unlikely (!items_len)) return TRACE_RETURN (true);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400866 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
867 for (unsigned int i = 0; i < items_len - 1; i++)
868 array[i] = items[i];
Behdad Esfahboda930c682012-09-04 18:17:57 -0400869 items.advance (items_len - 1);
870 return TRACE_RETURN (true);
871 }
872
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400873 inline bool sanitize_shallow (hb_sanitize_context_t *c) {
874 return c->check_struct (this)
875 && c->check_array (this, Type::static_size, len);
Behdad Esfahbode5546a42010-04-22 00:45:42 -0400876 }
877
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400878 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400879 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200880 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400881
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400882 /* Note: for structs that do not reference other structs,
883 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400884 * a bound check on the aggregate array size. We just include
885 * a small unreachable expression to make sure the structs
886 * pointed to do have a simple sanitize(), ie. they do not
887 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400888 */
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400889 (void) (false && array[0].sanitize (c));
890
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200891 return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400892 }
893
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400894 USHORT len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400895 Type array[VAR];
Behdad Esfahboded074222010-05-10 18:08:46 -0400896 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400897 DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400898};
899
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500900
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400901/* An array with sorted elements. Supports binary searching. */
902template <typename Type>
903struct SortedArrayOf : ArrayOf<Type> {
904
905 template <typename SearchType>
906 inline int search (const SearchType &x) const {
Behdad Esfahbod99159e52012-06-09 00:50:40 -0400907 unsigned int count = this->len;
908 /* Linear search is *much* faster for small counts. */
909 if (likely (count < 32)) {
910 for (unsigned int i = 0; i < count; i++)
911 if (this->array[i].cmp (x) == 0)
912 return i;
913 return -1;
914 } else {
915 struct Cmp {
916 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
917 };
918 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
919 return p ? p - this->array : -1;
920 }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400921 }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400922};
923
924
Behdad Esfahbod7d52e662012-11-16 18:49:54 -0800925} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400926
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400927
Behdad Esfahbod1e914342009-11-04 18:12:09 -0500928#endif /* HB_OPEN_TYPE_PRIVATE_HH */