blob: 4d8c507fbc94c6049167accfb59388d7de91856a [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 Esfahboda3263aa2010-04-22 18:29:09 -040037
Behdad Esfahbod196598b2009-08-04 11:04:32 -040038/*
39 * Casts
40 */
41
Behdad Esfahbod187454c2010-04-23 16:35:01 -040042/* Cast to struct T, reference to reference */
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040043template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040044inline const Type& CastR(const TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040045{ return reinterpret_cast<const Type&> (X); }
46template<typename Type, typename TObject>
Behdad Esfahbod187454c2010-04-23 16:35:01 -040047inline Type& CastR(TObject &X)
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040048{ return reinterpret_cast<Type&> (X); }
Behdad Esfahbod196598b2009-08-04 11:04:32 -040049
Behdad Esfahbod187454c2010-04-23 16:35:01 -040050/* Cast to struct T, pointer to pointer */
51template<typename Type, typename TObject>
52inline const Type* CastP(const TObject *X)
53{ return reinterpret_cast<const Type*> (X); }
54template<typename Type, typename TObject>
55inline Type* CastP(TObject *X)
56{ return reinterpret_cast<Type*> (X); }
57
Behdad Esfahbod09766b12010-05-10 17:36:03 -040058/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
59 * location pointed to by P plus Ofs bytes. */
60template<typename Type>
61inline const Type& StructAtOffset(const void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040062{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
Behdad Esfahbod09766b12010-05-10 17:36:03 -040063template<typename Type>
64inline Type& StructAtOffset(void *P, unsigned int offset)
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040065{ return * reinterpret_cast<Type*> ((char *) P + offset); }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040066
Behdad Esfahbod2e2f43e2010-04-21 22:30:36 -040067/* StructAfter<T>(X) returns the struct T& that is placed after X.
Behdad Esfahbod29c3f5e2010-04-21 23:01:00 -040068 * Works with X of variable size also. X must implement get_size() */
Behdad Esfahbode961c862010-04-21 15:56:11 -040069template<typename Type, typename TObject>
70inline const Type& StructAfter(const TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040071{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahbode961c862010-04-21 15:56:11 -040072template<typename Type, typename TObject>
73inline Type& StructAfter(TObject &X)
Behdad Esfahbod09766b12010-05-10 17:36:03 -040074{ return StructAtOffset<Type>(&X, X.get_size()); }
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040075
Behdad Esfahbode961c862010-04-21 15:56:11 -040076
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -050077
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040078/*
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040079 * Size checking
80 */
81
Behdad Esfahbodf6796352010-05-13 13:34:17 -040082/* Check _assertion in a method environment */
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040083#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
84 inline void _instance_assertion_on_line_##_line (void) const \
85 { \
86 ASSERT_STATIC (_assertion); \
87 ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
88 }
89# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
90# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
91
Behdad Esfahbodf6796352010-05-13 13:34:17 -040092/* Check that _code compiles in a method environment */
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040093#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
94 inline void _compiles_assertion_on_line_##_line (void) const \
Behdad Esfahbodf6796352010-05-13 13:34:17 -040095 { _code; }
Behdad Esfahboda00a63b2012-06-06 03:07:01 -040096# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
97# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
Behdad Esfahbod0abcc3b2010-05-10 17:04:20 -040098
99
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400100#define DEFINE_SIZE_STATIC(size) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400101 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400102 static const unsigned int static_size = (size); \
103 static const unsigned int min_size = (size)
104
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400105/* Size signifying variable-sized array */
106#define VAR 1
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400107
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400108#define DEFINE_SIZE_UNION(size, _member) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400109 DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400110 static const unsigned int min_size = (size)
111
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400112#define DEFINE_SIZE_MIN(size) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400113 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400114 static const unsigned int min_size = (size)
115
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400116#define DEFINE_SIZE_ARRAY(size, array) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400117 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
118 DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400119 static const unsigned int min_size = (size)
120
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400121#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400122 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
123 DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400124 static const unsigned int min_size = (size)
125
126
127
128/*
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400129 * Null objects
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400130 */
131
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400132/* Global nul-content Null pool. Enlarge as necessary. */
Behdad Esfahbod0bb0f5d2012-06-07 17:42:48 -0400133/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
Behdad Esfahbodcf5585c2010-05-19 12:03:35 -0400134static const void *_NullPool[64 / sizeof (void *)];
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400135
Behdad Esfahbodd2c2ca82010-05-10 19:58:25 -0400136/* Generic nul-content Null objects. */
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400137template <typename Type>
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400138static inline const Type& Null (void) {
Behdad Esfahboded074222010-05-10 18:08:46 -0400139 ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400140 return *CastP<Type> (_NullPool);
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400141}
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400142
143/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400144#define DEFINE_NULL_DATA(Type, data) \
145static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400146template <> \
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400147inline const Type& Null<Type> (void) { \
Behdad Esfahbod187454c2010-04-23 16:35:01 -0400148 return *CastP<Type> (_Null##Type); \
Behdad Esfahbod565c80b2010-04-22 10:26:35 -0400149} /* The following line really exists such that we end in a place needing semicolon */ \
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400150ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400151
152/* Accessor macro. */
Behdad Esfahbod9d367782010-04-21 00:32:47 -0400153#define Null(Type) Null<Type>()
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400154
155
Behdad Esfahbod577c1112009-08-04 19:31:02 -0400156
157/*
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400158 * Sanitize
159 */
160
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400161#ifndef HB_DEBUG_SANITIZE
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400162#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
Behdad Esfahbod95e20242009-08-28 16:31:20 -0400163#endif
164
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400165
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400166#define TRACE_SANITIZE() \
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200167 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
Behdad Esfahbod807c5b02010-04-28 20:25:22 -0400168
169
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400170struct hb_sanitize_context_t
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400171{
Behdad Esfahbod31f18ab2011-06-15 09:49:58 -0400172 inline void init (hb_blob_t *b)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400173 {
Behdad Esfahbod31f18ab2011-06-15 09:49:58 -0400174 this->blob = hb_blob_reference (b);
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400175 this->writable = false;
176 }
177
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200178 inline void start_processing (void)
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400179 {
Behdad Esfahbod4101ca72011-05-11 14:30:56 -0400180 this->start = hb_blob_get_data (this->blob, NULL);
181 this->end = this->start + hb_blob_get_length (this->blob);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400182 this->edit_count = 0;
Behdad Esfahbod20e3dd52010-05-04 23:21:57 -0400183 this->debug_depth = 0;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400184
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200185 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200186 "start [%p..%p] (%lu bytes)",
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200187 this->start, this->end,
188 (unsigned long) (this->end - this->start));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400189 }
190
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200191 inline void end_processing (void)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400192 {
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200193 DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200194 "end [%p..%p] %u edit requests",
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200195 this->start, this->end, this->edit_count);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400196
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400197 hb_blob_destroy (this->blob);
198 this->blob = NULL;
199 this->start = this->end = NULL;
200 }
201
Behdad Esfahbod4ad2cc52010-05-06 09:24:24 -0400202 inline bool check_range (const void *base, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400203 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400204 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400205
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200206 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
207 "check_range [%p..%p] (%d bytes) in [%p..%p]",
208 p, p + len, len,
209 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400210
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200211 return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400212 }
213
Behdad Esfahbod1cd1e112010-05-05 20:15:14 -0400214 inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400215 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400216 const char *p = (const char *) base;
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400217 bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400218
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200219 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
220 "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
221 p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
222 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400223
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200224 return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400225 }
226
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400227 template <typename Type>
228 inline bool check_struct (const Type *obj) const
229 {
Behdad Esfahbod54842372010-05-10 18:13:32 -0400230 return likely (this->check_range (obj, obj->min_size));
Behdad Esfahbodb1576172010-05-06 14:48:27 -0400231 }
232
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200233 inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400234 {
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400235 const char *p = (const char *) base;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400236 this->edit_count++;
237
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200238 hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
239 "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
240 this->edit_count,
241 p, p + len, len,
242 this->start, this->end);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400243
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200244 return TRACE_RETURN (this->writable);
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400245 }
246
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200247 mutable unsigned int debug_depth;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400248 const char *start, *end;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400249 bool writable;
Behdad Esfahbod254933c2010-04-23 13:57:10 -0400250 unsigned int edit_count;
Behdad Esfahbod98daaf12010-05-04 22:42:49 -0400251 hb_blob_t *blob;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400252};
253
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400254
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400255
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400256/* Template to sanitize an object. */
257template <typename Type>
258struct Sanitizer
259{
260 static hb_blob_t *sanitize (hb_blob_t *blob) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400261 hb_sanitize_context_t c[1] = {{0}};
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400262 bool sane;
263
Behdad Esfahbodd0b65732009-08-06 18:34:47 -0400264 /* TODO is_sane() stuff */
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400265
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400266 c->init (blob);
267
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400268 retry:
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400269 DEBUG_MSG_FUNC (SANITIZE, blob, "start");
Behdad Esfahbod4f3ad912009-08-04 23:01:23 -0400270
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200271 c->start_processing ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400272
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400273 if (unlikely (!c->start)) {
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200274 c->end_processing ();
Behdad Esfahbod48146e52010-05-10 20:07:56 -0400275 return blob;
276 }
277
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400278 Type *t = CastP<Type> (const_cast<char *> (c->start));
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400279
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400280 sane = t->sanitize (c);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400281 if (sane) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400282 if (c->edit_count) {
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400283 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 -0400284
Behdad Esfahbod8b534612009-08-19 18:16:50 -0400285 /* sanitize again to ensure no toe-stepping */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400286 c->edit_count = 0;
287 sane = t->sanitize (c);
288 if (c->edit_count) {
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400289 DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400290 sane = false;
291 }
292 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400293 } else {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400294 unsigned int edit_count = c->edit_count;
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400295 if (edit_count && !c->writable) {
296 c->start = hb_blob_get_data_writable (blob, NULL);
297 c->end = c->start + hb_blob_get_length (blob);
298
299 if (c->start) {
300 c->writable = true;
301 /* ok, we made it writable by relocating. try again */
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400302 DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400303 goto retry;
304 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400305 }
306 }
307
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200308 c->end_processing ();
Behdad Esfahbod4101ca72011-05-11 14:30:56 -0400309
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400310 DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400311 if (sane)
312 return blob;
313 else {
314 hb_blob_destroy (blob);
Behdad Esfahbod49110622011-05-02 19:36:39 -0400315 return hb_blob_get_empty ();
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400316 }
317 }
Behdad Esfahbodb435ab72010-05-10 19:51:57 -0400318
319 static const Type* lock_instance (hb_blob_t *blob) {
Behdad Esfahbod1c9f8712011-05-06 22:28:26 -0400320 hb_blob_make_immutable (blob);
321 const char *base = hb_blob_get_data (blob, NULL);
Behdad Esfahbodb435ab72010-05-10 19:51:57 -0400322 return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
323 }
Behdad Esfahbod4e8a0602009-08-04 20:52:47 -0400324};
325
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400326
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400327
328
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500329/*
330 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400331 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500332 */
333
334
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500335/* "The following data types are used in the OpenType font file.
336 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500337
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400338/*
339 * Int types
340 */
341
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400342
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400343template <typename Type, int Bytes> struct BEInt;
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -0500344
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400345template <typename Type>
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400346struct BEInt<Type, 2>
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400347{
348 public:
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400349 inline void set (Type i) { hb_be_uint16_put (v,i); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400350 inline operator Type (void) const { return hb_be_uint16_get (v); }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400351 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400352 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400353 private: uint8_t v[2];
354};
355template <typename Type>
Behdad Esfahbodd7bf4732011-08-05 18:18:21 -0400356struct BEInt<Type, 4>
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400357{
358 public:
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400359 inline void set (Type i) { hb_be_uint32_put (v,i); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400360 inline operator Type (void) const { return hb_be_uint32_get (v); }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400361 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400362 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400363 private: uint8_t v[4];
364};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500365
Behdad Esfahbod2467c662010-04-21 23:11:45 -0400366/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400367template <typename Type>
368struct IntType
369{
Behdad Esfahbod81408cd2010-07-23 14:46:57 -0400370 inline void set (Type i) { v.set (i); }
Behdad Esfahbod01c01612010-04-21 22:49:56 -0400371 inline operator Type(void) const { return v; }
372 inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
373 inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
Behdad Esfahbod4e573712010-09-28 16:23:58 -0400374 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400375 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400376 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200377 return TRACE_RETURN (likely (c->check_struct (this)));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400378 }
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400379 protected:
Behdad Esfahbod569da922010-05-10 16:38:32 -0400380 BEInt<Type, sizeof (Type)> v;
381 public:
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400382 DEFINE_SIZE_STATIC (sizeof (Type));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400383};
384
Behdad Esfahbodf60271c2011-08-02 09:56:30 -0400385/* Typedef these to avoid clash with windows.h */
386#define USHORT HB_USHORT
387#define SHORT HB_SHORT
388#define ULONG HB_ULONG
389#define LONG HB_LONG
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400390typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
391typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
392typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
393typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
394
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200395/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
396typedef SHORT FWORD;
397
398/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
399typedef USHORT UFWORD;
400
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400401/* Date represented in number of seconds since 12:00 midnight, January 1,
402 * 1904. The value is represented as a signed 64-bit integer. */
403struct LONGDATETIME
404{
405 inline bool sanitize (hb_sanitize_context_t *c) {
406 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200407 return TRACE_RETURN (likely (c->check_struct (this)));
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400408 }
409 private:
410 LONG major;
411 ULONG minor;
412 public:
413 DEFINE_SIZE_STATIC (8);
414};
415
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500416/* Array of four uint8s (length = 32 bits) used to identify a script, language
417 * system, feature, or baseline */
Behdad Esfahbod20cc86b2009-05-25 02:41:49 -0400418struct Tag : ULONG
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400419{
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500420 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400421 inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
422 inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400423 public:
424 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500425};
Behdad Esfahbod65f46b02010-05-06 19:35:19 -0400426DEFINE_NULL_DATA (Tag, " ");
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500427
428/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400429typedef USHORT GlyphID;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500430
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400431/* Script/language-system/feature index */
432struct Index : USHORT {
433 static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
434};
435DEFINE_NULL_DATA (Index, "\xff\xff");
436
Behdad Esfahbod1f437e62008-01-23 04:36:40 -0500437/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400438typedef USHORT Offset;
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400439
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400440/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
441typedef ULONG LongOffset;
442
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500443
444/* CheckSum */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400445struct CheckSum : ULONG
446{
447 static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
448 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500449 uint32_t Sum = 0L;
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400450 ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500451
452 while (Table < EndPtr)
453 Sum += *Table++;
454 return Sum;
455 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400456 public:
457 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500458};
459
460
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500461/*
462 * Version Numbers
463 */
464
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400465struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400466{
Behdad Esfahbod4f28fbd2011-05-31 12:33:11 -0400467 inline uint32_t to_int (void) const { return (major << 16) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400468
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400469 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400470 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200471 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400472 }
473
Behdad Esfahbod6ad8d5f2009-05-25 02:27:29 -0400474 USHORT major;
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400475 USHORT minor;
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400476 public:
477 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500478};
479
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400480
481
482/*
483 * Template subclasses of Offset and LongOffset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400484 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400485 */
486
487template <typename OffsetType, typename Type>
488struct GenericOffsetTo : OffsetType
489{
Behdad Esfahbod00e23fc2010-04-20 23:50:45 -0400490 inline const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400491 {
492 unsigned int offset = *this;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400493 if (unlikely (!offset)) return Null(Type);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400494 return StructAtOffset<Type> (base, offset);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400495 }
496
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400497 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400498 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200499 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400500 unsigned int offset = *this;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200501 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400502 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200503 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400504 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400505 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400506 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400507 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200508 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400509 unsigned int offset = *this;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200510 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400511 Type &obj = StructAtOffset<Type> (base, offset);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200512 return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400513 }
514
515 private:
516 /* Set the offset to Null */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400517 inline bool neuter (hb_sanitize_context_t *c) {
Behdad Esfahbodcf26e882012-05-11 03:16:57 +0200518 if (c->may_edit (this, this->static_size)) {
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400519 this->set (0); /* 0 is Null offset */
520 return true;
521 }
522 return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400523 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400524};
525template <typename Base, typename OffsetType, typename Type>
526inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
527
528template <typename Type>
529struct OffsetTo : GenericOffsetTo<Offset, Type> {};
530
531template <typename Type>
532struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400533
534
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400535/*
536 * Array Types
537 */
538
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400539template <typename LenType, typename Type>
540struct GenericArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400541{
Behdad Esfahbod4f5f1c32010-04-22 00:27:39 -0400542 const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500543 {
544 unsigned int count = len;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400545 if (unlikely (start_offset > count))
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500546 count = 0;
547 else
548 count -= start_offset;
549 count = MIN (count, *pcount);
550 *pcount = count;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400551 return array + start_offset;
Behdad Esfahbod48de3732009-11-04 16:59:50 -0500552 }
553
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400554 inline const Type& operator [] (unsigned int i) const
555 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400556 if (unlikely (i >= len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400557 return array[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400558 }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400559 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400560 { return len.static_size + len * Type::static_size; }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400561
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400562 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400563 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200564 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400565
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400566 /* Note: for structs that do not reference other structs,
567 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400568 * a bound check on the aggregate array size. We just include
569 * a small unreachable expression to make sure the structs
570 * pointed to do have a simple sanitize(), ie. they do not
571 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400572 */
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400573 (void) (false && array[0].sanitize (c));
574
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200575 return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400576 }
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400577 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400578 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200579 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400580 unsigned int count = len;
581 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400582 if (unlikely (!array[i].sanitize (c, base)))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200583 return TRACE_RETURN (false);
584 return TRACE_RETURN (true);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400585 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400586 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400587 inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400588 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200589 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400590 unsigned int count = len;
591 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400592 if (unlikely (!array[i].sanitize (c, base, user_data)))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200593 return TRACE_RETURN (false);
594 return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400595 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400596
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400597 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400598 inline bool sanitize_shallow (hb_sanitize_context_t *c) {
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400599 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200600 return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400601 }
602
603 public:
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400604 LenType len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400605 Type array[VAR];
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400606 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400607 DEFINE_SIZE_ARRAY (sizeof (LenType), array);
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400608};
609
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400610/* An array with a USHORT number of elements. */
611template <typename Type>
612struct ArrayOf : GenericArrayOf<USHORT, Type> {};
613
614/* An array with a ULONG number of elements. */
615template <typename Type>
616struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
617
618/* Array of Offset's */
619template <typename Type>
620struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
621
622/* Array of LongOffset's */
623template <typename Type>
624struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
625
626/* LongArray of LongOffset's */
627template <typename Type>
628struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
629
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400630/* Array of offsets relative to the beginning of the array itself. */
631template <typename Type>
632struct OffsetListOf : OffsetArrayOf<Type>
633{
634 inline const Type& operator [] (unsigned int i) const
635 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400636 if (unlikely (i >= this->len)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400637 return this+this->array[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400638 }
639
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400640 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400641 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200642 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400643 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400644 template <typename T>
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400645 inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400646 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200647 return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400648 }
649};
650
651
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400652/* An array with a USHORT number of elements,
653 * starting at second element. */
654template <typename Type>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400655struct HeadlessArrayOf
656{
657 inline const Type& operator [] (unsigned int i) const
658 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400659 if (unlikely (i >= len || !i)) return Null(Type);
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400660 return array[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400661 }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400662 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400663 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400664
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400665 inline bool sanitize_shallow (hb_sanitize_context_t *c) {
666 return c->check_struct (this)
667 && c->check_array (this, Type::static_size, len);
Behdad Esfahbode5546a42010-04-22 00:45:42 -0400668 }
669
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400670 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400671 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200672 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400673
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400674 /* Note: for structs that do not reference other structs,
675 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400676 * a bound check on the aggregate array size. We just include
677 * a small unreachable expression to make sure the structs
678 * pointed to do have a simple sanitize(), ie. they do not
679 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400680 */
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400681 (void) (false && array[0].sanitize (c));
682
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200683 return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400684 }
685
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400686 USHORT len;
Behdad Esfahbodb9615182010-05-10 18:20:54 -0400687 Type array[VAR];
Behdad Esfahboded074222010-05-10 18:08:46 -0400688 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400689 DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400690};
691
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500692
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400693/* An array with sorted elements. Supports binary searching. */
694template <typename Type>
695struct SortedArrayOf : ArrayOf<Type> {
696
697 template <typename SearchType>
698 inline int search (const SearchType &x) const {
Behdad Esfahbod99159e52012-06-09 00:50:40 -0400699 unsigned int count = this->len;
700 /* Linear search is *much* faster for small counts. */
701 if (likely (count < 32)) {
702 for (unsigned int i = 0; i < count; i++)
703 if (this->array[i].cmp (x) == 0)
704 return i;
705 return -1;
706 } else {
707 struct Cmp {
708 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
709 };
710 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
711 return p ? p - this->array : -1;
712 }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400713 }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400714};
715
716
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400717
Behdad Esfahbod1e914342009-11-04 18:12:09 -0500718#endif /* HB_OPEN_TYPE_PRIVATE_HH */