blob: 52e5f6db1ea2c675327bdd15864445a97241c33c [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 Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OPEN_TYPE_HH
30#define HB_OPEN_TYPE_HH
Behdad Esfahbod12c45682006-12-28 06:10:59 -050031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-blob.hh"
34#include "hb-face.hh"
35#include "hb-machinery.hh"
Behdad Esfahbodd1f29902018-08-31 16:31:00 -070036#include "hb-subset.hh"
Behdad Esfahbod12c45682006-12-28 06:10:59 -050037
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050038
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040039namespace OT {
40
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040041
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050042/*
43 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -040044 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050045 */
46
47
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -050048/* "The following data types are used in the OpenType font file.
49 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050050
Behdad Esfahbod5f810362009-05-17 00:54:25 -040051/*
52 * Int types
53 */
54
Behdad Esfahbod2467c662010-04-21 23:11:45 -040055/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbodbd61bc12012-12-11 16:00:43 -050056template <typename Type, unsigned int Size>
Behdad Esfahbode032ed92010-04-21 03:11:46 -040057struct IntType
58{
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -070059 typedef Type type;
Behdad Esfahbod442f4a52018-12-28 14:34:00 -050060 typedef typename hb_signedness_int (hb_is_signed (Type)) wide_type;
Behdad Esfahbod11d2f492018-12-01 13:12:21 -050061
Behdad Esfahbod415f3f42018-12-31 13:37:13 -050062 //TODO(C++11)IntType<Type, Size>& operator = (wide_type v) { set (v); return *this; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033063 void set (wide_type i) { v.set (i); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033064 operator wide_type () const { return v; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033065 bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
66 bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
67 static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
Behdad Esfahbod4a27c172017-10-27 14:29:12 -060068 template <typename Type2>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033069 int cmp (Type2 a) const
Behdad Esfahbod88a399a2015-02-19 16:57:12 +030070 {
71 Type b = v;
Behdad Esfahbodc3a8b042018-12-01 00:14:48 -050072 if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
Behdad Esfahbod88a399a2015-02-19 16:57:12 +030073 return (int) a - (int) b;
74 else
75 return a < b ? -1 : a == b ? 0 : +1;
76 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033077 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +030078 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -050079 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +010080 return_trace (likely (c->check_struct (this)));
Behdad Esfahbode032ed92010-04-21 03:11:46 -040081 }
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -040082 protected:
Behdad Esfahbodbd61bc12012-12-11 16:00:43 -050083 BEInt<Type, Size> v;
Behdad Esfahbod569da922010-05-10 16:38:32 -040084 public:
Behdad Esfahbodbd61bc12012-12-11 16:00:43 -050085 DEFINE_SIZE_STATIC (Size);
Behdad Esfahbode032ed92010-04-21 03:11:46 -040086};
87
Behdad Esfahbodc3a8b042018-12-01 00:14:48 -050088typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */
89typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */
90typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */
91typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */
92typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */
93typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */
Behdad Esfahbod11d2f492018-12-01 13:12:21 -050094/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
95 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
Behdad Esfahbodc3a8b042018-12-01 00:14:48 -050096typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
Behdad Esfahbode032ed92010-04-21 03:11:46 -040097
Behdad Esfahbod6b191782018-01-10 03:07:30 +010098/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
99typedef HBINT16 FWORD;
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200100
Behdad Esfahbod22955b22018-10-10 19:58:20 -0400101/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
102typedef HBINT32 FWORD32;
103
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100104/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
105typedef HBUINT16 UFWORD;
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200106
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900107/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100108struct F2DOT14 : HBINT16
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900109{
Ebrahim Byagowice99dd02018-04-15 22:08:50 +0430110 // 16384 means 1<<14
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330111 float to_float () const { return ((int32_t) v) / 16384.f; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330112 void set_float (float f) { v.set (round (f * 16384.f)); }
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900113 public:
114 DEFINE_SIZE_STATIC (2);
115};
116
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200117/* 32-bit signed fixed-point number (16.16). */
Ebrahim Byagowice99dd02018-04-15 22:08:50 +0430118struct Fixed : HBINT32
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200119{
Ebrahim Byagowice99dd02018-04-15 22:08:50 +0430120 // 65536 means 1<<16
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330121 float to_float () const { return ((int32_t) v) / 65536.f; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330122 void set_float (float f) { v.set (round (f * 65536.f)); }
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200123 public:
124 DEFINE_SIZE_STATIC (4);
125};
126
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400127/* Date represented in number of seconds since 12:00 midnight, January 1,
128 * 1904. The value is represented as a signed 64-bit integer. */
129struct LONGDATETIME
130{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330131 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300132 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500133 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100134 return_trace (likely (c->check_struct (this)));
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400135 }
Behdad Esfahbod6775da32014-01-23 14:18:49 -0500136 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100137 HBINT32 major;
138 HBUINT32 minor;
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400139 public:
140 DEFINE_SIZE_STATIC (8);
141};
142
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500143/* Array of four uint8s (length = 32 bits) used to identify a script, language
144 * system, feature, or baseline */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100145struct Tag : HBUINT32
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400146{
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500147 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330148 operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
149 operator char* () { return reinterpret_cast<char *> (&this->v); }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400150 public:
151 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500152};
153
154/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahboda685bfe2018-12-30 20:24:21 -0500155struct GlyphID : HBUINT16 {};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500156
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400157/* Script/language-system/feature index */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100158struct Index : HBUINT16 {
Behdad Esfahbodfda994e2018-09-07 15:02:57 -0400159 enum { NOT_FOUND_INDEX = 0xFFFFu };
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400160};
Behdad Esfahbod92806ee2018-08-05 21:41:52 -0700161DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400162
Behdad Esfahbod07386ea2018-10-22 21:18:27 -0700163typedef Index NameID;
164
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400165/* Offset, Null offset = 0 */
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200166template <typename Type, bool has_null=true>
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400167struct Offset : Type
Behdad Esfahbode95e0312013-01-08 16:15:46 -0600168{
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700169 typedef Type type;
170
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330171 bool is_null () const { return has_null && 0 == *this; }
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600172
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330173 void *serialize (hb_serialize_context_t *c, const void *base)
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600174 {
175 void *t = c->start_embed<void> ();
176 this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
177 return t;
178 }
Behdad Esfahboddf1c7d52018-02-25 19:06:25 -0800179
180 public:
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330181 DEFINE_SIZE_STATIC (sizeof (Type));
Behdad Esfahbode95e0312013-01-08 16:15:46 -0600182};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400183
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100184typedef Offset<HBUINT16> Offset16;
185typedef Offset<HBUINT32> Offset32;
Behdad Esfahbodc6173a32017-11-14 21:09:03 -0800186
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500187
188/* CheckSum */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100189struct CheckSum : HBUINT32
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400190{
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400191 /* This is reference implementation from the spec. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330192 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400193 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500194 uint32_t Sum = 0L;
Behdad Esfahbodec2538c2018-02-23 15:51:26 -0800195 assert (0 == (Length & 3));
196 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500197
198 while (Table < EndPtr)
199 Sum += *Table++;
200 return Sum;
201 }
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400202
203 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330204 void set_for_data (const void *data, unsigned int length)
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100205 { set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400206
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400207 public:
208 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500209};
210
211
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500212/*
213 * Version Numbers
214 */
215
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100216template <typename FixedType=HBUINT16>
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400217struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400218{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330219 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400220
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330221 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300222 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500223 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100224 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400225 }
226
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +0900227 FixedType major;
228 FixedType minor;
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400229 public:
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330230 DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500231};
232
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400233
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400234/*
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400235 * Template subclasses of Offset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400236 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400237 */
238
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500239template <typename Type, bool has_null>
240struct _hb_has_null
241{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330242 static const Type *get_null () { return nullptr; }
243 static Type *get_crap () { return nullptr; }
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500244};
245template <typename Type>
246struct _hb_has_null<Type, true>
247{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330248 static const Type *get_null () { return &Null(Type); }
249 static Type *get_crap () { return &Crap(Type); }
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500250};
251
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200252template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
253struct OffsetTo : Offset<OffsetType, has_null>
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400254{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330255 const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400256 {
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500257 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200258 return StructAtOffset<const Type> (base, *this);
Behdad Esfahboddcd1b072018-05-31 17:58:40 -0700259 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330260 Type& operator () (void *base) const
Behdad Esfahboddcd1b072018-05-31 17:58:40 -0700261 {
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500262 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200263 return StructAtOffset<Type> (base, *this);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400264 }
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400265
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330266 Type& serialize (hb_serialize_context_t *c, const void *base)
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400267 {
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600268 return * (Type *) Offset<OffsetType>::serialize (c, base);
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400269 }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400270
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700271 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330272 void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700273 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330274 if (&src == &Null (T))
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700275 {
276 this->set (0);
277 return;
278 }
279 serialize (c->serializer, base);
280 if (!src.subset (c))
281 this->set (0);
282 }
283
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330284 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300285 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500286 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100287 if (unlikely (!c->check_struct (this))) return_trace (false);
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200288 if (unlikely (this->is_null ())) return_trace (true);
289 if (unlikely (!c->check_range (base, *this))) return_trace (false);
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200290 return_trace (true);
291 }
292
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330293 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200294 {
295 TRACE_SANITIZE (this);
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200296 return_trace (sanitize_shallow (c, base) &&
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200297 (this->is_null () ||
Behdad Esfahbod361fc262018-09-13 16:47:33 +0200298 StructAtOffset<Type> (base, *this).sanitize (c) ||
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200299 neuter (c)));
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400300 }
Behdad Esfahbod4c6b0fb2018-09-13 16:39:30 +0200301 template <typename T1>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330302 bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300303 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500304 TRACE_SANITIZE (this);
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200305 return_trace (sanitize_shallow (c, base) &&
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200306 (this->is_null () ||
Behdad Esfahbod361fc262018-09-13 16:47:33 +0200307 StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200308 neuter (c)));
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400309 }
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200310 template <typename T1, typename T2>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330311 bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200312 {
313 TRACE_SANITIZE (this);
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200314 return_trace (sanitize_shallow (c, base) &&
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200315 (this->is_null () ||
Behdad Esfahbod361fc262018-09-13 16:47:33 +0200316 StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
Behdad Esfahbod4c6b0fb2018-09-13 16:39:30 +0200317 neuter (c)));
318 }
319 template <typename T1, typename T2, typename T3>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330320 bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
Behdad Esfahbod4c6b0fb2018-09-13 16:39:30 +0200321 {
322 TRACE_SANITIZE (this);
323 return_trace (sanitize_shallow (c, base) &&
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200324 (this->is_null () ||
Behdad Esfahbod361fc262018-09-13 16:47:33 +0200325 StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200326 neuter (c)));
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200327 }
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400328
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400329 /* Set the offset to Null */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330330 bool neuter (hb_sanitize_context_t *c) const
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200331 {
332 if (!has_null) return false;
Behdad Esfahbod51f56352014-06-04 18:42:32 -0400333 return c->try_set (this, 0);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400334 }
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330335 DEFINE_SIZE_STATIC (sizeof (OffsetType));
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400336};
Behdad Esfahbod205d72a2019-01-17 18:10:38 -0500337/* Partial specializations. */
338template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {};
339template <typename Type, typename OffsetType=HBUINT16 > struct NNOffsetTo : OffsetTo<Type, OffsetType, false> {};
340template <typename Type > struct LNNOffsetTo : OffsetTo<Type, HBUINT32, false> {};
Behdad Esfahbodf47a60a2018-11-22 17:53:29 -0500341
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200342template <typename Base, typename OffsetType, bool has_null, typename Type>
343static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
344template <typename Base, typename OffsetType, bool has_null, typename Type>
345static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400346
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400347
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400348/*
349 * Array Types
350 */
351
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100352template <typename Type>
353struct UnsizedArrayOf
354{
Behdad Esfahbod879faa22018-12-21 01:57:40 -0500355 typedef Type item_t;
Behdad Esfahbod3656f562018-12-16 20:35:11 -0500356 enum { item_size = hb_static_size (Type) };
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500357
Behdad Esfahbodea0e51d2018-10-29 16:00:23 -0700358 HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700359
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330360 const Type& operator [] (int i_) const
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800361 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500362 unsigned int i = (unsigned int) i_;
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800363 const Type *p = &arrayZ[i];
Behdad Esfahbod0328a1c2018-11-16 16:48:28 -0800364 if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800365 return *p;
366 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330367 Type& operator [] (int i_)
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800368 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500369 unsigned int i = (unsigned int) i_;
Behdad Esfahbod9714e112018-11-16 16:52:42 -0800370 Type *p = &arrayZ[i];
Behdad Esfahbod0328a1c2018-11-16 16:48:28 -0800371 if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800372 return *p;
373 }
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100374
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330375 unsigned int get_size (unsigned int len) const
Behdad Esfahbod1cf075e2018-11-02 11:38:00 -0400376 { return len * Type::static_size; }
377
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330378 template <typename T> operator T * () { return arrayZ; }
379 template <typename T> operator const T * () const { return arrayZ; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330380 hb_array_t<Type> as_array (unsigned int len)
Behdad Esfahbode6043062018-11-24 01:24:48 -0500381 { return hb_array (arrayZ, len); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330382 hb_array_t<const Type> as_array (unsigned int len) const
Behdad Esfahbode6043062018-11-24 01:24:48 -0500383 { return hb_array (arrayZ, len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330384 operator hb_array_t<Type> () { return as_array (); }
385 operator hb_array_t<const Type> () const { return as_array (); }
Behdad Esfahbod72462eb2018-11-02 11:46:24 -0400386
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500387 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330388 Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500389 { return *as_array (len).lsearch (x, &not_found); }
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500390 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330391 const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500392 { return *as_array (len).lsearch (x, &not_found); }
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500393
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330394 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500395 { as_array (len).qsort (start, end); }
396
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330397 bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100398 {
399 TRACE_SANITIZE (this);
400 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
401
402 /* Note: for structs that do not reference other structs,
403 * we do not need to call their sanitize() as we already did
404 * a bound check on the aggregate array size. We just include
405 * a small unreachable expression to make sure the structs
406 * pointed to do have a simple sanitize(), ie. they do not
407 * reference other structs via offsets.
408 */
409 (void) (false && arrayZ[0].sanitize (c));
410
411 return_trace (true);
412 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330413 bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100414 {
415 TRACE_SANITIZE (this);
416 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
417 for (unsigned int i = 0; i < count; i++)
418 if (unlikely (!arrayZ[i].sanitize (c, base)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330419 return_trace (false);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100420 return_trace (true);
421 }
422 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330423 bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100424 {
425 TRACE_SANITIZE (this);
426 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
427 for (unsigned int i = 0; i < count; i++)
428 if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330429 return_trace (false);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100430 return_trace (true);
431 }
432
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330433 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100434 {
435 TRACE_SANITIZE (this);
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200436 return_trace (c->check_array (arrayZ, count));
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100437 }
438
439 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200440 Type arrayZ[VAR];
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100441 public:
Behdad Esfahbodf47a60a2018-11-22 17:53:29 -0500442 DEFINE_SIZE_UNBOUNDED (0);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100443};
444
445/* Unsized array of offset's */
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700446template <typename Type, typename OffsetType, bool has_null=true>
447struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100448
449/* Unsized array of offsets relative to the beginning of the array itself. */
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700450template <typename Type, typename OffsetType, bool has_null=true>
451struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100452{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330453 const Type& operator [] (int i_) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100454 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500455 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500456 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
457 if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
458 return this+*p;
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100459 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330460 Type& operator [] (int i_)
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500461 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500462 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500463 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
464 if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
465 return this+*p;
466 }
467
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100468
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330469 bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100470 {
471 TRACE_SANITIZE (this);
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700472 return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100473 }
474 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330475 bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100476 {
477 TRACE_SANITIZE (this);
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700478 return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100479 }
480};
481
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500482/* An array with sorted elements. Supports binary searching. */
483template <typename Type>
484struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
485{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330486 hb_sorted_array_t<Type> as_array (unsigned int len)
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500487 { return hb_sorted_array (this->arrayZ, len); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330488 hb_sorted_array_t<const Type> as_array (unsigned int len) const
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500489 { return hb_sorted_array (this->arrayZ, len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330490 operator hb_sorted_array_t<Type> () { return as_array (); }
491 operator hb_sorted_array_t<const Type> () const { return as_array (); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500492
493 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330494 Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500495 { return *as_array (len).bsearch (x, &not_found); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500496 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330497 const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500498 { return *as_array (len).bsearch (x, &not_found); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500499 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330500 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
Behdad Esfahbodd77a0982018-11-24 10:06:13 -0500501 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
502 unsigned int to_store = (unsigned int) -1) const
503 { return as_array (len).bfind (x, i, not_found, to_store); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500504};
505
506
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400507/* An array with a number of elements. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100508template <typename Type, typename LenType=HBUINT16>
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400509struct ArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400510{
Behdad Esfahbod879faa22018-12-21 01:57:40 -0500511 typedef Type item_t;
Behdad Esfahbod3656f562018-12-16 20:35:11 -0500512 enum { item_size = hb_static_size (Type) };
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500513
Behdad Esfahbodea0e51d2018-10-29 16:00:23 -0700514 HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700515
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330516 const Type& operator [] (int i_) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400517 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500518 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330519 if (unlikely (i >= len)) return Null (Type);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700520 return arrayZ[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400521 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330522 Type& operator [] (int i_)
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400523 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500524 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330525 if (unlikely (i >= len)) return Crap (Type);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700526 return arrayZ[i];
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400527 }
Behdad Esfahbod28b68cf2018-10-30 23:33:30 -0700528
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330529 unsigned int get_size () const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400530 { return len.static_size + len * Type::static_size; }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400531
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330532 hb_array_t<Type> as_array ()
Behdad Esfahbode6043062018-11-24 01:24:48 -0500533 { return hb_array (arrayZ, len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330534 hb_array_t<const Type> as_array () const
Behdad Esfahbode6043062018-11-24 01:24:48 -0500535 { return hb_array (arrayZ, len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330536 operator hb_array_t<Type> (void) { return as_array (); }
Ebrahim Byagowi7ace1002018-12-17 20:07:04 +0330537 operator hb_array_t<const Type> (void) const { return as_array (); }
Behdad Esfahbodc514f652018-11-23 16:04:56 -0500538
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330539 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500540 { return as_array ().sub_array (start_offset, count);}
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330541 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500542 { return as_array ().sub_array (start_offset, count);}
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330543 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500544 { return as_array ().sub_array (start_offset, count);}
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330545 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500546 { return as_array ().sub_array (start_offset, count);}
547
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330548 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400549 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500550 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100551 if (unlikely (!c->extend_min (*this))) return_trace (false);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400552 len.set (items_len); /* TODO(serialize) Overflow? */
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100553 if (unlikely (!c->extend (*this))) return_trace (false);
554 return_trace (true);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400555 }
Behdad Esfahbod3d229002018-12-28 20:01:57 -0500556 template <typename Iterator>
Behdad Esfahbod445364d2019-01-08 12:42:15 -0800557 hb_enable_if_t (hb_is_iterator_of (Iterator, const Type),
Behdad Esfahbod3d229002018-12-28 20:01:57 -0500558 bool) serialize (hb_serialize_context_t *c,
559 Iterator items)
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400560 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500561 TRACE_SERIALIZE (this);
Behdad Esfahbod49161d42018-12-26 22:50:33 -0500562 unsigned count = items.len ();
563 if (unlikely (!serialize (c, count))) return_trace (false);
Behdad Esfahboddf138da2018-12-28 16:29:48 -0500564 /* TODO Umm. Just exhaust the iterator instead? Being extra
565 * cautious right now.. */
566 for (unsigned i = 0; i < count; i++, items++)
567 hb_assign (arrayZ[i], *items);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100568 return_trace (true);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400569 }
570
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330571 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300572 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500573 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100574 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400575
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400576 /* Note: for structs that do not reference other structs,
577 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400578 * a bound check on the aggregate array size. We just include
579 * a small unreachable expression to make sure the structs
580 * pointed to do have a simple sanitize(), ie. they do not
581 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400582 */
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700583 (void) (false && arrayZ[0].sanitize (c));
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400584
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100585 return_trace (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400586 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330587 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300588 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500589 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100590 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400591 unsigned int count = len;
592 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700593 if (unlikely (!arrayZ[i].sanitize (c, base)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330594 return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100595 return_trace (true);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400596 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400597 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330598 bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300599 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500600 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100601 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400602 unsigned int count = len;
603 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700604 if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330605 return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100606 return_trace (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400607 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400608
Behdad Esfahbod3e26c8d2018-11-24 00:58:44 -0500609 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330610 Type &lsearch (const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500611 { return *as_array ().lsearch (x, &not_found); }
Behdad Esfahbod3e26c8d2018-11-24 00:58:44 -0500612 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330613 const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500614 { return *as_array ().lsearch (x, &not_found); }
Behdad Esfahbodc7074b82014-05-08 18:24:31 -0400615
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330616 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500617 { as_array ().qsort (start, end); }
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600618
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330619 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300620 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500621 TRACE_SANITIZE (this);
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200622 return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400623 }
624
625 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200626 LenType len;
627 Type arrayZ[VAR];
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400628 public:
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700629 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400630};
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100631template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
Ebrahim Byagowi225b92b2018-07-01 14:32:00 +0430632typedef ArrayOf<HBUINT8, HBUINT8> PString;
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400633
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400634/* Array of Offset's */
Behdad Esfahbode8ff27c2018-10-28 16:29:09 -0700635template <typename Type>
636struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
637template <typename Type>
638struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
Behdad Esfahbod65621722018-10-28 16:27:18 -0700639template <typename Type>
640struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400641
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400642/* Array of offsets relative to the beginning of the array itself. */
643template <typename Type>
644struct OffsetListOf : OffsetArrayOf<Type>
645{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330646 const Type& operator [] (int i_) const
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400647 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500648 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330649 if (unlikely (i >= this->len)) return Null (Type);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700650 return this+this->arrayZ[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400651 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330652 const Type& operator [] (int i_)
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700653 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500654 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330655 if (unlikely (i >= this->len)) return Crap (Type);
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700656 return this+this->arrayZ[i];
657 }
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400658
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330659 bool subset (hb_subset_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700660 {
661 TRACE_SUBSET (this);
662 struct OffsetListOf<Type> *out = c->serializer->embed (*this);
663 if (unlikely (!out)) return_trace (false);
664 unsigned int count = this->len;
665 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod49c44b52018-09-03 16:37:17 -0700666 out->arrayZ[i].serialize_subset (c, (*this)[i], out);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700667 return_trace (true);
668 }
669
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330670 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300671 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500672 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100673 return_trace (OffsetArrayOf<Type>::sanitize (c, this));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400674 }
Behdad Esfahbod4a446ac2010-05-04 22:46:21 -0400675 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330676 bool sanitize (hb_sanitize_context_t *c, T user_data) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300677 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500678 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100679 return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400680 }
681};
682
Behdad Esfahbod51d9ba02014-06-27 15:27:15 -0400683/* An array starting at second element. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100684template <typename Type, typename LenType=HBUINT16>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400685struct HeadlessArrayOf
686{
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500687 enum { item_size = Type::static_size };
688
Behdad Esfahbodea0e51d2018-10-29 16:00:23 -0700689 HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700690
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330691 const Type& operator [] (int i_) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400692 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500693 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330694 if (unlikely (i >= lenP1 || !i)) return Null (Type);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700695 return arrayZ[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400696 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330697 Type& operator [] (int i_)
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700698 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500699 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330700 if (unlikely (i >= lenP1 || !i)) return Crap (Type);
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700701 return arrayZ[i-1];
702 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330703 unsigned int get_size () const
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200704 { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400705
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330706 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500707 hb_array_t<const Type> items)
Behdad Esfahboda930c682012-09-04 18:17:57 -0400708 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500709 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100710 if (unlikely (!c->extend_min (*this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500711 lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100712 if (unlikely (!c->extend (*this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500713 for (unsigned int i = 0; i < items.length; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700714 arrayZ[i] = items[i];
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100715 return_trace (true);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400716 }
717
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330718 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300719 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500720 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100721 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400722
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400723 /* Note: for structs that do not reference other structs,
724 * we do not need to call their sanitize() as we already did
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400725 * a bound check on the aggregate array size. We just include
726 * a small unreachable expression to make sure the structs
727 * pointed to do have a simple sanitize(), ie. they do not
728 * reference other structs via offsets.
Behdad Esfahbod40d73bc2010-04-21 00:49:40 -0400729 */
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700730 (void) (false && arrayZ[0].sanitize (c));
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400731
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100732 return_trace (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400733 }
734
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600735 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330736 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600737 {
738 TRACE_SANITIZE (this);
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200739 return_trace (lenP1.sanitize (c) &&
740 (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600741 }
742
743 public:
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200744 LenType lenP1;
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200745 Type arrayZ[VAR];
Behdad Esfahboded074222010-05-10 18:08:46 -0400746 public:
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700747 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400748};
749
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200750/* An array storing length-1. */
751template <typename Type, typename LenType=HBUINT16>
752struct ArrayOfM1
753{
Behdad Esfahbodea0e51d2018-10-29 16:00:23 -0700754 HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700755
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330756 const Type& operator [] (int i_) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200757 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500758 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330759 if (unlikely (i > lenM1)) return Null (Type);
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200760 return arrayZ[i];
761 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330762 Type& operator [] (int i_)
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200763 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500764 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330765 if (unlikely (i > lenM1)) return Crap (Type);
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200766 return arrayZ[i];
767 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330768 unsigned int get_size () const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200769 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
770
771 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330772 bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200773 {
774 TRACE_SANITIZE (this);
775 if (unlikely (!sanitize_shallow (c))) return_trace (false);
776 unsigned int count = lenM1 + 1;
777 for (unsigned int i = 0; i < count; i++)
778 if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330779 return_trace (false);
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200780 return_trace (true);
781 }
782
783 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330784 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200785 {
786 TRACE_SANITIZE (this);
787 return_trace (lenM1.sanitize (c) &&
788 (c->check_array (arrayZ, lenM1 + 1)));
789 }
790
791 public:
792 LenType lenM1;
793 Type arrayZ[VAR];
794 public:
795 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
796};
797
Behdad Esfahbod92b1e022018-07-25 16:58:47 -0700798/* An array with sorted elements. Supports binary searching. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100799template <typename Type, typename LenType=HBUINT16>
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400800struct SortedArrayOf : ArrayOf<Type, LenType>
Behdad Esfahbod40a47972014-05-08 18:21:04 -0400801{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330802 hb_sorted_array_t<Type> as_array ()
Behdad Esfahbode7003922018-11-24 01:31:00 -0500803 { return hb_sorted_array (this->arrayZ, this->len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330804 hb_sorted_array_t<const Type> as_array () const
Behdad Esfahbode7003922018-11-24 01:31:00 -0500805 { return hb_sorted_array (this->arrayZ, this->len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330806 operator hb_sorted_array_t<Type> () { return as_array (); }
807 operator hb_sorted_array_t<const Type> () const { return as_array (); }
Behdad Esfahbode7003922018-11-24 01:31:00 -0500808
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800809 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500810 { return as_array ().sub_array (start_offset, count);}
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800811 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500812 { return as_array ().sub_array (start_offset, count);}
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800813 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500814 { return as_array ().sub_array (start_offset, count);}
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800815 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500816 { return as_array ().sub_array (start_offset, count);}
817
Behdad Esfahbod82378092019-01-07 22:00:45 -0500818 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
819 {
820 TRACE_SERIALIZE (this);
821 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
822 return_trace (ret);
823 }
824 template <typename Iterator>
Behdad Esfahbod445364d2019-01-08 12:42:15 -0800825 hb_enable_if_t (hb_is_sorted_iterator_of (Iterator, const Type),
Behdad Esfahbod82378092019-01-07 22:00:45 -0500826 bool) serialize (hb_serialize_context_t *c,
827 Iterator items)
828 {
829 TRACE_SERIALIZE (this);
830 bool ret = ArrayOf<Type, LenType>::serialize (c, items);
831 return_trace (ret);
832 }
833
834
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500835 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330836 Type &bsearch (const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500837 { return *as_array ().bsearch (x, &not_found); }
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500838 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330839 const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500840 { return *as_array ().bsearch (x, &not_found); }
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500841 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330842 bool bfind (const T &x, unsigned int *i = nullptr,
Behdad Esfahbodd77a0982018-11-24 10:06:13 -0500843 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
844 unsigned int to_store = (unsigned int) -1) const
845 { return as_array ().bfind (x, i, not_found, to_store); }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400846};
847
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400848/*
849 * Binary-search arrays
850 */
851
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -0400852template <typename LenType=HBUINT16>
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600853struct BinSearchHeader
854{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330855 operator uint32_t () const { return len; }
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600856
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330857 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600858 {
859 TRACE_SANITIZE (this);
860 return_trace (c->check_struct (this));
861 }
862
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330863 void set (unsigned int v)
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600864 {
865 len.set (v);
866 assert (len == v);
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200867 entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400868 searchRange.set (16 * (1u << entrySelector));
869 rangeShift.set (v * 16 > searchRange
870 ? 16 * v - searchRange
871 : 0);
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600872 }
873
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600874 protected:
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -0400875 LenType len;
876 LenType searchRange;
877 LenType entrySelector;
878 LenType rangeShift;
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600879
880 public:
881 DEFINE_SIZE_STATIC (8);
882};
883
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -0400884template <typename Type, typename LenType=HBUINT16>
885struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600886
Behdad Esfahboda256a922018-10-29 11:25:35 -0700887
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400888struct VarSizedBinSearchHeader
889{
890
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330891 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400892 {
893 TRACE_SANITIZE (this);
894 return_trace (c->check_struct (this));
895 }
896
897 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
898 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
899 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
900 * that is less than or equal to the value of nUnits. */
901 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
902 * or equal to the value of nUnits. */
903 HBUINT16 rangeShift; /* The value of unitSize times the difference of the
904 * value of nUnits minus the largest power of 2 less
905 * than or equal to the value of nUnits. */
906 public:
907 DEFINE_SIZE_STATIC (10);
908};
909
910template <typename Type>
911struct VarSizedBinSearchArrayOf
912{
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500913 enum { item_size = Type::static_size };
914
Behdad Esfahbodea0e51d2018-10-29 16:00:23 -0700915 HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700916
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330917 bool last_is_terminator () const
Behdad Esfahbod3d309722018-11-24 23:12:28 -0500918 {
919 if (unlikely (!header.nUnits)) return false;
920
921 /* Gah.
922 *
923 * "The number of termination values that need to be included is table-specific.
924 * The value that indicates binary search termination is 0xFFFF." */
925 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
926 unsigned int count = Type::TerminationWordCount;
927 for (unsigned int i = 0; i < count; i++)
928 if (words[i] != 0xFFFFu)
929 return false;
930 return true;
931 }
932
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330933 const Type& operator [] (int i_) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400934 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500935 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500936 if (unlikely (i >= get_length ())) return Null (Type);
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400937 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
938 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330939 Type& operator [] (int i_)
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400940 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500941 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500942 if (unlikely (i >= get_length ())) return Crap (Type);
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400943 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
944 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330945 unsigned int get_length () const
946 { return header.nUnits - last_is_terminator (); }
947 unsigned int get_size () const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400948 { return header.static_size + header.nUnits * header.unitSize; }
949
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330950 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400951 {
952 TRACE_SANITIZE (this);
953 if (unlikely (!sanitize_shallow (c))) return_trace (false);
954
955 /* Note: for structs that do not reference other structs,
956 * we do not need to call their sanitize() as we already did
957 * a bound check on the aggregate array size. We just include
958 * a small unreachable expression to make sure the structs
959 * pointed to do have a simple sanitize(), ie. they do not
960 * reference other structs via offsets.
961 */
962 (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
963
964 return_trace (true);
965 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330966 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400967 {
968 TRACE_SANITIZE (this);
969 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500970 unsigned int count = get_length ();
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400971 for (unsigned int i = 0; i < count; i++)
972 if (unlikely (!(*this)[i].sanitize (c, base)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330973 return_trace (false);
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400974 return_trace (true);
975 }
Ebrahim Byagowib8b00fb2018-11-08 18:53:14 +0330976 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330977 bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
Ebrahim Byagowib8b00fb2018-11-08 18:53:14 +0330978 {
979 TRACE_SANITIZE (this);
980 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500981 unsigned int count = get_length ();
Ebrahim Byagowib8b00fb2018-11-08 18:53:14 +0330982 for (unsigned int i = 0; i < count; i++)
983 if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330984 return_trace (false);
Ebrahim Byagowib8b00fb2018-11-08 18:53:14 +0330985 return_trace (true);
986 }
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400987
988 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330989 const Type *bsearch (const T &key) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400990 {
991 unsigned int size = header.unitSize;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500992 int min = 0, max = (int) get_length () - 1;
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400993 while (min <= max)
994 {
Behdad Esfahbod21ede862018-10-25 13:19:34 -0700995 int mid = ((unsigned int) min + (unsigned int) max) / 2;
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400996 const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
997 int c = p->cmp (key);
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330998 if (c < 0) max = mid - 1;
999 else if (c > 0) min = mid + 1;
1000 else return p;
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001001 }
1002 return nullptr;
1003 }
1004
1005 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301006 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001007 {
1008 TRACE_SANITIZE (this);
1009 return_trace (header.sanitize (c) &&
Behdad Esfahbod2c824d32018-10-11 16:41:01 -04001010 Type::static_size <= header.unitSize &&
Behdad Esfahbode0144052018-11-12 14:23:31 -05001011 c->check_range (bytesZ.arrayZ,
1012 header.nUnits,
1013 header.unitSize));
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001014 }
1015
1016 protected:
1017 VarSizedBinSearchHeader header;
1018 UnsizedArrayOf<HBUINT8> bytesZ;
1019 public:
1020 DEFINE_SIZE_ARRAY (10, bytesZ);
1021};
1022
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -04001023
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08001024} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001025
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001026
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07001027#endif /* HB_OPEN_TYPE_HH */