Imported Upstream version 2.5.5
[platform/upstream/freetype2.git] / src / gxvalid / gxvjust.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  gxvjust.c                                                              */
4 /*                                                                         */
5 /*    TrueTypeGX/AAT just table validation (body).                         */
6 /*                                                                         */
7 /*  Copyright 2005, 2014 by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18 /***************************************************************************/
19 /*                                                                         */
20 /* gxvalid is derived from both gxlayout module and otvalid module.        */
21 /* Development of gxlayout is supported by the Information-technology      */
22 /* Promotion Agency(IPA), Japan.                                           */
23 /*                                                                         */
24 /***************************************************************************/
25
26
27 #include "gxvalid.h"
28 #include "gxvcommn.h"
29
30 #include FT_SFNT_NAMES_H
31
32
33   /*************************************************************************/
34   /*                                                                       */
35   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
36   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
37   /* messages during execution.                                            */
38   /*                                                                       */
39 #undef  FT_COMPONENT
40 #define FT_COMPONENT  trace_gxvjust
41
42   /*
43    * referred `just' table format specification:
44    * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6just.html
45    * last updated 2000.
46    * ----------------------------------------------
47    * [JUST HEADER]: GXV_JUST_HEADER_SIZE
48    * version     (fixed:  32bit) = 0x00010000
49    * format      (uint16: 16bit) = 0 is only defined (2000)
50    * horizOffset (uint16: 16bit)
51    * vertOffset  (uint16: 16bit)
52    * ----------------------------------------------
53    */
54
55   typedef struct  GXV_just_DataRec_
56   {
57     FT_UShort  wdc_offset_max;
58     FT_UShort  wdc_offset_min;
59     FT_UShort  pc_offset_max;
60     FT_UShort  pc_offset_min;
61
62   } GXV_just_DataRec, *GXV_just_Data;
63
64
65 #define  GXV_JUST_DATA( a )  GXV_TABLE_DATA( just, a )
66
67
68   /* GX just table does not define their subset of GID */
69   static void
70   gxv_just_check_max_gid( FT_UShort         gid,
71                           const FT_String*  msg_tag,
72                           GXV_Validator     gxvalid )
73   {
74     if ( gid < gxvalid->face->num_glyphs )
75       return;
76
77     GXV_TRACE(( "just table includes too large %s"
78                 " GID=%d > %d (in maxp)\n",
79                 msg_tag, gid, gxvalid->face->num_glyphs ));
80     GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
81   }
82
83
84   static void
85   gxv_just_wdp_entry_validate( FT_Bytes       table,
86                                FT_Bytes       limit,
87                                GXV_Validator  gxvalid )
88   {
89     FT_Bytes   p = table;
90     FT_ULong   justClass;
91 #ifdef GXV_LOAD_UNUSED_VARS
92     FT_Fixed   beforeGrowLimit;
93     FT_Fixed   beforeShrinkGrowLimit;
94     FT_Fixed   afterGrowLimit;
95     FT_Fixed   afterShrinkGrowLimit;
96     FT_UShort  growFlags;
97     FT_UShort  shrinkFlags;
98 #endif
99
100
101     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 );
102     justClass             = FT_NEXT_ULONG( p );
103 #ifndef GXV_LOAD_UNUSED_VARS
104     p += 4 + 4 + 4 + 4 + 2 + 2;
105 #else
106     beforeGrowLimit       = FT_NEXT_ULONG( p );
107     beforeShrinkGrowLimit = FT_NEXT_ULONG( p );
108     afterGrowLimit        = FT_NEXT_ULONG( p );
109     afterShrinkGrowLimit  = FT_NEXT_ULONG( p );
110     growFlags             = FT_NEXT_USHORT( p );
111     shrinkFlags           = FT_NEXT_USHORT( p );
112 #endif
113
114     /* According to Apple spec, only 7bits in justClass is used */
115     if ( ( justClass & 0xFFFFFF80UL ) != 0 )
116     {
117       GXV_TRACE(( "just table includes non-zero value"
118                   " in unused justClass higher bits"
119                   " of WidthDeltaPair" ));
120       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
121     }
122
123     gxvalid->subtable_length = p - table;
124   }
125
126
127   static void
128   gxv_just_wdc_entry_validate( FT_Bytes       table,
129                                FT_Bytes       limit,
130                                GXV_Validator  gxvalid )
131   {
132     FT_Bytes  p = table;
133     FT_ULong  count, i;
134
135
136     GXV_LIMIT_CHECK( 4 );
137     count = FT_NEXT_ULONG( p );
138     for ( i = 0; i < count; i++ )
139     {
140       GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count ));
141       gxv_just_wdp_entry_validate( p, limit, gxvalid );
142       p += gxvalid->subtable_length;
143     }
144
145     gxvalid->subtable_length = p - table;
146   }
147
148
149   static void
150   gxv_just_widthDeltaClusters_validate( FT_Bytes       table,
151                                         FT_Bytes       limit,
152                                         GXV_Validator  gxvalid )
153   {
154     FT_Bytes  p         = table ;
155     FT_Bytes  wdc_end   = table + GXV_JUST_DATA( wdc_offset_max );
156     FT_UInt   i;
157
158
159     GXV_NAME_ENTER( "just justDeltaClusters" );
160
161     if ( limit <= wdc_end )
162       FT_INVALID_OFFSET;
163
164     for ( i = 0; p <= wdc_end; i++ )
165     {
166       gxv_just_wdc_entry_validate( p, limit, gxvalid );
167       p += gxvalid->subtable_length;
168     }
169
170     gxvalid->subtable_length = p - table;
171
172     GXV_EXIT;
173   }
174
175
176   static void
177   gxv_just_actSubrecord_type0_validate( FT_Bytes       table,
178                                         FT_Bytes       limit,
179                                         GXV_Validator  gxvalid )
180   {
181     FT_Bytes   p = table;
182
183     FT_Fixed   lowerLimit;
184     FT_Fixed   upperLimit;
185 #ifdef GXV_LOAD_UNUSED_VARS
186     FT_UShort  order;
187 #endif
188     FT_UShort  decomposedCount;
189
190     FT_UInt    i;
191
192
193     GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
194     lowerLimit      = FT_NEXT_ULONG( p );
195     upperLimit      = FT_NEXT_ULONG( p );
196 #ifdef GXV_LOAD_UNUSED_VARS
197     order           = FT_NEXT_USHORT( p );
198 #else
199     p += 2;
200 #endif
201     decomposedCount = FT_NEXT_USHORT( p );
202
203     if ( lowerLimit >= upperLimit )
204     {
205       GXV_TRACE(( "just table includes invalid range spec:"
206                   " lowerLimit(%d) > upperLimit(%d)\n"     ));
207       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
208     }
209
210     for ( i = 0; i < decomposedCount; i++ )
211     {
212       FT_UShort glyphs;
213
214
215       GXV_LIMIT_CHECK( 2 );
216       glyphs = FT_NEXT_USHORT( p );
217       gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid );
218     }
219
220     gxvalid->subtable_length = p - table;
221   }
222
223
224   static void
225   gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
226                                         FT_Bytes       limit,
227                                         GXV_Validator  gxvalid )
228   {
229     FT_Bytes   p = table;
230     FT_UShort  addGlyph;
231
232
233     GXV_LIMIT_CHECK( 2 );
234     addGlyph = FT_NEXT_USHORT( p );
235
236     gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid );
237
238     gxvalid->subtable_length = p - table;
239   }
240
241
242   static void
243   gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
244                                         FT_Bytes       limit,
245                                         GXV_Validator  gxvalid )
246   {
247     FT_Bytes   p = table;
248 #ifdef GXV_LOAD_UNUSED_VARS
249     FT_Fixed      substThreshhold; /* Apple misspelled "Threshhold" */
250 #endif
251     FT_UShort  addGlyph;
252     FT_UShort  substGlyph;
253
254
255     GXV_LIMIT_CHECK( 4 + 2 + 2 );
256 #ifdef GXV_LOAD_UNUSED_VARS
257     substThreshhold = FT_NEXT_ULONG( p );
258 #else
259     p += 4;
260 #endif
261     addGlyph        = FT_NEXT_USHORT( p );
262     substGlyph      = FT_NEXT_USHORT( p );
263
264     if ( addGlyph != 0xFFFF )
265       gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid );
266
267     gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid );
268
269     gxvalid->subtable_length = p - table;
270   }
271
272
273   static void
274   gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
275                                         FT_Bytes       limit,
276                                         GXV_Validator  gxvalid )
277   {
278     FT_Bytes  p = table;
279     FT_ULong  variantsAxis;
280     FT_Fixed  minimumLimit;
281     FT_Fixed  noStretchValue;
282     FT_Fixed  maximumLimit;
283
284
285     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
286     variantsAxis   = FT_NEXT_ULONG( p );
287     minimumLimit   = FT_NEXT_ULONG( p );
288     noStretchValue = FT_NEXT_ULONG( p );
289     maximumLimit   = FT_NEXT_ULONG( p );
290
291     gxvalid->subtable_length = p - table;
292
293     if ( variantsAxis != 0x64756374L ) /* 'duct' */
294       GXV_TRACE(( "variantsAxis 0x%08x is non default value",
295                    variantsAxis ));
296
297     if ( minimumLimit > noStretchValue )
298       GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n",
299                   minimumLimit, noStretchValue ));
300     else if ( noStretchValue > maximumLimit )
301       GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n",
302                   noStretchValue, maximumLimit ));
303     else if ( !IS_PARANOID_VALIDATION )
304       return;
305
306     FT_INVALID_DATA;
307   }
308
309
310   static void
311   gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
312                                         FT_Bytes       limit,
313                                         GXV_Validator  gxvalid )
314   {
315     FT_Bytes   p = table;
316     FT_UShort  flags;
317     FT_UShort  glyph;
318
319
320     GXV_LIMIT_CHECK( 2 + 2 );
321     flags = FT_NEXT_USHORT( p );
322     glyph = FT_NEXT_USHORT( p );
323
324     if ( flags )
325       GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n",
326                    flags ));
327     gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid );
328
329     gxvalid->subtable_length = p - table;
330   }
331
332
333   /* parse single actSubrecord */
334   static void
335   gxv_just_actSubrecord_validate( FT_Bytes       table,
336                                   FT_Bytes       limit,
337                                   GXV_Validator  gxvalid )
338   {
339     FT_Bytes   p = table;
340     FT_UShort  actionClass;
341     FT_UShort  actionType;
342     FT_ULong   actionLength;
343
344
345     GXV_NAME_ENTER( "just actSubrecord" );
346
347     GXV_LIMIT_CHECK( 2 + 2 + 4 );
348     actionClass  = FT_NEXT_USHORT( p );
349     actionType   = FT_NEXT_USHORT( p );
350     actionLength = FT_NEXT_ULONG( p );
351
352     /* actionClass is related with justClass using 7bit only */
353     if ( ( actionClass & 0xFF80 ) != 0 )
354       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
355
356     if ( actionType == 0 )
357       gxv_just_actSubrecord_type0_validate( p, limit, gxvalid );
358     else if ( actionType == 1 )
359       gxv_just_actSubrecord_type1_validate( p, limit, gxvalid );
360     else if ( actionType == 2 )
361       gxv_just_actSubrecord_type2_validate( p, limit, gxvalid );
362     else if ( actionType == 3 )
363       ;                         /* Stretch glyph action: no actionData */
364     else if ( actionType == 4 )
365       gxv_just_actSubrecord_type4_validate( p, limit, gxvalid );
366     else if ( actionType == 5 )
367       gxv_just_actSubrecord_type5_validate( p, limit, gxvalid );
368     else
369       FT_INVALID_DATA;
370
371     gxvalid->subtable_length = actionLength;
372
373     GXV_EXIT;
374   }
375
376
377   static void
378   gxv_just_pcActionRecord_validate( FT_Bytes       table,
379                                     FT_Bytes       limit,
380                                     GXV_Validator  gxvalid )
381   {
382     FT_Bytes  p = table;
383     FT_ULong  actionCount;
384     FT_ULong  i;
385
386
387     GXV_LIMIT_CHECK( 4 );
388     actionCount = FT_NEXT_ULONG( p );
389     GXV_TRACE(( "actionCount = %d\n", actionCount ));
390
391     for ( i = 0; i < actionCount; i++ )
392     {
393       gxv_just_actSubrecord_validate( p, limit, gxvalid );
394       p += gxvalid->subtable_length;
395     }
396
397     gxvalid->subtable_length = p - table;
398
399     GXV_EXIT;
400   }
401
402
403   static void
404   gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
405                                                GXV_LookupValueCPtr  value_p,
406                                                GXV_Validator        gxvalid )
407   {
408     FT_UNUSED( glyph );
409
410     if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) )
411       GXV_JUST_DATA( pc_offset_max ) = value_p->u;
412     if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) )
413       GXV_JUST_DATA( pc_offset_min ) = value_p->u;
414   }
415
416
417   static void
418   gxv_just_pcLookupTable_validate( FT_Bytes       table,
419                                    FT_Bytes       limit,
420                                    GXV_Validator  gxvalid )
421   {
422     FT_Bytes  p = table;
423
424
425     GXV_NAME_ENTER( "just pcLookupTable" );
426     GXV_JUST_DATA( pc_offset_max ) = 0x0000;
427     GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU;
428
429     gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
430     gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
431
432     gxv_LookupTable_validate( p, limit, gxvalid );
433
434     /* subtable_length is set by gxv_LookupTable_validate() */
435
436     GXV_EXIT;
437   }
438
439
440   static void
441   gxv_just_postcompTable_validate( FT_Bytes       table,
442                                    FT_Bytes       limit,
443                                    GXV_Validator  gxvalid )
444   {
445     FT_Bytes  p = table;
446
447
448     GXV_NAME_ENTER( "just postcompTable" );
449
450     gxv_just_pcLookupTable_validate( p, limit, gxvalid );
451     p += gxvalid->subtable_length;
452
453     gxv_just_pcActionRecord_validate( p, limit, gxvalid );
454     p += gxvalid->subtable_length;
455
456     gxvalid->subtable_length = p - table;
457
458     GXV_EXIT;
459   }
460
461
462   static void
463   gxv_just_classTable_entry_validate(
464     FT_Byte                         state,
465     FT_UShort                       flags,
466     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
467     FT_Bytes                        table,
468     FT_Bytes                        limit,
469     GXV_Validator                   gxvalid )
470   {
471 #ifdef GXV_LOAD_UNUSED_VARS
472     /* TODO: validate markClass & currentClass */
473     FT_UShort  setMark;
474     FT_UShort  dontAdvance;
475     FT_UShort  markClass;
476     FT_UShort  currentClass;
477 #endif
478
479     FT_UNUSED( state );
480     FT_UNUSED( glyphOffset_p );
481     FT_UNUSED( table );
482     FT_UNUSED( limit );
483     FT_UNUSED( gxvalid );
484
485 #ifndef GXV_LOAD_UNUSED_VARS
486     FT_UNUSED( flags );
487 #else
488     setMark      = (FT_UShort)( ( flags >> 15 ) & 1    );
489     dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1    );
490     markClass    = (FT_UShort)( ( flags >> 7  ) & 0x7F );
491     currentClass = (FT_UShort)(   flags         & 0x7F );
492 #endif
493   }
494
495
496   static void
497   gxv_just_justClassTable_validate ( FT_Bytes       table,
498                                      FT_Bytes       limit,
499                                      GXV_Validator  gxvalid )
500   {
501     FT_Bytes   p = table;
502     FT_UShort  length;
503     FT_UShort  coverage;
504     FT_ULong   subFeatureFlags;
505
506
507     GXV_NAME_ENTER( "just justClassTable" );
508
509     GXV_LIMIT_CHECK( 2 + 2 + 4 );
510     length          = FT_NEXT_USHORT( p );
511     coverage        = FT_NEXT_USHORT( p );
512     subFeatureFlags = FT_NEXT_ULONG( p );
513
514     GXV_TRACE(( "  justClassTable: coverage = 0x%04x (%s) ", coverage ));
515     if ( ( coverage & 0x4000 ) == 0  )
516       GXV_TRACE(( "ascending\n" ));
517     else
518       GXV_TRACE(( "descending\n" ));
519
520     if ( subFeatureFlags )
521       GXV_TRACE(( "  justClassTable: nonzero value (0x%08x)"
522                   " in unused subFeatureFlags\n", subFeatureFlags ));
523
524     gxvalid->statetable.optdata               = NULL;
525     gxvalid->statetable.optdata_load_func     = NULL;
526     gxvalid->statetable.subtable_setup_func   = NULL;
527     gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
528     gxvalid->statetable.entry_validate_func   =
529       gxv_just_classTable_entry_validate;
530
531     gxv_StateTable_validate( p, table + length, gxvalid );
532
533     /* subtable_length is set by gxv_LookupTable_validate() */
534
535     GXV_EXIT;
536   }
537
538
539   static void
540   gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
541                                           GXV_LookupValueCPtr  value_p,
542                                           GXV_Validator        gxvalid )
543   {
544     FT_UNUSED( glyph );
545
546     if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) )
547       GXV_JUST_DATA( wdc_offset_max ) = value_p->u;
548     if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) )
549       GXV_JUST_DATA( wdc_offset_min ) = value_p->u;
550   }
551
552
553   static void
554   gxv_just_justData_lookuptable_validate( FT_Bytes       table,
555                                           FT_Bytes       limit,
556                                           GXV_Validator  gxvalid )
557   {
558     FT_Bytes  p = table;
559
560
561     GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
562     GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU;
563
564     gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
565     gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
566
567     gxv_LookupTable_validate( p, limit, gxvalid );
568
569     /* subtable_length is set by gxv_LookupTable_validate() */
570
571     GXV_EXIT;
572   }
573
574
575   /*
576    * gxv_just_justData_validate() parses and validates horizData, vertData.
577    */
578   static void
579   gxv_just_justData_validate( FT_Bytes       table,
580                               FT_Bytes       limit,
581                               GXV_Validator  gxvalid )
582   {
583     /*
584      * following 3 offsets are measured from the start of `just'
585      * (which table points to), not justData
586      */
587     FT_UShort  justClassTableOffset;
588     FT_UShort  wdcTableOffset;
589     FT_UShort  pcTableOffset;
590     FT_Bytes   p = table;
591
592     GXV_ODTECT( 4, odtect );
593
594
595     GXV_NAME_ENTER( "just justData" );
596
597     GXV_ODTECT_INIT( odtect );
598     GXV_LIMIT_CHECK( 2 + 2 + 2 );
599     justClassTableOffset = FT_NEXT_USHORT( p );
600     wdcTableOffset       = FT_NEXT_USHORT( p );
601     pcTableOffset        = FT_NEXT_USHORT( p );
602
603     GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
604     GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
605     GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
606
607     gxv_just_justData_lookuptable_validate( p, limit, gxvalid );
608     gxv_odtect_add_range( p, gxvalid->subtable_length,
609                           "just_LookupTable", odtect );
610
611     if ( wdcTableOffset )
612     {
613       gxv_just_widthDeltaClusters_validate(
614         gxvalid->root->base + wdcTableOffset, limit, gxvalid );
615       gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset,
616                             gxvalid->subtable_length, "just_wdcTable", odtect );
617     }
618
619     if ( pcTableOffset )
620     {
621       gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset,
622                                        limit, gxvalid );
623       gxv_odtect_add_range( gxvalid->root->base + pcTableOffset,
624                             gxvalid->subtable_length, "just_pcTable", odtect );
625     }
626
627     if ( justClassTableOffset )
628     {
629       gxv_just_justClassTable_validate(
630         gxvalid->root->base + justClassTableOffset, limit, gxvalid );
631       gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset,
632                             gxvalid->subtable_length, "just_justClassTable",
633                             odtect );
634     }
635
636     gxv_odtect_validate( odtect, gxvalid );
637
638     GXV_EXIT;
639   }
640
641
642   FT_LOCAL_DEF( void )
643   gxv_just_validate( FT_Bytes      table,
644                      FT_Face       face,
645                      FT_Validator  ftvalid )
646   {
647     FT_Bytes           p     = table;
648     FT_Bytes           limit = 0;
649
650     GXV_ValidatorRec   gxvalidrec;
651     GXV_Validator      gxvalid = &gxvalidrec;
652     GXV_just_DataRec   justrec;
653     GXV_just_Data      just = &justrec;
654
655     FT_ULong           version;
656     FT_UShort          format;
657     FT_UShort          horizOffset;
658     FT_UShort          vertOffset;
659
660     GXV_ODTECT( 3, odtect );
661
662
663     GXV_ODTECT_INIT( odtect );
664
665     gxvalid->root       = ftvalid;
666     gxvalid->table_data = just;
667     gxvalid->face       = face;
668
669     FT_TRACE3(( "validating `just' table\n" ));
670     GXV_INIT;
671
672     limit      = gxvalid->root->limit;
673
674     GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
675     version     = FT_NEXT_ULONG( p );
676     format      = FT_NEXT_USHORT( p );
677     horizOffset = FT_NEXT_USHORT( p );
678     vertOffset  = FT_NEXT_USHORT( p );
679     gxv_odtect_add_range( table, p - table, "just header", odtect );
680
681
682     /* Version 1.0 (always:2000) */
683     GXV_TRACE(( " (version = 0x%08x)\n", version ));
684     if ( version != 0x00010000UL )
685       FT_INVALID_FORMAT;
686
687     /* format 0 (always:2000) */
688     GXV_TRACE(( " (format = 0x%04x)\n", format ));
689     if ( format != 0x0000 )
690         FT_INVALID_FORMAT;
691
692     GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
693     GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
694
695
696     /* validate justData */
697     if ( 0 < horizOffset )
698     {
699       gxv_just_justData_validate( table + horizOffset, limit, gxvalid );
700       gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length,
701                             "horizJustData", odtect );
702     }
703
704     if ( 0 < vertOffset )
705     {
706       gxv_just_justData_validate( table + vertOffset, limit, gxvalid );
707       gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length,
708                             "vertJustData", odtect );
709     }
710
711     gxv_odtect_validate( odtect, gxvalid );
712
713     FT_TRACE4(( "\n" ));
714   }
715
716
717 /* END */