• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * gxvjust.c
4  *
5  *   TrueTypeGX/AAT just table validation (body).
6  *
7  * Copyright (C) 2005-2022 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 > %ld (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 %lu/%lu\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(%ld) > upperLimit(%ld)\n",
210                   lowerLimit, upperLimit ));
211       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
212     }
213 
214     for ( i = 0; i < decomposedCount; i++ )
215     {
216       FT_UShort glyphs;
217 
218 
219       GXV_LIMIT_CHECK( 2 );
220       glyphs = FT_NEXT_USHORT( p );
221       gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid );
222     }
223 
224     gxvalid->subtable_length = (FT_ULong)( p - table );
225   }
226 
227 
228   static void
gxv_just_actSubrecord_type1_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)229   gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
230                                         FT_Bytes       limit,
231                                         GXV_Validator  gxvalid )
232   {
233     FT_Bytes   p = table;
234     FT_UShort  addGlyph;
235 
236 
237     GXV_LIMIT_CHECK( 2 );
238     addGlyph = FT_NEXT_USHORT( p );
239 
240     gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid );
241 
242     gxvalid->subtable_length = (FT_ULong)( p - table );
243   }
244 
245 
246   static void
gxv_just_actSubrecord_type2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)247   gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
248                                         FT_Bytes       limit,
249                                         GXV_Validator  gxvalid )
250   {
251     FT_Bytes   p = table;
252 #ifdef GXV_LOAD_UNUSED_VARS
253     FT_Fixed      substThreshhold; /* Apple misspelled "Threshhold" */
254 #endif
255     FT_UShort  addGlyph;
256     FT_UShort  substGlyph;
257 
258 
259     GXV_LIMIT_CHECK( 4 + 2 + 2 );
260 #ifdef GXV_LOAD_UNUSED_VARS
261     substThreshhold = FT_NEXT_ULONG( p );
262 #else
263     p += 4;
264 #endif
265     addGlyph        = FT_NEXT_USHORT( p );
266     substGlyph      = FT_NEXT_USHORT( p );
267 
268     if ( addGlyph != 0xFFFF )
269       gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid );
270 
271     gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid );
272 
273     gxvalid->subtable_length = (FT_ULong)( p - table );
274   }
275 
276 
277   static void
gxv_just_actSubrecord_type4_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)278   gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
279                                         FT_Bytes       limit,
280                                         GXV_Validator  gxvalid )
281   {
282     FT_Bytes  p = table;
283     FT_ULong  variantsAxis;
284     FT_Fixed  minimumLimit;
285     FT_Fixed  noStretchValue;
286     FT_Fixed  maximumLimit;
287 
288 
289     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
290     variantsAxis   = FT_NEXT_ULONG( p );
291     minimumLimit   = FT_NEXT_LONG( p );
292     noStretchValue = FT_NEXT_LONG( p );
293     maximumLimit   = FT_NEXT_LONG( p );
294 
295     gxvalid->subtable_length = (FT_ULong)( p - table );
296 
297     if ( variantsAxis != 0x64756374L ) /* 'duct' */
298       GXV_TRACE(( "variantsAxis 0x%08lx is non default value",
299                    variantsAxis ));
300 
301     if ( minimumLimit > noStretchValue )
302       GXV_TRACE(( "type4:minimumLimit 0x%08lx > noStretchValue 0x%08lx\n",
303                   minimumLimit, noStretchValue ));
304     else if ( noStretchValue > maximumLimit )
305       GXV_TRACE(( "type4:noStretchValue 0x%08lx > maximumLimit 0x%08lx\n",
306                   noStretchValue, maximumLimit ));
307     else if ( !IS_PARANOID_VALIDATION )
308       return;
309 
310     FT_INVALID_DATA;
311   }
312 
313 
314   static void
gxv_just_actSubrecord_type5_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)315   gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
316                                         FT_Bytes       limit,
317                                         GXV_Validator  gxvalid )
318   {
319     FT_Bytes   p = table;
320     FT_UShort  flags;
321     FT_UShort  glyph;
322 
323 
324     GXV_LIMIT_CHECK( 2 + 2 );
325     flags = FT_NEXT_USHORT( p );
326     glyph = FT_NEXT_USHORT( p );
327 
328     if ( flags )
329       GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n",
330                    flags ));
331     gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid );
332 
333     gxvalid->subtable_length = (FT_ULong)( p - table );
334   }
335 
336 
337   /* parse single actSubrecord */
338   static void
gxv_just_actSubrecord_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)339   gxv_just_actSubrecord_validate( FT_Bytes       table,
340                                   FT_Bytes       limit,
341                                   GXV_Validator  gxvalid )
342   {
343     FT_Bytes   p = table;
344     FT_UShort  actionClass;
345     FT_UShort  actionType;
346     FT_ULong   actionLength;
347 
348 
349     GXV_NAME_ENTER( "just actSubrecord" );
350 
351     GXV_LIMIT_CHECK( 2 + 2 + 4 );
352     actionClass  = FT_NEXT_USHORT( p );
353     actionType   = FT_NEXT_USHORT( p );
354     actionLength = FT_NEXT_ULONG( p );
355 
356     /* actionClass is related with justClass using 7bit only */
357     if ( ( actionClass & 0xFF80 ) != 0 )
358       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
359 
360     if ( actionType == 0 )
361       gxv_just_actSubrecord_type0_validate( p, limit, gxvalid );
362     else if ( actionType == 1 )
363       gxv_just_actSubrecord_type1_validate( p, limit, gxvalid );
364     else if ( actionType == 2 )
365       gxv_just_actSubrecord_type2_validate( p, limit, gxvalid );
366     else if ( actionType == 3 )
367       ;                         /* Stretch glyph action: no actionData */
368     else if ( actionType == 4 )
369       gxv_just_actSubrecord_type4_validate( p, limit, gxvalid );
370     else if ( actionType == 5 )
371       gxv_just_actSubrecord_type5_validate( p, limit, gxvalid );
372     else
373       FT_INVALID_DATA;
374 
375     gxvalid->subtable_length = actionLength;
376 
377     GXV_EXIT;
378   }
379 
380 
381   static void
gxv_just_pcActionRecord_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)382   gxv_just_pcActionRecord_validate( FT_Bytes       table,
383                                     FT_Bytes       limit,
384                                     GXV_Validator  gxvalid )
385   {
386     FT_Bytes  p = table;
387     FT_ULong  actionCount;
388     FT_ULong  i;
389 
390 
391     GXV_LIMIT_CHECK( 4 );
392     actionCount = FT_NEXT_ULONG( p );
393     GXV_TRACE(( "actionCount = %lu\n", actionCount ));
394 
395     for ( i = 0; i < actionCount; i++ )
396     {
397       gxv_just_actSubrecord_validate( p, limit, gxvalid );
398       p += gxvalid->subtable_length;
399     }
400 
401     gxvalid->subtable_length = (FT_ULong)( p - table );
402 
403     GXV_EXIT;
404   }
405 
406 
407   static void
gxv_just_pcTable_LookupValue_entry_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)408   gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
409                                                GXV_LookupValueCPtr  value_p,
410                                                GXV_Validator        gxvalid )
411   {
412     FT_UNUSED( glyph );
413 
414     if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) )
415       GXV_JUST_DATA( pc_offset_max ) = value_p->u;
416     if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) )
417       GXV_JUST_DATA( pc_offset_min ) = value_p->u;
418   }
419 
420 
421   static void
gxv_just_pcLookupTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)422   gxv_just_pcLookupTable_validate( FT_Bytes       table,
423                                    FT_Bytes       limit,
424                                    GXV_Validator  gxvalid )
425   {
426     FT_Bytes  p = table;
427 
428 
429     GXV_NAME_ENTER( "just pcLookupTable" );
430     GXV_JUST_DATA( pc_offset_max ) = 0x0000;
431     GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU;
432 
433     gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
434     gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
435 
436     gxv_LookupTable_validate( p, limit, gxvalid );
437 
438     /* subtable_length is set by gxv_LookupTable_validate() */
439 
440     GXV_EXIT;
441   }
442 
443 
444   static void
gxv_just_postcompTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)445   gxv_just_postcompTable_validate( FT_Bytes       table,
446                                    FT_Bytes       limit,
447                                    GXV_Validator  gxvalid )
448   {
449     FT_Bytes  p = table;
450 
451 
452     GXV_NAME_ENTER( "just postcompTable" );
453 
454     gxv_just_pcLookupTable_validate( p, limit, gxvalid );
455     p += gxvalid->subtable_length;
456 
457     gxv_just_pcActionRecord_validate( p, limit, gxvalid );
458     p += gxvalid->subtable_length;
459 
460     gxvalid->subtable_length = (FT_ULong)( p - table );
461 
462     GXV_EXIT;
463   }
464 
465 
466   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)467   gxv_just_classTable_entry_validate(
468     FT_Byte                         state,
469     FT_UShort                       flags,
470     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
471     FT_Bytes                        table,
472     FT_Bytes                        limit,
473     GXV_Validator                   gxvalid )
474   {
475 #ifdef GXV_LOAD_UNUSED_VARS
476     /* TODO: validate markClass & currentClass */
477     FT_UShort  setMark;
478     FT_UShort  dontAdvance;
479     FT_UShort  markClass;
480     FT_UShort  currentClass;
481 #endif
482 
483     FT_UNUSED( state );
484     FT_UNUSED( glyphOffset_p );
485     FT_UNUSED( table );
486     FT_UNUSED( limit );
487     FT_UNUSED( gxvalid );
488 
489 #ifndef GXV_LOAD_UNUSED_VARS
490     FT_UNUSED( flags );
491 #else
492     setMark      = (FT_UShort)( ( flags >> 15 ) & 1    );
493     dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1    );
494     markClass    = (FT_UShort)( ( flags >> 7  ) & 0x7F );
495     currentClass = (FT_UShort)(   flags         & 0x7F );
496 #endif
497   }
498 
499 
500   static void
gxv_just_justClassTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)501   gxv_just_justClassTable_validate ( FT_Bytes       table,
502                                      FT_Bytes       limit,
503                                      GXV_Validator  gxvalid )
504   {
505     FT_Bytes   p = table;
506     FT_UShort  length;
507     FT_UShort  coverage;
508     FT_ULong   subFeatureFlags;
509 
510 
511     GXV_NAME_ENTER( "just justClassTable" );
512 
513     GXV_LIMIT_CHECK( 2 + 2 + 4 );
514     length          = FT_NEXT_USHORT( p );
515     coverage        = FT_NEXT_USHORT( p );
516     subFeatureFlags = FT_NEXT_ULONG( p );
517 
518     GXV_TRACE(( "  justClassTable: coverage = 0x%04x ", coverage ));
519     if ( ( coverage & 0x4000 ) == 0  )
520       GXV_TRACE(( "ascending\n" ));
521     else
522       GXV_TRACE(( "descending\n" ));
523 
524     if ( subFeatureFlags )
525       GXV_TRACE(( "  justClassTable: nonzero value (0x%08lx)"
526                   " in unused subFeatureFlags\n", subFeatureFlags ));
527 
528     gxvalid->statetable.optdata               = NULL;
529     gxvalid->statetable.optdata_load_func     = NULL;
530     gxvalid->statetable.subtable_setup_func   = NULL;
531     gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
532     gxvalid->statetable.entry_validate_func   =
533       gxv_just_classTable_entry_validate;
534 
535     gxv_StateTable_validate( p, table + length, gxvalid );
536 
537     /* subtable_length is set by gxv_LookupTable_validate() */
538 
539     GXV_EXIT;
540   }
541 
542 
543   static void
gxv_just_wdcTable_LookupValue_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)544   gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
545                                           GXV_LookupValueCPtr  value_p,
546                                           GXV_Validator        gxvalid )
547   {
548     FT_UNUSED( glyph );
549 
550     if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) )
551       GXV_JUST_DATA( wdc_offset_max ) = value_p->u;
552     if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) )
553       GXV_JUST_DATA( wdc_offset_min ) = value_p->u;
554   }
555 
556 
557   static void
gxv_just_justData_lookuptable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)558   gxv_just_justData_lookuptable_validate( FT_Bytes       table,
559                                           FT_Bytes       limit,
560                                           GXV_Validator  gxvalid )
561   {
562     FT_Bytes  p = table;
563 
564 
565     GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
566     GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU;
567 
568     gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
569     gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
570 
571     gxv_LookupTable_validate( p, limit, gxvalid );
572 
573     /* subtable_length is set by gxv_LookupTable_validate() */
574 
575     GXV_EXIT;
576   }
577 
578 
579   /*
580    * gxv_just_justData_validate() parses and validates horizData, vertData.
581    */
582   static void
gxv_just_justData_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)583   gxv_just_justData_validate( FT_Bytes       table,
584                               FT_Bytes       limit,
585                               GXV_Validator  gxvalid )
586   {
587     /*
588      * following 3 offsets are measured from the start of `just'
589      * (which table points to), not justData
590      */
591     FT_UShort  justClassTableOffset;
592     FT_UShort  wdcTableOffset;
593     FT_UShort  pcTableOffset;
594     FT_Bytes   p = table;
595 
596     GXV_ODTECT( 4, odtect );
597 
598 
599     GXV_NAME_ENTER( "just justData" );
600 
601     GXV_ODTECT_INIT( odtect );
602     GXV_LIMIT_CHECK( 2 + 2 + 2 );
603     justClassTableOffset = FT_NEXT_USHORT( p );
604     wdcTableOffset       = FT_NEXT_USHORT( p );
605     pcTableOffset        = FT_NEXT_USHORT( p );
606 
607     GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
608     GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
609     GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
610 
611     gxv_just_justData_lookuptable_validate( p, limit, gxvalid );
612     gxv_odtect_add_range( p, gxvalid->subtable_length,
613                           "just_LookupTable", odtect );
614 
615     if ( wdcTableOffset )
616     {
617       gxv_just_widthDeltaClusters_validate(
618         gxvalid->root->base + wdcTableOffset, limit, gxvalid );
619       gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset,
620                             gxvalid->subtable_length, "just_wdcTable", odtect );
621     }
622 
623     if ( pcTableOffset )
624     {
625       gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset,
626                                        limit, gxvalid );
627       gxv_odtect_add_range( gxvalid->root->base + pcTableOffset,
628                             gxvalid->subtable_length, "just_pcTable", odtect );
629     }
630 
631     if ( justClassTableOffset )
632     {
633       gxv_just_justClassTable_validate(
634         gxvalid->root->base + justClassTableOffset, limit, gxvalid );
635       gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset,
636                             gxvalid->subtable_length, "just_justClassTable",
637                             odtect );
638     }
639 
640     gxv_odtect_validate( odtect, gxvalid );
641 
642     GXV_EXIT;
643   }
644 
645 
646   FT_LOCAL_DEF( void )
gxv_just_validate(FT_Bytes table,FT_Face face,FT_Validator ftvalid)647   gxv_just_validate( FT_Bytes      table,
648                      FT_Face       face,
649                      FT_Validator  ftvalid )
650   {
651     FT_Bytes           p     = table;
652     FT_Bytes           limit = 0;
653 
654     GXV_ValidatorRec   gxvalidrec;
655     GXV_Validator      gxvalid = &gxvalidrec;
656     GXV_just_DataRec   justrec;
657     GXV_just_Data      just = &justrec;
658 
659     FT_ULong           version;
660     FT_UShort          format;
661     FT_UShort          horizOffset;
662     FT_UShort          vertOffset;
663 
664     GXV_ODTECT( 3, odtect );
665 
666 
667     GXV_ODTECT_INIT( odtect );
668 
669     gxvalid->root       = ftvalid;
670     gxvalid->table_data = just;
671     gxvalid->face       = face;
672 
673     FT_TRACE3(( "validating `just' table\n" ));
674     GXV_INIT;
675 
676     limit      = gxvalid->root->limit;
677 
678     GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
679     version     = FT_NEXT_ULONG( p );
680     format      = FT_NEXT_USHORT( p );
681     horizOffset = FT_NEXT_USHORT( p );
682     vertOffset  = FT_NEXT_USHORT( p );
683     gxv_odtect_add_range( table, (FT_ULong)( p - table ),
684                           "just header", odtect );
685 
686 
687     /* Version 1.0 (always:2000) */
688     GXV_TRACE(( " (version = 0x%08lx)\n", version ));
689     if ( version != 0x00010000UL )
690       FT_INVALID_FORMAT;
691 
692     /* format 0 (always:2000) */
693     GXV_TRACE(( " (format = 0x%04x)\n", format ));
694     if ( format != 0x0000 )
695         FT_INVALID_FORMAT;
696 
697     GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
698     GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
699 
700 
701     /* validate justData */
702     if ( 0 < horizOffset )
703     {
704       gxv_just_justData_validate( table + horizOffset, limit, gxvalid );
705       gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length,
706                             "horizJustData", odtect );
707     }
708 
709     if ( 0 < vertOffset )
710     {
711       gxv_just_justData_validate( table + vertOffset, limit, gxvalid );
712       gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length,
713                             "vertJustData", odtect );
714     }
715 
716     gxv_odtect_validate( odtect, gxvalid );
717 
718     FT_TRACE4(( "\n" ));
719   }
720 
721 
722 /* END */
723