Clean up NO_INDEX
[profile/ivi/org.tizen.video-player.git] / src / hb-open-type-private.hh
1 /*
2  * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #ifndef HB_OPEN_TYPES_PRIVATE_HH
28 #define HB_OPEN_TYPES_PRIVATE_HH
29
30 #include "hb-private.h"
31
32 #include "hb-blob.h"
33
34
35
36 /*
37  * Casts
38  */
39
40 /* Cast to struct T, reference to reference */
41 template<typename Type, typename TObject>
42 inline const Type& CastR(const TObject &X)
43 { return reinterpret_cast<const Type&> (X); }
44 template<typename Type, typename TObject>
45 inline Type& CastR(TObject &X)
46 { return reinterpret_cast<Type&> (X); }
47
48 /* Cast to struct T, pointer to pointer */
49 template<typename Type, typename TObject>
50 inline const Type* CastP(const TObject *X)
51 { return reinterpret_cast<const Type*> (X); }
52 template<typename Type, typename TObject>
53 inline Type* CastP(TObject *X)
54 { return reinterpret_cast<Type*> (X); }
55
56 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
57  * location pointed to by P plus Ofs bytes. */
58 template<typename Type>
59 inline const Type& StructAtOffset(const void *P, unsigned int offset)
60 { return * reinterpret_cast<const Type*> ((const char *) P + offset); }
61 template<typename Type>
62 inline Type& StructAtOffset(void *P, unsigned int offset)
63 { return * reinterpret_cast<Type*> ((char *) P + offset); }
64
65 /* StructAfter<T>(X) returns the struct T& that is placed after X.
66  * Works with X of variable size also.  X must implement get_size() */
67 template<typename Type, typename TObject>
68 inline const Type& StructAfter(const TObject &X)
69 { return StructAtOffset<Type>(&X, X.get_size()); }
70 template<typename Type, typename TObject>
71 inline Type& StructAfter(TObject &X)
72 { return StructAtOffset<Type>(&X, X.get_size()); }
73
74
75
76 /*
77  * Size checking
78  */
79
80 #define _DEFINE_SIZE_ASSERTION(_assertion) \
81   inline void _size_assertion (void) const \
82   { ASSERT_STATIC (_assertion); }
83
84
85 #define DEFINE_SIZE_STATIC(size) \
86   _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size)); \
87   static const unsigned int static_size = (size); \
88   static const unsigned int min_size = (size)
89
90 /* Size signifying variable-sized array */
91 #define VAR 1
92
93 #define DEFINE_SIZE_UNION(size, _member) \
94   _DEFINE_SIZE_ASSERTION (this->u._member.static_size == (size)); \
95   static const unsigned int min_size = (size)
96
97 #define DEFINE_SIZE_MIN(size) \
98   _DEFINE_SIZE_ASSERTION (sizeof (*this) >= (size)); \
99   static const unsigned int min_size = (size)
100
101 #define DEFINE_SIZE_ARRAY(size, array) \
102   _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + array[0].static_size); \
103   static const unsigned int min_size = (size)
104
105 #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
106   _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + this->array1[0].static_size + this->array2[0].static_size); \
107   static const unsigned int min_size = (size)
108
109
110
111 /*
112  * Null objects
113  */
114
115 /* Global nul-content Null pool.  Enlarge as necessary. */
116 static const void *_NullPool[32 / sizeof (void *)];
117
118 /* Generic nul-content Null objects. */
119 template <typename Type>
120 static inline const Type& Null () {
121   ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
122   return *CastP<Type> (_NullPool);
123 }
124
125 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
126 #define DEFINE_NULL_DATA(Type, data) \
127 static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
128 template <> \
129 inline const Type& Null<Type> () { \
130   return *CastP<Type> (_Null##Type); \
131 } /* The following line really exists such that we end in a place needing semicolon */ \
132 ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
133
134 /* Accessor macro. */
135 #define Null(Type) Null<Type>()
136
137
138 /*
139  * Trace
140  */
141
142
143 template <int max_depth>
144 struct hb_trace_t {
145   explicit hb_trace_t (unsigned int *pdepth, const char *what, const char *function, const void *obj) : pdepth(pdepth) {
146     if (*pdepth < max_depth)
147       fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function);
148     if (max_depth) ++*pdepth;
149   }
150   ~hb_trace_t (void) { if (max_depth) --*pdepth; }
151
152   private:
153   unsigned int *pdepth;
154 };
155 template <> /* Optimize when tracing is disabled */
156 struct hb_trace_t<0> {
157   explicit hb_trace_t (unsigned int *pdepth, const char *what, const char *function, const void *obj) {}
158 };
159
160
161
162 /*
163  * Sanitize
164  */
165
166 #ifndef HB_DEBUG_SANITIZE
167 #define HB_DEBUG_SANITIZE HB_DEBUG+0
168 #endif
169
170
171 #define TRACE_SANITIZE() \
172         hb_trace_t<HB_DEBUG_SANITIZE> trace (&context->debug_depth, "SANITIZE", HB_FUNC, this); \
173
174
175 struct hb_sanitize_context_t
176 {
177   inline void init (hb_blob_t *blob)
178   {
179     this->blob = hb_blob_reference (blob);
180     this->start = hb_blob_lock (blob);
181     this->end = this->start + hb_blob_get_length (blob);
182     this->writable = hb_blob_is_writable (blob);
183     this->edit_count = 0;
184     this->debug_depth = 0;
185
186     if (HB_DEBUG_SANITIZE)
187       fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
188                this->blob, this->start, this->end, this->end - this->start);
189   }
190
191   inline void finish (void)
192   {
193     if (HB_DEBUG_SANITIZE)
194       fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
195                this->blob, this->start, this->end, this->edit_count);
196
197     hb_blob_unlock (this->blob);
198     hb_blob_destroy (this->blob);
199     this->blob = NULL;
200     this->start = this->end = NULL;
201   }
202
203   inline bool check_range (const void *base, unsigned int len) const
204   {
205     const char *p = (const char *) base;
206     bool ret = this->start <= p &&
207                p <= this->end &&
208                (unsigned int) (this->end - p) >= len;
209
210     if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE) \
211       fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
212                p,
213                this->debug_depth, this->debug_depth,
214                p, p + len, len,
215                this->start, this->end,
216                ret ? "pass" : "FAIL");
217
218     return likely (ret);
219   }
220
221   inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
222   {
223     const char *p = (const char *) base;
224     bool overflows = len >= ((unsigned int) -1) / record_size;
225
226     if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
227       fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
228                p,
229                this->debug_depth, this->debug_depth,
230                p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
231                this->start, this->end,
232                !overflows ? "does not overflow" : "OVERFLOWS FAIL");
233
234     return likely (!overflows && this->check_range (base, record_size * len));
235   }
236
237   template <typename Type>
238   inline bool check_struct (const Type *obj) const
239   {
240     return likely (this->check_range (obj, obj->min_size));
241   }
242
243   inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
244   {
245     const char *p = (const char *) base;
246     this->edit_count++;
247
248     if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
249       fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
250                p,
251                this->debug_depth, this->debug_depth,
252                this->edit_count,
253                p, p + len, len,
254                this->start, this->end,
255                this->writable ? "granted" : "REJECTED");
256
257     return this->writable;
258   }
259
260   unsigned int debug_depth;
261   const char *start, *end;
262   bool writable;
263   unsigned int edit_count;
264   hb_blob_t *blob;
265 };
266
267
268
269 /* Template to sanitize an object. */
270 template <typename Type>
271 struct Sanitizer
272 {
273   static hb_blob_t *sanitize (hb_blob_t *blob) {
274     hb_sanitize_context_t context[1] = {{0}};
275     bool sane;
276
277     /* TODO is_sane() stuff */
278
279   retry:
280     if (HB_DEBUG_SANITIZE)
281       fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);
282
283     context->init (blob);
284
285     if (unlikely (!context->start)) {
286       context->finish ();
287       return blob;
288     }
289
290     Type *t = CastP<Type> (const_cast<char *> (context->start));
291
292     sane = t->sanitize (context);
293     if (sane) {
294       if (context->edit_count) {
295         if (HB_DEBUG_SANITIZE)
296           fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n",
297                    blob, context->edit_count, HB_FUNC);
298
299         /* sanitize again to ensure no toe-stepping */
300         context->edit_count = 0;
301         sane = t->sanitize (context);
302         if (context->edit_count) {
303           if (HB_DEBUG_SANITIZE)
304             fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
305                      blob, context->edit_count, HB_FUNC);
306           sane = false;
307         }
308       }
309       context->finish ();
310     } else {
311       unsigned int edit_count = context->edit_count;
312       context->finish ();
313       if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
314         /* ok, we made it writable by relocating.  try again */
315         if (HB_DEBUG_SANITIZE)
316           fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC);
317         goto retry;
318       }
319     }
320
321     if (HB_DEBUG_SANITIZE)
322       fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC);
323     if (sane)
324       return blob;
325     else {
326       hb_blob_destroy (blob);
327       return hb_blob_create_empty ();
328     }
329   }
330
331   static const Type* lock_instance (hb_blob_t *blob) {
332     const char *base = hb_blob_lock (blob);
333     return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
334   }
335 };
336
337
338
339
340 /*
341  *
342  * The OpenType Font File: Data Types
343  */
344
345
346 /* "The following data types are used in the OpenType font file.
347  *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
348
349 /*
350  * Int types
351  */
352
353
354 template <typename Type, int Bytes> class BEInt;
355
356 /* LONGTERMTODO: On machines allowing unaligned access, we can make the
357  * following tighter by using byteswap instructions on ints directly. */
358 template <typename Type>
359 class BEInt<Type, 2>
360 {
361   public:
362   inline class BEInt<Type,2>& operator = (Type i) { hb_be_uint16_put (v,i); return *this; }
363   inline operator Type () const { return hb_be_uint16_get (v); }
364   inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); }
365   inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
366   private: uint8_t v[2];
367 };
368 template <typename Type>
369 class BEInt<Type, 4>
370 {
371   public:
372   inline class BEInt<Type,4>& operator = (Type i) { hb_be_uint32_put (v,i); return *this; }
373   inline operator Type () const { return hb_be_uint32_get (v); }
374   inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_cmp (v, o.v); }
375   inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
376   private: uint8_t v[4];
377 };
378
379 /* Integer types in big-endian order and no alignment requirement */
380 template <typename Type>
381 struct IntType
382 {
383   inline void set (Type i) { v = i; }
384   inline operator Type(void) const { return v; }
385   inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
386   inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
387   inline bool sanitize (hb_sanitize_context_t *context) {
388     TRACE_SANITIZE ();
389     return context->check_struct (this);
390   }
391   protected:
392   BEInt<Type, sizeof (Type)> v;
393   public:
394   DEFINE_SIZE_STATIC (sizeof (Type));
395 };
396
397 typedef IntType<uint16_t> USHORT;       /* 16-bit unsigned integer. */
398 typedef IntType<int16_t>  SHORT;        /* 16-bit signed integer. */
399 typedef IntType<uint32_t> ULONG;        /* 32-bit unsigned integer. */
400 typedef IntType<int32_t>  LONG;         /* 32-bit signed integer. */
401
402 /* Array of four uint8s (length = 32 bits) used to identify a script, language
403  * system, feature, or baseline */
404 struct Tag : ULONG
405 {
406   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
407   inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
408   inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
409   public:
410   DEFINE_SIZE_STATIC (4);
411 };
412 DEFINE_NULL_DATA (Tag, "    ");
413
414 /* Glyph index number, same as uint16 (length = 16 bits) */
415 typedef USHORT GlyphID;
416
417 /* Script/language-system/feature index */
418 struct Index : USHORT {
419   static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
420 };
421 DEFINE_NULL_DATA (Index, "\xff\xff");
422
423 /* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
424 typedef USHORT Offset;
425
426 /* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
427 typedef ULONG LongOffset;
428
429
430 /* CheckSum */
431 struct CheckSum : ULONG
432 {
433   static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
434   {
435     uint32_t Sum = 0L;
436     ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
437
438     while (Table < EndPtr)
439       Sum += *Table++;
440     return Sum;
441   }
442   public:
443   DEFINE_SIZE_STATIC (4);
444 };
445
446
447 /*
448  * Version Numbers
449  */
450
451 struct FixedVersion
452 {
453   inline operator uint32_t (void) const { return (major << 16) + minor; }
454
455   inline bool sanitize (hb_sanitize_context_t *context) {
456     TRACE_SANITIZE ();
457     return context->check_struct (this);
458   }
459
460   USHORT major;
461   USHORT minor;
462   public:
463   DEFINE_SIZE_STATIC (4);
464 };
465
466
467
468 /*
469  * Template subclasses of Offset and LongOffset that do the dereferencing.
470  * Use: (base+offset)
471  */
472
473 template <typename OffsetType, typename Type>
474 struct GenericOffsetTo : OffsetType
475 {
476   inline const Type& operator () (const void *base) const
477   {
478     unsigned int offset = *this;
479     if (unlikely (!offset)) return Null(Type);
480     return StructAtOffset<Type> (base, offset);
481   }
482
483   inline bool sanitize (hb_sanitize_context_t *context, void *base) {
484     TRACE_SANITIZE ();
485     if (!context->check_struct (this)) return false;
486     unsigned int offset = *this;
487     if (unlikely (!offset)) return true;
488     Type &obj = StructAtOffset<Type> (base, offset);
489     return likely (obj.sanitize (context)) || neuter (context);
490   }
491   template <typename T>
492   inline bool sanitize (hb_sanitize_context_t *context, void *base, T user_data) {
493     TRACE_SANITIZE ();
494     if (!context->check_struct (this)) return false;
495     unsigned int offset = *this;
496     if (unlikely (!offset)) return true;
497     Type &obj = StructAtOffset<Type> (base, offset);
498     return likely (obj.sanitize (context, user_data)) || neuter (context);
499   }
500
501   private:
502   /* Set the offset to Null */
503   inline bool neuter (hb_sanitize_context_t *context) {
504     if (context->can_edit (this, this->static_size)) {
505       this->set (0); /* 0 is Null offset */
506       return true;
507     }
508     return false;
509   }
510 };
511 template <typename Base, typename OffsetType, typename Type>
512 inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
513
514 template <typename Type>
515 struct OffsetTo : GenericOffsetTo<Offset, Type> {};
516
517 template <typename Type>
518 struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
519
520
521 /*
522  * Array Types
523  */
524
525 template <typename LenType, typename Type>
526 struct GenericArrayOf
527 {
528   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
529   {
530     unsigned int count = len;
531     if (unlikely (start_offset > count))
532       count = 0;
533     else
534       count -= start_offset;
535     count = MIN (count, *pcount);
536     *pcount = count;
537     return array + start_offset;
538   }
539
540   inline const Type& operator [] (unsigned int i) const
541   {
542     if (unlikely (i >= len)) return Null(Type);
543     return array[i];
544   }
545   inline unsigned int get_size () const
546   { return len.static_size + len * Type::static_size; }
547
548   inline bool sanitize (hb_sanitize_context_t *context) {
549     TRACE_SANITIZE ();
550     if (!likely (sanitize_shallow (context))) return false;
551     /* Note: for structs that do not reference other structs,
552      * we do not need to call their sanitize() as we already did
553      * a bound check on the aggregate array size, hence the return.
554      */
555     return true;
556     /* We do keep this code though to make sure the structs pointed
557      * to do have a simple sanitize(), ie. they do not reference
558      * other structs. */
559     unsigned int count = len;
560     for (unsigned int i = 0; i < count; i++)
561       if (array[i].sanitize (context))
562         return false;
563     return true;
564   }
565   inline bool sanitize (hb_sanitize_context_t *context, void *base) {
566     TRACE_SANITIZE ();
567     if (!likely (sanitize_shallow (context))) return false;
568     unsigned int count = len;
569     for (unsigned int i = 0; i < count; i++)
570       if (!array[i].sanitize (context, base))
571         return false;
572     return true;
573   }
574   template <typename T>
575   inline bool sanitize (hb_sanitize_context_t *context, void *base, T user_data) {
576     TRACE_SANITIZE ();
577     if (!likely (sanitize_shallow (context))) return false;
578     unsigned int count = len;
579     for (unsigned int i = 0; i < count; i++)
580       if (!array[i].sanitize (context, base, user_data))
581         return false;
582     return true;
583   }
584
585   private:
586   inline bool sanitize_shallow (hb_sanitize_context_t *context) {
587     TRACE_SANITIZE ();
588     return context->check_struct (this)
589         && context->check_array (this, Type::static_size, len);
590   }
591
592   public:
593   LenType len;
594   Type array[VAR];
595   public:
596   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
597 };
598
599 /* An array with a USHORT number of elements. */
600 template <typename Type>
601 struct ArrayOf : GenericArrayOf<USHORT, Type> {};
602
603 /* An array with a ULONG number of elements. */
604 template <typename Type>
605 struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
606
607 /* Array of Offset's */
608 template <typename Type>
609 struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
610
611 /* Array of LongOffset's */
612 template <typename Type>
613 struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
614
615 /* LongArray of LongOffset's */
616 template <typename Type>
617 struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
618
619 /* Array of offsets relative to the beginning of the array itself. */
620 template <typename Type>
621 struct OffsetListOf : OffsetArrayOf<Type>
622 {
623   inline const Type& operator [] (unsigned int i) const
624   {
625     if (unlikely (i >= this->len)) return Null(Type);
626     return this+this->array[i];
627   }
628
629   inline bool sanitize (hb_sanitize_context_t *context) {
630     TRACE_SANITIZE ();
631     return OffsetArrayOf<Type>::sanitize (context, this);
632   }
633   template <typename T>
634   inline bool sanitize (hb_sanitize_context_t *context, T user_data) {
635     TRACE_SANITIZE ();
636     return OffsetArrayOf<Type>::sanitize (context, this, user_data);
637   }
638 };
639
640
641 /* An array with a USHORT number of elements,
642  * starting at second element. */
643 template <typename Type>
644 struct HeadlessArrayOf
645 {
646   inline const Type& operator [] (unsigned int i) const
647   {
648     if (unlikely (i >= len || !i)) return Null(Type);
649     return array[i-1];
650   }
651   inline unsigned int get_size () const
652   { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
653
654   inline bool sanitize_shallow (hb_sanitize_context_t *context) {
655     return context->check_struct (this)
656         && context->check_array (this, Type::static_size, len);
657   }
658
659   inline bool sanitize (hb_sanitize_context_t *context) {
660     TRACE_SANITIZE ();
661     if (!likely (sanitize_shallow (context))) return false;
662     /* Note: for structs that do not reference other structs,
663      * we do not need to call their sanitize() as we already did
664      * a bound check on the aggregate array size, hence the return.
665      */
666     return true;
667     /* We do keep this code though to make sure the structs pointed
668      * to do have a simple sanitize(), ie. they do not reference
669      * other structs. */
670     unsigned int count = len ? len - 1 : 0;
671     Type *a = array;
672     for (unsigned int i = 0; i < count; i++)
673       if (!a[i].sanitize (context))
674         return false;
675     return true;
676   }
677
678   USHORT len;
679   Type array[VAR];
680   public:
681   DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
682 };
683
684
685 #endif /* HB_OPEN_TYPE_PRIVATE_HH */