hb-open-type-private.hh revision 977eeb714454630bd045bb11f58ff6397f10b143
164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod/*
2ee58aaebd296ea8237516754fd4e825d524b11b7Behdad Esfahbod * Copyright (C) 2007,2008,2009  Red Hat, Inc.
364aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *  This is part of HarfBuzz, an OpenType Layout engine library.
564aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
664aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * Permission is hereby granted, without written agreement and without
764aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
864aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * software and its documentation for any purpose, provided that the
964aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
1064aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * all copies of this software.
1164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
1264aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1364aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1564aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1664aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * DAMAGE.
1764aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
1864aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
1964aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2064aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2164aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2264aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2364aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod *
2464aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
2564aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod */
2664aef3a54999496fd1de4f5aa5b019e4c03b3836Behdad Esfahbod
275f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#ifndef HB_OPEN_TYPES_PRIVATE_HH
285f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#define HB_OPEN_TYPES_PRIVATE_HH
2912c4568c680ea2b9b98a16a8b7402ca185c90ef6Behdad Esfahbod
302098a021a826e76ee27d5db74e32738d7d1c3d30Behdad Esfahbod#include "hb-private.h"
3112c4568c680ea2b9b98a16a8b7402ca185c90ef6Behdad Esfahbod
3270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod#include "hb-blob.h"
3370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
34a16ecbf0564a6e2576da22c12827f3c0719da549Behdad Esfahbod
35706ab25a4cb043d46e6088aa0a7184ee200276c9Behdad Esfahbod#define NO_INDEX		((unsigned int) 0xFFFF)
365a0b791184cf6ef39eae0570e14aca21abc32845Behdad Esfahbod
37706ab25a4cb043d46e6088aa0a7184ee200276c9Behdad Esfahbod
38196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod/*
39196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod * Casts
40196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod */
41196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod
422b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define CONST_CHARP(X)		(reinterpret_cast<const char *>(X))
432b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define DECONST_CHARP(X)	((char *)reinterpret_cast<const char *>(X))
442b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define CHARP(X)		(reinterpret_cast<char *>(X))
452b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod
462b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define CONST_CAST(T,X,Ofs)	(*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + Ofs)))
472b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define DECONST_CAST(T,X,Ofs)	(*(reinterpret_cast<T *>((char *)CONST_CHARP(&(X)) + Ofs)))
482b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod#define CAST(T,X,Ofs) 		(*(reinterpret_cast<T *>(CHARP(&(X)) + Ofs)))
49196598bbccff08415ff5192314cba044df258cadBehdad Esfahbod
50284899ccbe79fda7405ab09d3092fc25fd89e810Behdad Esfahbod#define CONST_NEXT(T,X)		(*(reinterpret_cast<const T *>(CONST_CHARP(&(X)) + (X).get_size ())))
51284899ccbe79fda7405ab09d3092fc25fd89e810Behdad Esfahbod#define NEXT(T,X)		(*(reinterpret_cast<T *>(CHARP(&(X)) + (X).get_size ())))
5270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
5370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod/*
54600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod * Class features
55600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod */
56600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod
578b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
588b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Null objects */
598b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
608b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Global nul-content Null pool.  Enlarge as necessary. */
618b8358033184198ff638ee1379093717596e162dBehdad Esfahbodstatic const char NullPool[16] = "";
628b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
638b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Generic template for nul-content sizeof-sized Null objects. */
648b8358033184198ff638ee1379093717596e162dBehdad Esfahbodtemplate <typename Type>
6560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct Null
6660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
67f8dc67b3c24dfc805da756a73cb217b36e16b4b8Behdad Esfahbod  ASSERT_STATIC (sizeof (Type) <= sizeof (NullPool));
684497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  static inline const Type &get () { return *(const Type*)NullPool; }
698b8358033184198ff638ee1379093717596e162dBehdad Esfahbod};
708b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
718b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
728b8358033184198ff638ee1379093717596e162dBehdad Esfahbod#define DEFINE_NULL_DATA(Type, size, data) \
73cc6c644ff2af5f6669b6ec100ff13e904872b21cBehdad Esfahbodstatic const char _Null##Type[size] = data; \
748b8358033184198ff638ee1379093717596e162dBehdad Esfahbodtemplate <> \
7560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct Null <Type> \
7660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{ \
774497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  static inline const Type &get () { return *(const Type*)_Null##Type; } \
788b8358033184198ff638ee1379093717596e162dBehdad Esfahbod}
798b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
808b8358033184198ff638ee1379093717596e162dBehdad Esfahbod/* Accessor macro. */
818b8358033184198ff638ee1379093717596e162dBehdad Esfahbod#define Null(Type) (Null<Type>::get())
828b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
838b8358033184198ff638ee1379093717596e162dBehdad Esfahbod
848b8358033184198ff638ee1379093717596e162dBehdad Esfahbod#define ASSERT_SIZE_DATA(Type, size, data) \
851f437e6f47fb6c15761021bd2078f31778f2179cBehdad Esfahbod  ASSERT_SIZE (Type, size); \
861f437e6f47fb6c15761021bd2078f31778f2179cBehdad Esfahbod  DEFINE_NULL_DATA (Type, size, data)
871f437e6f47fb6c15761021bd2078f31778f2179cBehdad Esfahbod
88600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod/* get_for_data() is a static class method returning a reference to an
89600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod * instance of Type located at the input data location.  It's just a
9054e5aac5e2947d4e2864c6f2987e4d275da73100Behdad Esfahbod * fancy, NULL-safe, cast! */
91fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#define STATIC_DEFINE_GET_FOR_DATA(Type) \
9260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  static inline const Type& get_for_data (const char *data) \
9360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  { \
948b8358033184198ff638ee1379093717596e162dBehdad Esfahbod    if (HB_UNLIKELY (data == NULL)) return Null(Type); \
954497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod    return *(const Type*)data; \
96212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod  }
97212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod/* Like get_for_data(), but checks major version first. */
98cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod#define STATIC_DEFINE_GET_FOR_DATA_CHECK_MAJOR_VERSION(Type, MajorMin, MajorMax) \
99212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod  static inline const Type& get_for_data (const char *data) \
100212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod  { \
101212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod    if (HB_UNLIKELY (data == NULL)) return Null(Type); \
1024497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod    const Type& t = *(const Type*)data; \
103cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod    if (HB_UNLIKELY (t.version.major < MajorMin || t.version.major > MajorMax)) return Null(Type); \
104212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod    return t; \
105212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod  }
106600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod
107600e5eb80f553ea8eb862e6784133574c74ca513Behdad Esfahbod
108577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod/*
109577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod * Sanitize
110577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod */
111577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
1129b76a290a94f2603f3cb9498ae976125347cf54bBehdad Esfahbod#if HB_DEBUG
113b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG_ARG_DEF	, unsigned int sanitize_depth
114b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG_ARG	, sanitize_depth + 1
1159b76a290a94f2603f3cb9498ae976125347cf54bBehdad Esfahbod#define SANITIZE_DEBUG_ARG_INIT	, 1
116b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG() \
117b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod	HB_STMT_START { \
1189b76a290a94f2603f3cb9498ae976125347cf54bBehdad Esfahbod	    if (sanitize_depth < HB_DEBUG) \
1197acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod		fprintf (stderr, "SANITIZE(%p) %-*d-> %s\n", \
1207acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod			 (CONST_CHARP (this) == NullPool) ? 0 : this, \
1219b76a290a94f2603f3cb9498ae976125347cf54bBehdad Esfahbod			 sanitize_depth, sanitize_depth, \
1227acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod			 __PRETTY_FUNCTION__); \
123b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod	} HB_STMT_END
124b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#else
125b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG_ARG_DEF
126b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG_ARG
127b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG_ARG_INIT
128b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#define SANITIZE_DEBUG() HB_STMT_START {} HB_STMT_END
129b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod#endif
130b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod
13141895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod#define SANITIZE_ARG_DEF \
13241895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod	hb_sanitize_context_t *context SANITIZE_DEBUG_ARG_DEF
13341895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod#define SANITIZE_ARG \
13441895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod	context SANITIZE_DEBUG_ARG
13541895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod#define SANITIZE_ARG_INIT \
13641895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod	&context SANITIZE_DEBUG_ARG_INIT
13741895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod
138577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbodtypedef struct _hb_sanitize_context_t hb_sanitize_context_t;
139577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbodstruct _hb_sanitize_context_t
140577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod{
141577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  const char *start, *end;
142577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  int edit_count;
143577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  hb_blob_t *blob;
144577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod};
145577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
146577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbodstatic HB_GNUC_UNUSED void
1474e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod_hb_sanitize_init (hb_sanitize_context_t *context,
1484e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod		   hb_blob_t *blob)
149577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod{
150577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  context->blob = blob;
151577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  context->start = hb_blob_lock (blob);
152577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  context->end = context->start + hb_blob_get_length (blob);
153577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  context->edit_count = 0;
1544f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
1554f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
1567acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod  fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
1577f96b39a9d5a81ba77e0c3dea8fe2cdb9957c4c7Behdad Esfahbod	   context->blob, context->start, context->end, context->end - context->start);
1584f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
159577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod}
160577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
161577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbodstatic HB_GNUC_UNUSED void
1624e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod_hb_sanitize_fini (hb_sanitize_context_t *context,
1634e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod		   bool unlock)
164577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod{
1654f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
1667acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod  fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
1677acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod	   context->blob, context->start, context->end, context->edit_count);
1684f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
1694f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
170577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod  if (unlock)
171577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod    hb_blob_unlock (context->blob);
172577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod}
173577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
1744f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbodstatic HB_GNUC_UNUSED inline bool
17541895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod_hb_sanitize_check (SANITIZE_ARG_DEF,
17641895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod		    const char *base,
17741895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod		    unsigned int len)
17841895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod{
179ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod  bool ret = context->start <= base &&
180ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     base <= context->end &&
181ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     (unsigned int) (context->end - base) >= len;
182ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod
183ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod#if HB_DEBUG
184ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod  if (sanitize_depth < HB_DEBUG) \
185ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod    fprintf (stderr, "SANITIZE(%p) %-*d-> check [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
186ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     base,
187ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     sanitize_depth, sanitize_depth,
188ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     base, base+len, len,
189ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     context->start, context->end,
190ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	     ret ? "pass" : "FAIL");
191ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod#endif
192ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod  return ret;
19341895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod}
19441895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod
19541895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbodstatic HB_GNUC_UNUSED inline bool
196815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod_hb_sanitize_array (SANITIZE_ARG_DEF,
197815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod		    const char *base,
198815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod		    unsigned int record_size,
199815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod		    unsigned int len)
200815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod{
201815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod  bool overflows = len >= ((unsigned int) -1) / record_size;
202815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod
203815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod#if HB_DEBUG
204815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod  if (sanitize_depth < HB_DEBUG) \
205815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod    fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
206815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod	     base,
207815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod	     sanitize_depth, sanitize_depth,
208815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod	     base, base + (record_size * len), record_size, len, (unsigned long) record_size * len,
209815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod	     context->start, context->end,
210815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod	     !overflows ? "does not overflow" : "OVERFLOWS FAIL");
211815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod#endif
212815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod  return HB_LIKELY (!overflows) && _hb_sanitize_check (SANITIZE_ARG, base, record_size * len);
213815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod}
214815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod
215815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbodstatic HB_GNUC_UNUSED inline bool
21641895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod_hb_sanitize_edit (SANITIZE_ARG_DEF,
2174f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod		   const char *base HB_GNUC_UNUSED,
2184f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod		   unsigned int len HB_GNUC_UNUSED)
219577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod{
220977eeb714454630bd045bb11f58ff6397f10b143Behdad Esfahbod  bool perm = hb_blob_try_writable_inplace (context->blob);
221f4b58d3fc2956a9d1b6178588d809c781f7a5c0cBehdad Esfahbod  context->edit_count++;
2224f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
2234f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
224ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod  fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
225ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   base,
226ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   sanitize_depth, sanitize_depth,
227ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   context->edit_count,
228ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   base, base+len, len,
229ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   context->start, context->end,
230ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	   perm ? "granted" : "REJECTED");
2314f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
2324f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod  return perm;
233577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod}
234577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
235577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG))
236577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE2(X,Y) (SANITIZE (X) && SANITIZE (Y))
237577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
238577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_THIS(X) HB_LIKELY ((X).sanitize (SANITIZE_ARG, CONST_CHARP(this)))
239577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_THIS2(X,Y) (SANITIZE_THIS (X) && SANITIZE_THIS (Y))
240577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_THIS3(X,Y,Z) (SANITIZE_THIS (X) && SANITIZE_THIS (Y) && SANITIZE_THIS(Z))
241577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
242577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_BASE(X,B) HB_LIKELY ((X).sanitize (SANITIZE_ARG, B))
243577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_BASE2(X,Y,B) (SANITIZE_BASE (X,B) && SANITIZE_BASE (Y,B))
244577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
245577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_SELF() SANITIZE_OBJ (*this)
246577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_OBJ(X) SANITIZE_MEM(&(X), sizeof (X))
247577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod#define SANITIZE_GET_SIZE() SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ())
248577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
249d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod/* TODO Optimize this if L is fixed (gcc magic) */
25041895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod#define SANITIZE_MEM(B,L) HB_LIKELY (_hb_sanitize_check (SANITIZE_ARG, CONST_CHARP(B), (L)))
251577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
252815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod#define SANITIZE_ARRAY(A,S,L) HB_LIKELY (_hb_sanitize_array (SANITIZE_ARG, CONST_CHARP(A), S, L))
253815a73e4202ca17677f12e862b70ca8724cf2f57Behdad Esfahbod
254d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod#define NEUTER(Var, Val) \
255d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod	(SANITIZE_OBJ (Var) && \
25641895506cb6a41b1a833866f8822261ea449ea0bBehdad Esfahbod	 _hb_sanitize_edit (SANITIZE_ARG, CONST_CHARP(&(Var)), sizeof (Var)) && \
257d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod	 ((Var) = (Val), true))
258577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
259577c1116493d785d3455626612f97dabb383abf0Behdad Esfahbod
2604e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod/* Template to sanitize an object. */
2614e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbodtemplate <typename Type>
2624e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbodstruct Sanitizer
2634e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod{
2644e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  static hb_blob_t *sanitize (hb_blob_t *blob) {
2654e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    hb_sanitize_context_t context;
2664e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    bool sane;
2674e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
268d0b657379bbe63602953412d6bc944b2a0f430ebBehdad Esfahbod    /* TODO is_sane() stuff */
2694e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
2704e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  retry:
2714f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
2727acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod    fprintf (stderr, "Sanitizer %p start %s\n", blob, __PRETTY_FUNCTION__);
2734f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
2744f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod
2754e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    _hb_sanitize_init (&context, blob);
2764e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
2778cd6fa28d1b77100491519b8dedb2e113508bf59Behdad Esfahbod    Type *t = &CAST (Type, *DECONST_CHARP(context.start), 0);
2784e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
279b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    sane = t->sanitize (SANITIZE_ARG_INIT);
2804e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    if (sane) {
2814e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      if (context.edit_count) {
2820d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod#if HB_DEBUG
2830d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod	fprintf (stderr, "Sanitizer %p passed first round with %d edits; going a second round %s\n",
2840d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod		 blob, context.edit_count, __PRETTY_FUNCTION__);
2850d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod#endif
2864e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod        /* sanitize again to ensure not toe-stepping */
2874e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod        context.edit_count = 0;
288b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod	sane = t->sanitize (SANITIZE_ARG_INIT);
2894e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod	if (context.edit_count) {
2900d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod#if HB_DEBUG
291ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod	  fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
2920d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod		   blob, context.edit_count, __PRETTY_FUNCTION__);
2930d77ab8a73f57c9fca4c6f9301dae394d79526e3Behdad Esfahbod#endif
2944e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod	  sane = false;
2954e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod	}
2964e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      }
2974e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      _hb_sanitize_fini (&context, true);
2984e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    } else {
2994f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod      unsigned int edit_count = context.edit_count;
3004e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      _hb_sanitize_fini (&context, true);
301977eeb714454630bd045bb11f58ff6397f10b143Behdad Esfahbod      if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
302977eeb714454630bd045bb11f58ff6397f10b143Behdad Esfahbod        /* ok, we made it writable by relocating.  try again */
3034f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
3047acb389569cf99c6bae9db31a8ed7c7007fbb566Behdad Esfahbod	fprintf (stderr, "Sanitizer %p retry %s\n", blob, __PRETTY_FUNCTION__);
3054f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
3064e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod        goto retry;
3074e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      }
3084e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    }
3094e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
3104f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#if HB_DEBUG
311ae728e51e94d18d731b7c8dc524da1a4f427d63bBehdad Esfahbod    fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", __PRETTY_FUNCTION__);
3124f3ad9115a4161fc23fa559c26082440196217ecBehdad Esfahbod#endif
3134e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    if (sane)
3144e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      return blob;
3154e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    else {
3164e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      hb_blob_destroy (blob);
3174e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod      return hb_blob_create_empty ();
3184e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    }
3194e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  }
3204e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
321d60bb8ca2ae6edf29b2227b56c57f0d16879370bBehdad Esfahbod  static const Type& lock_instance (hb_blob_t *blob) {
3224e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod    return Type::get_for_data (hb_blob_lock (blob));
3234e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod  }
3244e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod};
3254e8a0602bb0b3cbf7f26cc38790e37cdec7b0b37Behdad Esfahbod
3262d15e72c75931398db5e027e660f1320bb979117Behdad Esfahbod
327b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod/*
328b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod *
329bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod * The OpenType Font File: Data Types
330b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod */
331b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
332b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
333b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod/* "The following data types are used in the OpenType font file.
334b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
335b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
3365f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod/*
3375f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod * Int types
3385f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod */
3395f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
3409e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod/* TODO On machines that allow unaligned access, use this version. */
3419e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod#define _DEFINE_INT_TYPE1_UNALIGNED(NAME, TYPE, BIG_ENDIAN, BYTES) \
34260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  struct NAME \
34360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  { \
34420cc86b3592db33731de671f008d7d222776be49Behdad Esfahbod    inline NAME& operator = (TYPE i) { (TYPE&) v = BIG_ENDIAN (i); return *this; } \
34520cc86b3592db33731de671f008d7d222776be49Behdad Esfahbod    inline operator TYPE(void) const { return BIG_ENDIAN ((TYPE&) v); } \
34620cc86b3592db33731de671f008d7d222776be49Behdad Esfahbod    inline bool operator== (NAME o) const { return (TYPE&) v == (TYPE&) o.v; } \
347b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    inline bool sanitize (SANITIZE_ARG_DEF) { \
348b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod      SANITIZE_DEBUG (); \
349b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod      return SANITIZE_SELF (); \
350b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    } \
3519e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    private: unsigned char v[BYTES]; \
3529e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod  }; \
3539e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod  ASSERT_SIZE (NAME, BYTES)
3549e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod
3559e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod#define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN, BYTES) \
3569e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod  struct NAME \
3579e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod  { \
3589e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    inline NAME& operator = (TYPE i) { BIG_ENDIAN##_put_unaligned(v, i); return *this; } \
3599e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    inline operator TYPE(void) const { return BIG_ENDIAN##_get_unaligned (v); } \
3609e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    inline bool operator== (NAME o) const { return BIG_ENDIAN##_cmp_unaligned (v, o.v); } \
3619e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    inline bool sanitize (SANITIZE_ARG_DEF) { \
3629e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod      SANITIZE_DEBUG (); \
3639e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod      return SANITIZE_SELF (); \
3649e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    } \
3659e826ea2832f0444bcef9075b445d481a58a09c2Behdad Esfahbod    private: unsigned char v[BYTES]; \
3665f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  }; \
36720cc86b3592db33731de671f008d7d222776be49Behdad Esfahbod  ASSERT_SIZE (NAME, BYTES)
368df66028781a7609a515980e64396e6f1044d764aBehdad Esfahbod#define DEFINE_INT_TYPE0(NAME, type, b)	DEFINE_INT_TYPE1 (NAME, type##_t, hb_be_##type, b)
369df66028781a7609a515980e64396e6f1044d764aBehdad Esfahbod#define DEFINE_INT_TYPE(NAME, u, w)	DEFINE_INT_TYPE0 (NAME, u##int##w, (w / 8))
3705f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
371b6e62bc5db76ae342177b2b646c37f45eccad975Behdad Esfahbod
37220cc86b3592db33731de671f008d7d222776be49Behdad EsfahbodDEFINE_INT_TYPE (USHORT,  u, 16);	/* 16-bit unsigned integer. */
37320cc86b3592db33731de671f008d7d222776be49Behdad EsfahbodDEFINE_INT_TYPE (SHORT,	  , 16);	/* 16-bit signed integer. */
37420cc86b3592db33731de671f008d7d222776be49Behdad EsfahbodDEFINE_INT_TYPE (ULONG,	 u, 32);	/* 32-bit unsigned integer. */
37520cc86b3592db33731de671f008d7d222776be49Behdad EsfahbodDEFINE_INT_TYPE (LONG,	  , 32);	/* 32-bit signed integer. */
3766b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
377bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
3786b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* Array of four uint8s (length = 32 bits) used to identify a script, language
3796b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod * system, feature, or baseline */
38020cc86b3592db33731de671f008d7d222776be49Behdad Esfahbodstruct Tag : ULONG
38160d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
3824497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  inline Tag (const Tag &o) { *(ULONG*)this = (ULONG&) o; }
3834497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  inline Tag (uint32_t i) { *(ULONG*)this = i; }
3844497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  inline Tag (const char *c) { *(ULONG*)this = *(ULONG*)c; }
3854497af0069a94c69fc1518b1db2c1282721b732aBehdad Esfahbod  inline bool operator== (const char *c) const { return *(ULONG*)this == *(ULONG*)c; }
386befc022affd2386b3f46cd7d11e4262f6c8bce9fBehdad Esfahbod  /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
3872b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod  inline operator const char* (void) const { return CONST_CHARP(this); }
3882b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod  inline operator char* (void) { return CHARP(this); }
389738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod
390738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF) {
391b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
392738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod    /* Note: Only accept ASCII-visible tags (mind DEL)
393738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod     * This is one of the few times (only time?) we check
394738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod     * for data integrity, as opposed o just boundary checks
395738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod     */
396738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod    return SANITIZE_SELF () && (((uint32_t) *this) & 0x80808080) == 0;
397738c54d9caa3affc4b434e56bfb810ff6dc9b0b3Behdad Esfahbod  }
3986b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
399303fe62824d4e99df554b6bfaacba05d068522fbBehdad EsfahbodASSERT_SIZE (Tag, 4);
400da1097bc3b1995776c205707fd2b17603b804646Behdad Esfahbod#define _NULL_TAG_INIT  {' ', ' ', ' ', ' '}
401da1097bc3b1995776c205707fd2b17603b804646Behdad EsfahbodDEFINE_NULL_DATA (Tag, 4, _NULL_TAG_INIT);
402da1097bc3b1995776c205707fd2b17603b804646Behdad Esfahbod#undef _NULL_TAG_INIT
4036b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4046b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* Glyph index number, same as uint16 (length = 16 bits) */
4056ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbodtypedef USHORT GlyphID;
4066b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4071f437e6f47fb6c15761021bd2078f31778f2179cBehdad Esfahbod/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
4086ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbodtypedef USHORT Offset;
4096ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod
4106ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
4116ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbodtypedef ULONG LongOffset;
4126ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod
4136b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4146b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/* CheckSum */
41560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct CheckSum : ULONG
41660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
41760d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
41860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
4196b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    uint32_t Sum = 0L;
42001e4fcb032be601f272e62228881e2aabfb9d925Behdad Esfahbod    ULONG *EndPtr = Table+((Length+3) & ~3) / sizeof(ULONG);
4216b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4226b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    while (Table < EndPtr)
4236b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod      Sum += *Table++;
4246b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod    return Sum;
4256b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod  }
4266b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
4278b8358033184198ff638ee1379093717596e162dBehdad EsfahbodASSERT_SIZE (CheckSum, 4);
4286b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4296b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
4306b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod/*
4316b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod * Version Numbers
4326b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod */
4336b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
43487fcdcbe3644da10154688765db2d62eb9ac079aBehdad Esfahbodstruct FixedVersion
43560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
43609c292e3b688a67fbae67b645d1e6ffcf8d8eb6eBehdad Esfahbod  inline operator uint32_t (void) const { return (major << 16) + minor; }
43796908b898476ca5d7da5f386b15be76f9e83d76eBehdad Esfahbod
438cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF) {
439b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
440cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod    return SANITIZE_SELF ();
441cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod  }
442cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod
4436ad8d5f3c7028147b371137ae4bca6aae66b3489Behdad Esfahbod  USHORT major;
44487fcdcbe3644da10154688765db2d62eb9ac079aBehdad Esfahbod  USHORT minor;
4456b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod};
44687fcdcbe3644da10154688765db2d62eb9ac079aBehdad EsfahbodASSERT_SIZE (FixedVersion, 4);
4476b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
44892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
44992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
4505f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod/*
45192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod * Template subclasses of Offset and LongOffset that do the dereferencing.
45292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod * Use: (this+memberName)
4535f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod */
4545f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
45592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename OffsetType, typename Type>
45692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct GenericOffsetTo : OffsetType
45792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod{
45892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  inline const Type& operator() (const void *base) const
45992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  {
46092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    unsigned int offset = *this;
46192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    if (HB_UNLIKELY (!offset)) return Null(Type);
46295639fccc1ef18eadeb737e8b611d1d1f1315fc2Behdad Esfahbod    return CONST_CAST(Type, *CONST_CHARP(base), offset);
46392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  }
46492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
46520b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
466b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
46795528131b5ab9fc9e265ace715832135ebd457a4Behdad Esfahbod    if (!SANITIZE_SELF ()) return false;
46892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    unsigned int offset = *this;
46992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod    if (HB_UNLIKELY (!offset)) return true;
470ac26e2a838d1266bb5f39c43245eb2a52c5e072dBehdad Esfahbod    return SANITIZE (CAST(Type, *DECONST_CHARP(base), offset)) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
47192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  }
47220b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
473b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
47495528131b5ab9fc9e265ace715832135ebd457a4Behdad Esfahbod    if (!SANITIZE_SELF ()) return false;
475b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    unsigned int offset = *this;
476b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    if (HB_UNLIKELY (!offset)) return true;
477b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), base2) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
478b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod  }
47920b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
480b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
48195528131b5ab9fc9e265ace715832135ebd457a4Behdad Esfahbod    if (!SANITIZE_SELF ()) return false;
48242b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    unsigned int offset = *this;
48342b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    if (HB_UNLIKELY (!offset)) return true;
484ac26e2a838d1266bb5f39c43245eb2a52c5e072dBehdad Esfahbod    return SANITIZE_BASE (CAST(Type, *DECONST_CHARP(base), offset), user_data) || NEUTER (DECONST_CAST(OffsetType,*this,0), 0);
48542b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod  }
48692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod};
48792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Base, typename OffsetType, typename Type>
48892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodinline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
48992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
4905f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbodtemplate <typename Type>
49192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct OffsetTo : GenericOffsetTo<Offset, Type> {};
49292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
49392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
49492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
495bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
496bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
49792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/*
49892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod * Array Types
49992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod */
50092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
50192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename LenType, typename Type>
50292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct GenericArrayOf
50360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
50460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
50560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
5065f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod    if (HB_UNLIKELY (i >= len)) return Null(Type);
5075f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod    return array[i];
5085f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  }
50960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline unsigned int get_size () const
51079420ad9caf2d5fc94c3693e8292edfa27060b2dBehdad Esfahbod  { return sizeof (len) + len * sizeof (array[0]); }
511e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod
51220b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF) {
513b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
514dc9c4d93cd0f3ac991f32df08c1c17fc389054c0Behdad Esfahbod    if (!SANITIZE_GET_SIZE()) return false;
5153564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod    /* Note:
5163564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * for non-recursive types, this is not much needed.
5173564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * But we keep the code to make sure the objects pointed to
5183564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * do have a simple sanitize(). */
5193564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod    return true;
52070de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    unsigned int count = len;
52170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
52270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod      if (!SANITIZE (array[i]))
52370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod        return false;
5249bd629ccd064e739789e504c41ad875eed93abbaBehdad Esfahbod    return true;
52570de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
52620b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
527b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
528dc9c4d93cd0f3ac991f32df08c1c17fc389054c0Behdad Esfahbod    if (!SANITIZE_GET_SIZE()) return false;
529e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod    unsigned int count = len;
530e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod    for (unsigned int i = 0; i < count; i++)
53195639fccc1ef18eadeb737e8b611d1d1f1315fc2Behdad Esfahbod      if (!array[i].sanitize (SANITIZE_ARG, base))
532e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod        return false;
5339bd629ccd064e739789e504c41ad875eed93abbaBehdad Esfahbod    return true;
534e6ab2c59ba2d37942ac5fcbfe61d38b7e359ac8cBehdad Esfahbod  }
53520b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, const void *base2) {
536b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
537b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    if (!SANITIZE_GET_SIZE()) return false;
538b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    unsigned int count = len;
539b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod    for (unsigned int i = 0; i < count; i++)
540b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod      if (!array[i].sanitize (SANITIZE_ARG, base, base2))
541b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod        return false;
5429bd629ccd064e739789e504c41ad875eed93abbaBehdad Esfahbod    return true;
543b508e5ccd528f3f0f49f545bd5f30a525d5abd5aBehdad Esfahbod  }
54420b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, const void *base, unsigned int user_data) {
545b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
54642b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    if (!SANITIZE_GET_SIZE()) return false;
54742b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    unsigned int count = len;
54842b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
54942b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod      if (!array[i].sanitize (SANITIZE_ARG, base, user_data))
55042b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod        return false;
5519bd629ccd064e739789e504c41ad875eed93abbaBehdad Esfahbod    return true;
55242b778f89e0818fe06910ce04e2203485823da09Behdad Esfahbod  }
55370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
55492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod  LenType len;
555e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod  Type array[];
556e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod};
557e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod
55892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* An array with a USHORT number of elements. */
55992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
56092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct ArrayOf : GenericArrayOf<USHORT, Type> {};
56192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
56292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* An array with a ULONG number of elements. */
56392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
56492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongArrayOf : GenericArrayOf<ULONG, Type> {};
56592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
56692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* Array of Offset's */
56792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
56892b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
56992b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
57092b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* Array of LongOffset's */
57192b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
57292b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
57392b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
57492b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod/* LongArray of LongOffset's */
57592b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodtemplate <typename Type>
57692b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbodstruct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
57792b5dd8e71e1bdeaa6e86a53f167683a3f5f4289Behdad Esfahbod
57880e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod/* Array of offsets relative to the beginning of the array itself. */
57980e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbodtemplate <typename Type>
58080e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbodstruct OffsetListOf : OffsetArrayOf<Type>
58180e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod{
58280e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
58380e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  {
58480e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    if (HB_UNLIKELY (i >= this->len)) return Null(Type);
58580e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    return this+this->array[i];
58680e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
58780e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
58880e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF) {
58980e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    SANITIZE_DEBUG ();
59080e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this));
59180e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
59280e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF, unsigned int user_data) {
59380e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    SANITIZE_DEBUG ();
59480e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod    return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, CONST_CHARP(this), user_data);
59580e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod  }
59680e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod};
59780e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
59880e2aa2e1bfa2c8ecedcfa4cce8cadeb15792ac3Behdad Esfahbod
599e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod/* An array with a USHORT number of elements,
600e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod * starting at second element. */
601e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbodtemplate <typename Type>
60260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct HeadlessArrayOf
60360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
60460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline const Type& operator [] (unsigned int i) const
60560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
606e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod    if (HB_UNLIKELY (i >= len || !i)) return Null(Type);
607e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod    return array[i-1];
608e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod  }
60960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  inline unsigned int get_size () const
61079420ad9caf2d5fc94c3693e8292edfa27060b2dBehdad Esfahbod  { return sizeof (len) + (len ? len - 1 : 0) * sizeof (array[0]); }
6115f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
61220b035dad41247076815a2bbb0346d63058b322fBehdad Esfahbod  inline bool sanitize (SANITIZE_ARG_DEF) {
613b28815c1f6e46d38471cacbc31248ca6fda8c4d1Behdad Esfahbod    SANITIZE_DEBUG ();
614dc9c4d93cd0f3ac991f32df08c1c17fc389054c0Behdad Esfahbod    if (!SANITIZE_GET_SIZE()) return false;
6153564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod    /* Note:
6163564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * for non-recursive types, this is not much needed.
6173564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * But we keep the code to make sure the objects pointed to
6183564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod     * do have a simple sanitize(). */
6193564ee5216004d45d30b0ded61184cf8dde5dd89Behdad Esfahbod    return true;
62015164d9258a74122a4db748d35532bd72c47cec2Behdad Esfahbod    unsigned int count = len ? len - 1 : 0;
62170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
62270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod      if (!SANITIZE (array[i]))
62370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod        return false;
6249bd629ccd064e739789e504c41ad875eed93abbaBehdad Esfahbod    return true;
62570de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
62670de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
6275f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  USHORT len;
6285f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod  Type array[];
6295f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod};
6305f810363acc3ad3cba631a68620e3d37e54c95c4Behdad Esfahbod
6316b4ce01da121e12e1c78ad7eaedf469f35f3568dBehdad Esfahbod
6325f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#endif /* HB_OPEN_TYPES_PRIVATE_HH */
633