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