• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * gxvcommn.c
4  *
5  *   TrueTypeGX/AAT common tables validation (body).
6  *
7  * Copyright (C) 2004-2023 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 "gxvcommn.h"
29 
30 
31   /**************************************************************************
32    *
33    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
34    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
35    * messages during execution.
36    */
37 #undef  FT_COMPONENT
38 #define FT_COMPONENT  gxvcommon
39 
40 
41   /*************************************************************************/
42   /*************************************************************************/
43   /*****                                                               *****/
44   /*****                       16bit offset sorter                     *****/
45   /*****                                                               *****/
46   /*************************************************************************/
47   /*************************************************************************/
48 
49   FT_COMPARE_DEF( int )
gxv_compare_ushort_offset(const void * a,const void * b)50   gxv_compare_ushort_offset( const void*  a,
51                              const void*  b )
52   {
53     return  *(FT_UShort*)a - *(FT_UShort*)b;
54   }
55 
56 
57   FT_LOCAL_DEF( void )
gxv_set_length_by_ushort_offset(FT_UShort * offset,FT_UShort ** length,FT_UShort * buff,FT_UInt nmemb,FT_UShort limit,GXV_Validator gxvalid)58   gxv_set_length_by_ushort_offset( FT_UShort*     offset,
59                                    FT_UShort**    length,
60                                    FT_UShort*     buff,
61                                    FT_UInt        nmemb,
62                                    FT_UShort      limit,
63                                    GXV_Validator  gxvalid )
64   {
65     FT_UInt  i;
66 
67 
68     for ( i = 0; i < nmemb; i++ )
69       *(length[i]) = 0;
70 
71     for ( i = 0; i < nmemb; i++ )
72       buff[i] = offset[i];
73     buff[nmemb] = limit;
74 
75     ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ),
76               gxv_compare_ushort_offset );
77 
78     if ( buff[nmemb] > limit )
79       FT_INVALID_OFFSET;
80 
81     for ( i = 0; i < nmemb; i++ )
82     {
83       FT_UInt  j;
84 
85 
86       for ( j = 0; j < nmemb; j++ )
87         if ( buff[j] == offset[i] )
88           break;
89 
90       if ( j == nmemb )
91         FT_INVALID_OFFSET;
92 
93       *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] );
94 
95       if ( 0 != offset[i] && 0 == *(length[i]) )
96         FT_INVALID_OFFSET;
97     }
98   }
99 
100 
101   /*************************************************************************/
102   /*************************************************************************/
103   /*****                                                               *****/
104   /*****                       32bit offset sorter                     *****/
105   /*****                                                               *****/
106   /*************************************************************************/
107   /*************************************************************************/
108 
109   FT_COMPARE_DEF( int )
gxv_compare_ulong_offset(const void * a,const void * b)110   gxv_compare_ulong_offset( const void*  a,
111                             const void*  b )
112   {
113     FT_ULong  a_ = *(FT_ULong*)a;
114     FT_ULong  b_ = *(FT_ULong*)b;
115 
116 
117     if ( a_ < b_ )
118       return -1;
119     else if ( a_ > b_ )
120       return 1;
121     else
122       return 0;
123   }
124 
125 
126   FT_LOCAL_DEF( void )
gxv_set_length_by_ulong_offset(FT_ULong * offset,FT_ULong ** length,FT_ULong * buff,FT_UInt nmemb,FT_ULong limit,GXV_Validator gxvalid)127   gxv_set_length_by_ulong_offset( FT_ULong*      offset,
128                                   FT_ULong**     length,
129                                   FT_ULong*      buff,
130                                   FT_UInt        nmemb,
131                                   FT_ULong       limit,
132                                   GXV_Validator  gxvalid)
133   {
134     FT_UInt  i;
135 
136 
137     for ( i = 0; i < nmemb; i++ )
138       *(length[i]) = 0;
139 
140     for ( i = 0; i < nmemb; i++ )
141       buff[i] = offset[i];
142     buff[nmemb] = limit;
143 
144     ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ),
145               gxv_compare_ulong_offset );
146 
147     if ( buff[nmemb] > limit )
148       FT_INVALID_OFFSET;
149 
150     for ( i = 0; i < nmemb; i++ )
151     {
152       FT_UInt  j;
153 
154 
155       for ( j = 0; j < nmemb; j++ )
156         if ( buff[j] == offset[i] )
157           break;
158 
159       if ( j == nmemb )
160         FT_INVALID_OFFSET;
161 
162       *(length[i]) = buff[j + 1] - buff[j];
163 
164       if ( 0 != offset[i] && 0 == *(length[i]) )
165         FT_INVALID_OFFSET;
166     }
167   }
168 
169 
170   /*************************************************************************/
171   /*************************************************************************/
172   /*****                                                               *****/
173   /*****               scan value array and get min & max              *****/
174   /*****                                                               *****/
175   /*************************************************************************/
176   /*************************************************************************/
177 
178 
179   FT_LOCAL_DEF( void )
gxv_array_getlimits_byte(FT_Bytes table,FT_Bytes limit,FT_Byte * min,FT_Byte * max,GXV_Validator gxvalid)180   gxv_array_getlimits_byte( FT_Bytes       table,
181                             FT_Bytes       limit,
182                             FT_Byte*       min,
183                             FT_Byte*       max,
184                             GXV_Validator  gxvalid )
185   {
186     FT_Bytes  p = table;
187 
188 
189     *min = 0xFF;
190     *max = 0x00;
191 
192     while ( p < limit )
193     {
194       FT_Byte  val;
195 
196 
197       GXV_LIMIT_CHECK( 1 );
198       val = FT_NEXT_BYTE( p );
199 
200       *min = (FT_Byte)FT_MIN( *min, val );
201       *max = (FT_Byte)FT_MAX( *max, val );
202     }
203 
204     gxvalid->subtable_length = (FT_ULong)( p - table );
205   }
206 
207 
208   FT_LOCAL_DEF( void )
gxv_array_getlimits_ushort(FT_Bytes table,FT_Bytes limit,FT_UShort * min,FT_UShort * max,GXV_Validator gxvalid)209   gxv_array_getlimits_ushort( FT_Bytes       table,
210                               FT_Bytes       limit,
211                               FT_UShort*     min,
212                               FT_UShort*     max,
213                               GXV_Validator  gxvalid )
214   {
215     FT_Bytes  p = table;
216 
217 
218     *min = 0xFFFFU;
219     *max = 0x0000;
220 
221     while ( p < limit )
222     {
223       FT_UShort  val;
224 
225 
226       GXV_LIMIT_CHECK( 2 );
227       val = FT_NEXT_USHORT( p );
228 
229       *min = (FT_Byte)FT_MIN( *min, val );
230       *max = (FT_Byte)FT_MAX( *max, val );
231     }
232 
233     gxvalid->subtable_length = (FT_ULong)( p - table );
234   }
235 
236 
237   /*************************************************************************/
238   /*************************************************************************/
239   /*****                                                               *****/
240   /*****                       BINSEARCHHEADER                         *****/
241   /*****                                                               *****/
242   /*************************************************************************/
243   /*************************************************************************/
244 
245   typedef struct  GXV_BinSrchHeader_
246   {
247     FT_UShort  unitSize;
248     FT_UShort  nUnits;
249     FT_UShort  searchRange;
250     FT_UShort  entrySelector;
251     FT_UShort  rangeShift;
252 
253   } GXV_BinSrchHeader;
254 
255 
256   static void
gxv_BinSrchHeader_check_consistency(GXV_BinSrchHeader * binSrchHeader,GXV_Validator gxvalid)257   gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader*  binSrchHeader,
258                                        GXV_Validator       gxvalid )
259   {
260     FT_UShort  searchRange;
261     FT_UShort  entrySelector;
262     FT_UShort  rangeShift;
263 
264 
265     if ( binSrchHeader->unitSize == 0 )
266       FT_INVALID_DATA;
267 
268     if ( binSrchHeader->nUnits == 0 )
269     {
270       if ( binSrchHeader->searchRange   == 0 &&
271            binSrchHeader->entrySelector == 0 &&
272            binSrchHeader->rangeShift    == 0 )
273         return;
274       else
275         FT_INVALID_DATA;
276     }
277 
278     for ( searchRange = 1, entrySelector = 1;
279           ( searchRange * 2 ) <= binSrchHeader->nUnits &&
280             searchRange < 0x8000U;
281           searchRange *= 2, entrySelector++ )
282       ;
283 
284     entrySelector--;
285     searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize );
286     rangeShift  = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize
287                                - searchRange );
288 
289     if ( searchRange   != binSrchHeader->searchRange   ||
290          entrySelector != binSrchHeader->entrySelector ||
291          rangeShift    != binSrchHeader->rangeShift    )
292     {
293       GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" ));
294       GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, "
295                   "searchRange=%d, entrySelector=%d, "
296                   "rangeShift=%d\n",
297                   binSrchHeader->unitSize, binSrchHeader->nUnits,
298                   binSrchHeader->searchRange, binSrchHeader->entrySelector,
299                   binSrchHeader->rangeShift ));
300       GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, "
301                   "searchRange=%d, entrySelector=%d, "
302                   "rangeShift=%d\n",
303                   binSrchHeader->unitSize, binSrchHeader->nUnits,
304                   searchRange, entrySelector, rangeShift ));
305 
306       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
307     }
308   }
309 
310 
311   /*
312    * parser & validator of BinSrchHeader
313    * which is used in LookupTable format 2, 4, 6.
314    *
315    * Essential parameters (unitSize, nUnits) are returned by
316    * given pointer, others (searchRange, entrySelector, rangeShift)
317    * can be calculated by essential parameters, so they are just
318    * validated and discarded.
319    *
320    * However, wrong values in searchRange, entrySelector, rangeShift
321    * won't cause fatal errors, because these parameters might be
322    * only used in old m68k font driver in MacOS.
323    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
324    */
325 
326   FT_LOCAL_DEF( void )
gxv_BinSrchHeader_validate(FT_Bytes table,FT_Bytes limit,FT_UShort * unitSize_p,FT_UShort * nUnits_p,GXV_Validator gxvalid)327   gxv_BinSrchHeader_validate( FT_Bytes       table,
328                               FT_Bytes       limit,
329                               FT_UShort*     unitSize_p,
330                               FT_UShort*     nUnits_p,
331                               GXV_Validator  gxvalid )
332   {
333     FT_Bytes           p = table;
334     GXV_BinSrchHeader  binSrchHeader;
335 
336 
337     GXV_NAME_ENTER( "BinSrchHeader validate" );
338 
339     if ( *unitSize_p == 0 )
340     {
341       GXV_LIMIT_CHECK( 2 );
342       binSrchHeader.unitSize =  FT_NEXT_USHORT( p );
343     }
344     else
345       binSrchHeader.unitSize = *unitSize_p;
346 
347     if ( *nUnits_p == 0 )
348     {
349       GXV_LIMIT_CHECK( 2 );
350       binSrchHeader.nUnits = FT_NEXT_USHORT( p );
351     }
352     else
353       binSrchHeader.nUnits = *nUnits_p;
354 
355     GXV_LIMIT_CHECK( 2 + 2 + 2 );
356     binSrchHeader.searchRange   = FT_NEXT_USHORT( p );
357     binSrchHeader.entrySelector = FT_NEXT_USHORT( p );
358     binSrchHeader.rangeShift    = FT_NEXT_USHORT( p );
359     GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits ));
360 
361     gxv_BinSrchHeader_check_consistency( &binSrchHeader, gxvalid );
362 
363     if ( *unitSize_p == 0 )
364       *unitSize_p = binSrchHeader.unitSize;
365 
366     if ( *nUnits_p == 0 )
367       *nUnits_p = binSrchHeader.nUnits;
368 
369     gxvalid->subtable_length = (FT_ULong)( p - table );
370     GXV_EXIT;
371   }
372 
373 
374   /*************************************************************************/
375   /*************************************************************************/
376   /*****                                                               *****/
377   /*****                         LOOKUP TABLE                          *****/
378   /*****                                                               *****/
379   /*************************************************************************/
380   /*************************************************************************/
381 
382 #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC )                   \
383           ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) )
384 
385   static GXV_LookupValueDesc
gxv_lookup_value_load(FT_Bytes p,GXV_LookupValue_SignSpec signspec)386   gxv_lookup_value_load( FT_Bytes                  p,
387                          GXV_LookupValue_SignSpec  signspec )
388   {
389     GXV_LookupValueDesc  v;
390 
391 
392     if ( signspec == GXV_LOOKUPVALUE_UNSIGNED )
393       v.u = FT_NEXT_USHORT( p );
394     else
395       v.s = FT_NEXT_SHORT( p );
396 
397     return v;
398   }
399 
400 
401 #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \
402           FT_BEGIN_STMNT                                               \
403             if ( UNITSIZE != CORRECTSIZE )                             \
404             {                                                          \
405               FT_ERROR(( "unitSize=%d differs from"                    \
406                          " expected unitSize=%d"                       \
407                          " in LookupTable %s\n",                       \
408                           UNITSIZE, CORRECTSIZE, FORMAT ));            \
409               if ( UNITSIZE != 0 && NUNITS != 0 )                      \
410               {                                                        \
411                 FT_ERROR(( " cannot validate anymore\n" ));            \
412                 FT_INVALID_FORMAT;                                     \
413               }                                                        \
414               else                                                     \
415                 FT_ERROR(( " forcibly continues\n" ));                 \
416             }                                                          \
417           FT_END_STMNT
418 
419 
420   /* ================= Simple Array Format 0 Lookup Table ================ */
421   static void
gxv_LookupTable_fmt0_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)422   gxv_LookupTable_fmt0_validate( FT_Bytes       table,
423                                  FT_Bytes       limit,
424                                  GXV_Validator  gxvalid )
425   {
426     FT_Bytes   p = table;
427     FT_UShort  i;
428 
429     GXV_LookupValueDesc  value;
430 
431 
432     GXV_NAME_ENTER( "LookupTable format 0" );
433 
434     GXV_LIMIT_CHECK( 2 * gxvalid->face->num_glyphs );
435 
436     for ( i = 0; i < gxvalid->face->num_glyphs; i++ )
437     {
438       GXV_LIMIT_CHECK( 2 );
439       if ( p + 2 >= limit )     /* some fonts have too-short fmt0 array */
440       {
441         GXV_TRACE(( "too short, glyphs %d - %ld are missing\n",
442                     i, gxvalid->face->num_glyphs ));
443         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
444         break;
445       }
446 
447       value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
448       gxvalid->lookupval_func( i, &value, gxvalid );
449     }
450 
451     gxvalid->subtable_length = (FT_ULong)( p - table );
452     GXV_EXIT;
453   }
454 
455 
456   /* ================= Segment Single Format 2 Lookup Table ============== */
457   /*
458    * Apple spec says:
459    *
460    *   To guarantee that a binary search terminates, you must include one or
461    *   more special `end of search table' values at the end of the data to
462    *   be searched.  The number of termination values that need to be
463    *   included is table-specific.  The value that indicates binary search
464    *   termination is 0xFFFF.
465    *
466    * The problem is that nUnits does not include this end-marker.  It's
467    * quite difficult to discriminate whether the following 0xFFFF comes from
468    * the end-marker or some next data.
469    *
470    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
471    */
472   static void
gxv_LookupTable_fmt2_skip_endmarkers(FT_Bytes table,FT_UShort unitSize,GXV_Validator gxvalid)473   gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes       table,
474                                         FT_UShort      unitSize,
475                                         GXV_Validator  gxvalid )
476   {
477     FT_Bytes  p = table;
478 
479 
480     while ( ( p + 4 ) < gxvalid->root->limit )
481     {
482       if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */
483            p[2] != 0xFF || p[3] != 0xFF )  /* firstGlyph */
484         break;
485       p += unitSize;
486     }
487 
488     gxvalid->subtable_length = (FT_ULong)( p - table );
489   }
490 
491 
492   static void
gxv_LookupTable_fmt2_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)493   gxv_LookupTable_fmt2_validate( FT_Bytes       table,
494                                  FT_Bytes       limit,
495                                  GXV_Validator  gxvalid )
496   {
497     FT_Bytes             p = table;
498     FT_UShort            gid;
499 
500     FT_UShort            unitSize;
501     FT_UShort            nUnits;
502     FT_UShort            unit;
503     FT_UShort            lastGlyph;
504     FT_UShort            firstGlyph;
505     GXV_LookupValueDesc  value;
506 
507 
508     GXV_NAME_ENTER( "LookupTable format 2" );
509 
510     unitSize = nUnits = 0;
511     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
512     p += gxvalid->subtable_length;
513 
514     GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 );
515 
516     for ( unit = 0, gid = 0; unit < nUnits; unit++ )
517     {
518       GXV_LIMIT_CHECK( 2 + 2 + 2 );
519       lastGlyph  = FT_NEXT_USHORT( p );
520       firstGlyph = FT_NEXT_USHORT( p );
521       value      = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
522 
523       gxv_glyphid_validate( firstGlyph, gxvalid );
524       gxv_glyphid_validate( lastGlyph, gxvalid );
525 
526       if ( lastGlyph < gid )
527       {
528         GXV_TRACE(( "reverse ordered segment specification:"
529                     " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
530                     unit, lastGlyph, unit - 1 , gid ));
531         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
532       }
533 
534       if ( lastGlyph < firstGlyph )
535       {
536         GXV_TRACE(( "reverse ordered range specification at unit %d:"
537                     " lastGlyph %d < firstGlyph %d ",
538                     unit, lastGlyph, firstGlyph ));
539         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
540 
541         if ( gxvalid->root->level == FT_VALIDATE_TIGHT )
542           continue;     /* ftxvalidator silently skips such an entry */
543 
544         FT_TRACE4(( "continuing with exchanged values\n" ));
545         gid        = firstGlyph;
546         firstGlyph = lastGlyph;
547         lastGlyph  = gid;
548       }
549 
550       for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
551         gxvalid->lookupval_func( gid, &value, gxvalid );
552     }
553 
554     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid );
555     p += gxvalid->subtable_length;
556 
557     gxvalid->subtable_length = (FT_ULong)( p - table );
558     GXV_EXIT;
559   }
560 
561 
562   /* ================= Segment Array Format 4 Lookup Table =============== */
563   static void
gxv_LookupTable_fmt4_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)564   gxv_LookupTable_fmt4_validate( FT_Bytes       table,
565                                  FT_Bytes       limit,
566                                  GXV_Validator  gxvalid )
567   {
568     FT_Bytes             p = table;
569     FT_UShort            unit;
570     FT_UShort            gid;
571 
572     FT_UShort            unitSize;
573     FT_UShort            nUnits;
574     FT_UShort            lastGlyph;
575     FT_UShort            firstGlyph;
576     GXV_LookupValueDesc  base_value;
577     GXV_LookupValueDesc  value;
578 
579 
580     GXV_NAME_ENTER( "LookupTable format 4" );
581 
582     unitSize = nUnits = 0;
583     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
584     p += gxvalid->subtable_length;
585 
586     GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 );
587 
588     for ( unit = 0, gid = 0; unit < nUnits; unit++ )
589     {
590       GXV_LIMIT_CHECK( 2 + 2 );
591       lastGlyph  = FT_NEXT_USHORT( p );
592       firstGlyph = FT_NEXT_USHORT( p );
593 
594       gxv_glyphid_validate( firstGlyph, gxvalid );
595       gxv_glyphid_validate( lastGlyph, gxvalid );
596 
597       if ( lastGlyph < gid )
598       {
599         GXV_TRACE(( "reverse ordered segment specification:"
600                     " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
601                     unit, lastGlyph, unit - 1 , gid ));
602         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
603       }
604 
605       if ( lastGlyph < firstGlyph )
606       {
607         GXV_TRACE(( "reverse ordered range specification at unit %d:"
608                     " lastGlyph %d < firstGlyph %d ",
609                     unit, lastGlyph, firstGlyph ));
610         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
611 
612         if ( gxvalid->root->level == FT_VALIDATE_TIGHT )
613           continue; /* ftxvalidator silently skips such an entry */
614 
615         FT_TRACE4(( "continuing with exchanged values\n" ));
616         gid        = firstGlyph;
617         firstGlyph = lastGlyph;
618         lastGlyph  = gid;
619       }
620 
621       GXV_LIMIT_CHECK( 2 );
622       base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED );
623 
624       for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
625       {
626         value = gxvalid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ),
627                                          &base_value,
628                                          limit,
629                                          gxvalid );
630 
631         gxvalid->lookupval_func( gid, &value, gxvalid );
632       }
633     }
634 
635     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid );
636     p += gxvalid->subtable_length;
637 
638     gxvalid->subtable_length = (FT_ULong)( p - table );
639     GXV_EXIT;
640   }
641 
642 
643   /* ================= Segment Table Format 6 Lookup Table =============== */
644   static void
gxv_LookupTable_fmt6_skip_endmarkers(FT_Bytes table,FT_UShort unitSize,GXV_Validator gxvalid)645   gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes       table,
646                                         FT_UShort      unitSize,
647                                         GXV_Validator  gxvalid )
648   {
649     FT_Bytes  p = table;
650 
651 
652     while ( p < gxvalid->root->limit )
653     {
654       if ( p[0] != 0xFF || p[1] != 0xFF )
655         break;
656       p += unitSize;
657     }
658 
659     gxvalid->subtable_length = (FT_ULong)( p - table );
660   }
661 
662 
663   static void
gxv_LookupTable_fmt6_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)664   gxv_LookupTable_fmt6_validate( FT_Bytes       table,
665                                  FT_Bytes       limit,
666                                  GXV_Validator  gxvalid )
667   {
668     FT_Bytes             p = table;
669     FT_UShort            unit;
670     FT_UShort            prev_glyph;
671 
672     FT_UShort            unitSize;
673     FT_UShort            nUnits;
674     FT_UShort            glyph;
675     GXV_LookupValueDesc  value;
676 
677 
678     GXV_NAME_ENTER( "LookupTable format 6" );
679 
680     unitSize = nUnits = 0;
681     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid );
682     p += gxvalid->subtable_length;
683 
684     GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 );
685 
686     for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ )
687     {
688       GXV_LIMIT_CHECK( 2 + 2 );
689       glyph = FT_NEXT_USHORT( p );
690       value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
691 
692       if ( gxv_glyphid_validate( glyph, gxvalid ) )
693         GXV_TRACE(( " endmarker found within defined range"
694                     " (entry %d < nUnits=%d)\n",
695                     unit, nUnits ));
696 
697       if ( prev_glyph > glyph )
698       {
699         GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n",
700                     glyph, prev_glyph ));
701         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
702       }
703       prev_glyph = glyph;
704 
705       gxvalid->lookupval_func( glyph, &value, gxvalid );
706     }
707 
708     gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, gxvalid );
709     p += gxvalid->subtable_length;
710 
711     gxvalid->subtable_length = (FT_ULong)( p - table );
712     GXV_EXIT;
713   }
714 
715 
716   /* ================= Trimmed Array Format 8 Lookup Table =============== */
717   static void
gxv_LookupTable_fmt8_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)718   gxv_LookupTable_fmt8_validate( FT_Bytes       table,
719                                  FT_Bytes       limit,
720                                  GXV_Validator  gxvalid )
721   {
722     FT_Bytes              p = table;
723     FT_UShort             i;
724 
725     GXV_LookupValueDesc   value;
726     FT_UShort             firstGlyph;
727     FT_UShort             glyphCount;
728 
729 
730     GXV_NAME_ENTER( "LookupTable format 8" );
731 
732     /* firstGlyph + glyphCount */
733     GXV_LIMIT_CHECK( 2 + 2 );
734     firstGlyph = FT_NEXT_USHORT( p );
735     glyphCount = FT_NEXT_USHORT( p );
736 
737     gxv_glyphid_validate( firstGlyph, gxvalid );
738     gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), gxvalid );
739 
740     /* valueArray */
741     for ( i = 0; i < glyphCount; i++ )
742     {
743       GXV_LIMIT_CHECK( 2 );
744       value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign );
745       gxvalid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, gxvalid );
746     }
747 
748     gxvalid->subtable_length = (FT_ULong)( p - table );
749     GXV_EXIT;
750   }
751 
752 
753   FT_LOCAL_DEF( void )
gxv_LookupTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)754   gxv_LookupTable_validate( FT_Bytes       table,
755                             FT_Bytes       limit,
756                             GXV_Validator  gxvalid )
757   {
758     FT_Bytes   p = table;
759     FT_UShort  format;
760 
761     GXV_Validate_Func  fmt_funcs_table[] =
762     {
763       gxv_LookupTable_fmt0_validate, /* 0 */
764       NULL,                          /* 1 */
765       gxv_LookupTable_fmt2_validate, /* 2 */
766       NULL,                          /* 3 */
767       gxv_LookupTable_fmt4_validate, /* 4 */
768       NULL,                          /* 5 */
769       gxv_LookupTable_fmt6_validate, /* 6 */
770       NULL,                          /* 7 */
771       gxv_LookupTable_fmt8_validate, /* 8 */
772     };
773 
774     GXV_Validate_Func  func;
775 
776 
777     GXV_NAME_ENTER( "LookupTable" );
778 
779     /* lookuptbl_head may be used in fmt4 transit function. */
780     gxvalid->lookuptbl_head = table;
781 
782     /* format */
783     GXV_LIMIT_CHECK( 2 );
784     format = FT_NEXT_USHORT( p );
785     GXV_TRACE(( " (format %d)\n", format ));
786 
787     if ( format > 8 )
788       FT_INVALID_FORMAT;
789 
790     func = fmt_funcs_table[format];
791     if ( !func )
792       FT_INVALID_FORMAT;
793 
794     func( p, limit, gxvalid );
795     p += gxvalid->subtable_length;
796 
797     gxvalid->subtable_length = (FT_ULong)( p - table );
798 
799     GXV_EXIT;
800   }
801 
802 
803   /*************************************************************************/
804   /*************************************************************************/
805   /*****                                                               *****/
806   /*****                          Glyph ID                             *****/
807   /*****                                                               *****/
808   /*************************************************************************/
809   /*************************************************************************/
810 
811   FT_LOCAL_DEF( FT_Int )
gxv_glyphid_validate(FT_UShort gid,GXV_Validator gxvalid)812   gxv_glyphid_validate( FT_UShort      gid,
813                         GXV_Validator  gxvalid )
814   {
815     FT_Face  face;
816 
817 
818     if ( gid == 0xFFFFU )
819     {
820       GXV_EXIT;
821       return 1;
822     }
823 
824     face = gxvalid->face;
825     if ( face->num_glyphs < gid )
826     {
827       GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %ld < %d\n",
828                   face->num_glyphs, gid ));
829       GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
830     }
831 
832     return 0;
833   }
834 
835 
836   /*************************************************************************/
837   /*************************************************************************/
838   /*****                                                               *****/
839   /*****                        CONTROL POINT                          *****/
840   /*****                                                               *****/
841   /*************************************************************************/
842   /*************************************************************************/
843 
844   FT_LOCAL_DEF( void )
gxv_ctlPoint_validate(FT_UShort gid,FT_UShort ctl_point,GXV_Validator gxvalid)845   gxv_ctlPoint_validate( FT_UShort      gid,
846                          FT_UShort      ctl_point,
847                          GXV_Validator  gxvalid )
848   {
849     FT_Face       face;
850     FT_Error      error;
851 
852     FT_GlyphSlot  glyph;
853     FT_Outline    outline;
854     FT_UShort     n_points;
855 
856 
857     face = gxvalid->face;
858 
859     error = FT_Load_Glyph( face,
860                            gid,
861                            FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM );
862     if ( error )
863       FT_INVALID_GLYPH_ID;
864 
865     glyph    = face->glyph;
866     outline  = glyph->outline;
867     n_points = (FT_UShort)outline.n_points;
868 
869     if ( !( ctl_point < n_points ) )
870       FT_INVALID_DATA;
871   }
872 
873 
874   /*************************************************************************/
875   /*************************************************************************/
876   /*****                                                               *****/
877   /*****                          SFNT NAME                            *****/
878   /*****                                                               *****/
879   /*************************************************************************/
880   /*************************************************************************/
881 
882   FT_LOCAL_DEF( void )
gxv_sfntName_validate(FT_UShort name_index,FT_UShort min_index,FT_UShort max_index,GXV_Validator gxvalid)883   gxv_sfntName_validate( FT_UShort      name_index,
884                          FT_UShort      min_index,
885                          FT_UShort      max_index,
886                          GXV_Validator  gxvalid )
887   {
888     FT_SfntName  name;
889     FT_UInt      i;
890     FT_UInt      nnames;
891 
892 
893     GXV_NAME_ENTER( "sfntName" );
894 
895     if ( name_index < min_index || max_index < name_index )
896       FT_INVALID_FORMAT;
897 
898     nnames = FT_Get_Sfnt_Name_Count( gxvalid->face );
899     for ( i = 0; i < nnames; i++ )
900     {
901       if ( FT_Get_Sfnt_Name( gxvalid->face, i, &name ) != FT_Err_Ok )
902         continue;
903 
904       if ( name.name_id == name_index )
905         goto Out;
906     }
907 
908     GXV_TRACE(( "  nameIndex = %d (UNTITLED)\n", name_index ));
909     FT_INVALID_DATA;
910     goto Exit;  /* make compiler happy */
911 
912   Out:
913     FT_TRACE1(( "  nameIndex = %d (", name_index ));
914     GXV_TRACE_HEXDUMP_SFNTNAME( name );
915     FT_TRACE1(( ")\n" ));
916 
917   Exit:
918     GXV_EXIT;
919   }
920 
921 
922   /*************************************************************************/
923   /*************************************************************************/
924   /*****                                                               *****/
925   /*****                          STATE TABLE                          *****/
926   /*****                                                               *****/
927   /*************************************************************************/
928   /*************************************************************************/
929 
930   /* -------------------------- Class Table --------------------------- */
931 
932   /*
933    * highestClass specifies how many classes are defined in this
934    * Class Subtable.  Apple spec does not mention whether undefined
935    * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used)
936    * are permitted.  At present, holes in a defined class are not checked.
937    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
938    */
939 
940   static void
gxv_ClassTable_validate(FT_Bytes table,FT_UShort * length_p,FT_UShort stateSize,FT_Byte * maxClassID_p,GXV_Validator gxvalid)941   gxv_ClassTable_validate( FT_Bytes       table,
942                            FT_UShort*     length_p,
943                            FT_UShort      stateSize,
944                            FT_Byte*       maxClassID_p,
945                            GXV_Validator  gxvalid )
946   {
947     FT_Bytes   p     = table;
948     FT_Bytes   limit = table + *length_p;
949     FT_UShort  firstGlyph;
950     FT_UShort  nGlyphs;
951 
952 
953     GXV_NAME_ENTER( "ClassTable" );
954 
955     *maxClassID_p = 3;  /* Classes 0, 2, and 3 are predefined */
956 
957     GXV_LIMIT_CHECK( 2 + 2 );
958     firstGlyph = FT_NEXT_USHORT( p );
959     nGlyphs    = FT_NEXT_USHORT( p );
960 
961     GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
962 
963     if ( !nGlyphs )
964       goto Out;
965 
966     gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), gxvalid );
967 
968     {
969       FT_Byte    nGlyphInClass[256];
970       FT_Byte    classID;
971       FT_UShort  i;
972 
973 
974       FT_MEM_ZERO( nGlyphInClass, 256 );
975 
976 
977       for ( i = 0; i < nGlyphs; i++ )
978       {
979         GXV_LIMIT_CHECK( 1 );
980         classID = FT_NEXT_BYTE( p );
981         switch ( classID )
982         {
983           /* following classes should not appear in class array */
984         case 0:             /* end of text */
985         case 2:             /* out of bounds */
986         case 3:             /* end of line */
987           FT_INVALID_DATA;
988           break;
989 
990         case 1:             /* out of bounds */
991         default:            /* user-defined: 4 - ( stateSize - 1 ) */
992           if ( classID >= stateSize )
993             FT_INVALID_DATA;   /* assign glyph to undefined state */
994 
995           nGlyphInClass[classID]++;
996           break;
997         }
998       }
999       *length_p = (FT_UShort)( p - table );
1000 
1001       /* scan max ClassID in use */
1002       for ( i = 0; i < stateSize; i++ )
1003         if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) )
1004           *maxClassID_p = (FT_Byte)i;  /* XXX: Check Range? */
1005     }
1006 
1007   Out:
1008     GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
1009                 stateSize, *maxClassID_p ));
1010     GXV_EXIT;
1011   }
1012 
1013 
1014   /* --------------------------- State Array ----------------------------- */
1015 
1016   static void
gxv_StateArray_validate(FT_Bytes table,FT_UShort * length_p,FT_Byte maxClassID,FT_UShort stateSize,FT_Byte * maxState_p,FT_Byte * maxEntry_p,GXV_Validator gxvalid)1017   gxv_StateArray_validate( FT_Bytes       table,
1018                            FT_UShort*     length_p,
1019                            FT_Byte        maxClassID,
1020                            FT_UShort      stateSize,
1021                            FT_Byte*       maxState_p,
1022                            FT_Byte*       maxEntry_p,
1023                            GXV_Validator  gxvalid )
1024   {
1025     FT_Bytes  p     = table;
1026     FT_Bytes  limit = table + *length_p;
1027     FT_Byte   clazz;
1028     FT_Byte   entry;
1029 
1030     FT_UNUSED( stateSize ); /* for the non-debugging case */
1031 
1032 
1033     GXV_NAME_ENTER( "StateArray" );
1034 
1035     GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
1036                 (int)( *length_p ), stateSize, (int)maxClassID ));
1037 
1038     /*
1039      * 2 states are predefined and must be described in StateArray:
1040      * state 0 (start of text), 1 (start of line)
1041      */
1042     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
1043 
1044     *maxState_p = 0;
1045     *maxEntry_p = 0;
1046 
1047     /* read if enough to read another state */
1048     while ( p + ( 1 + maxClassID ) <= limit )
1049     {
1050       (*maxState_p)++;
1051       for ( clazz = 0; clazz <= maxClassID; clazz++ )
1052       {
1053         entry = FT_NEXT_BYTE( p );
1054         *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
1055       }
1056     }
1057     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1058                 *maxState_p, *maxEntry_p ));
1059 
1060     *length_p = (FT_UShort)( p - table );
1061 
1062     GXV_EXIT;
1063   }
1064 
1065 
1066   /* --------------------------- Entry Table ----------------------------- */
1067 
1068   static void
gxv_EntryTable_validate(FT_Bytes table,FT_UShort * length_p,FT_Byte maxEntry,FT_UShort stateArray,FT_UShort stateArray_length,FT_Byte maxClassID,FT_Bytes statetable_table,FT_Bytes statetable_limit,GXV_Validator gxvalid)1069   gxv_EntryTable_validate( FT_Bytes       table,
1070                            FT_UShort*     length_p,
1071                            FT_Byte        maxEntry,
1072                            FT_UShort      stateArray,
1073                            FT_UShort      stateArray_length,
1074                            FT_Byte        maxClassID,
1075                            FT_Bytes       statetable_table,
1076                            FT_Bytes       statetable_limit,
1077                            GXV_Validator  gxvalid )
1078   {
1079     FT_Bytes  p     = table;
1080     FT_Bytes  limit = table + *length_p;
1081     FT_Byte   entry;
1082     FT_Byte   state;
1083     FT_Int    entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
1084 
1085     GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
1086 
1087 
1088     GXV_NAME_ENTER( "EntryTable" );
1089 
1090     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1091 
1092     if ( ( maxEntry + 1 ) * entrySize > *length_p )
1093     {
1094       GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT );
1095 
1096       /* ftxvalidator and FontValidator both warn and continue */
1097       maxEntry = (FT_Byte)( *length_p / entrySize - 1 );
1098       GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n",
1099                   maxEntry ));
1100     }
1101 
1102     for ( entry = 0; entry <= maxEntry; entry++ )
1103     {
1104       FT_UShort  newState;
1105       FT_UShort  flags;
1106 
1107 
1108       GXV_LIMIT_CHECK( 2 + 2 );
1109       newState = FT_NEXT_USHORT( p );
1110       flags    = FT_NEXT_USHORT( p );
1111 
1112 
1113       if ( newState < stateArray                     ||
1114            stateArray + stateArray_length < newState )
1115       {
1116         GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
1117                     newState ));
1118         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1119         continue;
1120       }
1121 
1122       if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
1123       {
1124         GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
1125                     newState,  1 + maxClassID ));
1126         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1127         continue;
1128       }
1129 
1130       state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
1131 
1132       switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
1133       {
1134       case GXV_GLYPHOFFSET_NONE:
1135         glyphOffset.uc = 0;  /* make compiler happy */
1136         break;
1137 
1138       case GXV_GLYPHOFFSET_UCHAR:
1139         glyphOffset.uc = FT_NEXT_BYTE( p );
1140         break;
1141 
1142       case GXV_GLYPHOFFSET_CHAR:
1143         glyphOffset.c = FT_NEXT_CHAR( p );
1144         break;
1145 
1146       case GXV_GLYPHOFFSET_USHORT:
1147         glyphOffset.u = FT_NEXT_USHORT( p );
1148         break;
1149 
1150       case GXV_GLYPHOFFSET_SHORT:
1151         glyphOffset.s = FT_NEXT_SHORT( p );
1152         break;
1153 
1154       case GXV_GLYPHOFFSET_ULONG:
1155         glyphOffset.ul = FT_NEXT_ULONG( p );
1156         break;
1157 
1158       case GXV_GLYPHOFFSET_LONG:
1159         glyphOffset.l = FT_NEXT_LONG( p );
1160         break;
1161       }
1162 
1163       if ( gxvalid->statetable.entry_validate_func )
1164         gxvalid->statetable.entry_validate_func( state,
1165                                                  flags,
1166                                                  &glyphOffset,
1167                                                  statetable_table,
1168                                                  statetable_limit,
1169                                                  gxvalid );
1170     }
1171 
1172     *length_p = (FT_UShort)( p - table );
1173 
1174     GXV_EXIT;
1175   }
1176 
1177 
1178   /* =========================== State Table ============================= */
1179 
1180   FT_LOCAL_DEF( void )
gxv_StateTable_subtable_setup(FT_UShort table_size,FT_UShort classTable,FT_UShort stateArray,FT_UShort entryTable,FT_UShort * classTable_length_p,FT_UShort * stateArray_length_p,FT_UShort * entryTable_length_p,GXV_Validator gxvalid)1181   gxv_StateTable_subtable_setup( FT_UShort      table_size,
1182                                  FT_UShort      classTable,
1183                                  FT_UShort      stateArray,
1184                                  FT_UShort      entryTable,
1185                                  FT_UShort*     classTable_length_p,
1186                                  FT_UShort*     stateArray_length_p,
1187                                  FT_UShort*     entryTable_length_p,
1188                                  GXV_Validator  gxvalid )
1189   {
1190     FT_UShort   o[3];
1191     FT_UShort*  l[3];
1192     FT_UShort   buff[4];
1193 
1194 
1195     o[0] = classTable;
1196     o[1] = stateArray;
1197     o[2] = entryTable;
1198     l[0] = classTable_length_p;
1199     l[1] = stateArray_length_p;
1200     l[2] = entryTable_length_p;
1201 
1202     gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, gxvalid );
1203   }
1204 
1205 
1206   FT_LOCAL_DEF( void )
gxv_StateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)1207   gxv_StateTable_validate( FT_Bytes       table,
1208                            FT_Bytes       limit,
1209                            GXV_Validator  gxvalid )
1210   {
1211     FT_UShort   stateSize;
1212     FT_UShort   classTable;     /* offset to Class(Sub)Table */
1213     FT_UShort   stateArray;     /* offset to StateArray */
1214     FT_UShort   entryTable;     /* offset to EntryTable */
1215 
1216     FT_UShort   classTable_length;
1217     FT_UShort   stateArray_length;
1218     FT_UShort   entryTable_length;
1219     FT_Byte     maxClassID;
1220     FT_Byte     maxState;
1221     FT_Byte     maxEntry;
1222 
1223     GXV_StateTable_Subtable_Setup_Func  setup_func;
1224 
1225     FT_Bytes    p = table;
1226 
1227 
1228     GXV_NAME_ENTER( "StateTable" );
1229 
1230     GXV_TRACE(( "StateTable header\n" ));
1231 
1232     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
1233     stateSize  = FT_NEXT_USHORT( p );
1234     classTable = FT_NEXT_USHORT( p );
1235     stateArray = FT_NEXT_USHORT( p );
1236     entryTable = FT_NEXT_USHORT( p );
1237 
1238     GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
1239     GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
1240     GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
1241     GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
1242 
1243     if ( stateSize > 0xFF )
1244       FT_INVALID_DATA;
1245 
1246     if ( gxvalid->statetable.optdata_load_func )
1247       gxvalid->statetable.optdata_load_func( p, limit, gxvalid );
1248 
1249     if ( gxvalid->statetable.subtable_setup_func )
1250       setup_func = gxvalid->statetable.subtable_setup_func;
1251     else
1252       setup_func = gxv_StateTable_subtable_setup;
1253 
1254     setup_func( (FT_UShort)( limit - table ),
1255                 classTable,
1256                 stateArray,
1257                 entryTable,
1258                 &classTable_length,
1259                 &stateArray_length,
1260                 &entryTable_length,
1261                 gxvalid );
1262 
1263     GXV_TRACE(( "StateTable Subtables\n" ));
1264 
1265     if ( classTable != 0 )
1266       gxv_ClassTable_validate( table + classTable,
1267                                &classTable_length,
1268                                stateSize,
1269                                &maxClassID,
1270                                gxvalid );
1271     else
1272       maxClassID = (FT_Byte)( stateSize - 1 );
1273 
1274     if ( stateArray != 0 )
1275       gxv_StateArray_validate( table + stateArray,
1276                                &stateArray_length,
1277                                maxClassID,
1278                                stateSize,
1279                                &maxState,
1280                                &maxEntry,
1281                                gxvalid );
1282     else
1283     {
1284 #if 0
1285       maxState = 1;     /* 0:start of text, 1:start of line are predefined */
1286 #endif
1287       maxEntry = 0;
1288     }
1289 
1290     if ( maxEntry > 0 && entryTable == 0 )
1291       FT_INVALID_OFFSET;
1292 
1293     if ( entryTable != 0 )
1294       gxv_EntryTable_validate( table + entryTable,
1295                                &entryTable_length,
1296                                maxEntry,
1297                                stateArray,
1298                                stateArray_length,
1299                                maxClassID,
1300                                table,
1301                                limit,
1302                                gxvalid );
1303 
1304     GXV_EXIT;
1305   }
1306 
1307 
1308   /* ================= eXtended State Table (for morx) =================== */
1309 
1310   FT_LOCAL_DEF( void )
gxv_XStateTable_subtable_setup(FT_ULong table_size,FT_ULong classTable,FT_ULong stateArray,FT_ULong entryTable,FT_ULong * classTable_length_p,FT_ULong * stateArray_length_p,FT_ULong * entryTable_length_p,GXV_Validator gxvalid)1311   gxv_XStateTable_subtable_setup( FT_ULong       table_size,
1312                                   FT_ULong       classTable,
1313                                   FT_ULong       stateArray,
1314                                   FT_ULong       entryTable,
1315                                   FT_ULong*      classTable_length_p,
1316                                   FT_ULong*      stateArray_length_p,
1317                                   FT_ULong*      entryTable_length_p,
1318                                   GXV_Validator  gxvalid )
1319   {
1320     FT_ULong   o[3];
1321     FT_ULong*  l[3];
1322     FT_ULong   buff[4];
1323 
1324 
1325     o[0] = classTable;
1326     o[1] = stateArray;
1327     o[2] = entryTable;
1328     l[0] = classTable_length_p;
1329     l[1] = stateArray_length_p;
1330     l[2] = entryTable_length_p;
1331 
1332     gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, gxvalid );
1333   }
1334 
1335 
1336   static void
gxv_XClassTable_lookupval_validate(FT_UShort glyph,GXV_LookupValueCPtr value_p,GXV_Validator gxvalid)1337   gxv_XClassTable_lookupval_validate( FT_UShort            glyph,
1338                                       GXV_LookupValueCPtr  value_p,
1339                                       GXV_Validator        gxvalid )
1340   {
1341     FT_UNUSED( glyph );
1342 
1343     if ( value_p->u >= gxvalid->xstatetable.nClasses )
1344       FT_INVALID_DATA;
1345     if ( value_p->u > gxvalid->xstatetable.maxClassID )
1346       gxvalid->xstatetable.maxClassID = value_p->u;
1347   }
1348 
1349 
1350   /*
1351     +===============+ --------+
1352     | lookup header |         |
1353     +===============+         |
1354     | BinSrchHeader |         |
1355     +===============+         |
1356     | lastGlyph[0]  |         |
1357     +---------------+         |
1358     | firstGlyph[0] |         |    head of lookup table
1359     +---------------+         |             +
1360     | offset[0]     |    ->   |          offset            [byte]
1361     +===============+         |             +
1362     | lastGlyph[1]  |         | (glyphID - firstGlyph) * 2 [byte]
1363     +---------------+         |
1364     | firstGlyph[1] |         |
1365     +---------------+         |
1366     | offset[1]     |         |
1367     +===============+         |
1368                               |
1369      ....                     |
1370                               |
1371     16bit value array         |
1372     +===============+         |
1373     |     value     | <-------+
1374      ....
1375   */
1376   static GXV_LookupValueDesc
gxv_XClassTable_lookupfmt4_transit(FT_UShort relative_gindex,GXV_LookupValueCPtr base_value_p,FT_Bytes lookuptbl_limit,GXV_Validator gxvalid)1377   gxv_XClassTable_lookupfmt4_transit( FT_UShort            relative_gindex,
1378                                       GXV_LookupValueCPtr  base_value_p,
1379                                       FT_Bytes             lookuptbl_limit,
1380                                       GXV_Validator        gxvalid )
1381   {
1382     FT_Bytes             p;
1383     FT_Bytes             limit;
1384     FT_UShort            offset;
1385     GXV_LookupValueDesc  value;
1386 
1387     /* XXX: check range? */
1388     offset = (FT_UShort)( base_value_p->u +
1389                           relative_gindex * sizeof ( FT_UShort ) );
1390 
1391     p     = gxvalid->lookuptbl_head + offset;
1392     limit = lookuptbl_limit;
1393 
1394     GXV_LIMIT_CHECK ( 2 );
1395     value.u = FT_NEXT_USHORT( p );
1396 
1397     return value;
1398   }
1399 
1400 
1401   static void
gxv_XStateArray_validate(FT_Bytes table,FT_ULong * length_p,FT_UShort maxClassID,FT_ULong stateSize,FT_UShort * maxState_p,FT_UShort * maxEntry_p,GXV_Validator gxvalid)1402   gxv_XStateArray_validate( FT_Bytes       table,
1403                             FT_ULong*      length_p,
1404                             FT_UShort      maxClassID,
1405                             FT_ULong       stateSize,
1406                             FT_UShort*     maxState_p,
1407                             FT_UShort*     maxEntry_p,
1408                             GXV_Validator  gxvalid )
1409   {
1410     FT_Bytes   p = table;
1411     FT_Bytes   limit = table + *length_p;
1412     FT_UShort  clazz;
1413     FT_UShort  entry;
1414 
1415     FT_UNUSED( stateSize ); /* for the non-debugging case */
1416 
1417 
1418     GXV_NAME_ENTER( "XStateArray" );
1419 
1420     GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
1421                 (int)( *length_p ), (int)stateSize, (int)maxClassID ));
1422 
1423     /*
1424      * 2 states are predefined and must be described:
1425      * state 0 (start of text), 1 (start of line)
1426      */
1427     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
1428 
1429     *maxState_p = 0;
1430     *maxEntry_p = 0;
1431 
1432     /* read if enough to read another state */
1433     while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
1434     {
1435       (*maxState_p)++;
1436       for ( clazz = 0; clazz <= maxClassID; clazz++ )
1437       {
1438         entry = FT_NEXT_USHORT( p );
1439         *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry );
1440       }
1441     }
1442     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1443                 *maxState_p, *maxEntry_p ));
1444 
1445     *length_p = (FT_ULong)( p - table );
1446 
1447     GXV_EXIT;
1448   }
1449 
1450 
1451   static void
gxv_XEntryTable_validate(FT_Bytes table,FT_ULong * length_p,FT_UShort maxEntry,FT_ULong stateArray_length,FT_UShort maxClassID,FT_Bytes xstatetable_table,FT_Bytes xstatetable_limit,GXV_Validator gxvalid)1452   gxv_XEntryTable_validate( FT_Bytes       table,
1453                             FT_ULong*      length_p,
1454                             FT_UShort      maxEntry,
1455                             FT_ULong       stateArray_length,
1456                             FT_UShort      maxClassID,
1457                             FT_Bytes       xstatetable_table,
1458                             FT_Bytes       xstatetable_limit,
1459                             GXV_Validator  gxvalid )
1460   {
1461     FT_Bytes   p = table;
1462     FT_Bytes   limit = table + *length_p;
1463     FT_UShort  entry;
1464     FT_UShort  state;
1465     FT_Int     entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
1466 
1467 
1468     GXV_NAME_ENTER( "XEntryTable" );
1469     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1470 
1471     if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
1472       FT_INVALID_TOO_SHORT;
1473 
1474     for (entry = 0; entry <= maxEntry; entry++ )
1475     {
1476       FT_UShort                        newState_idx;
1477       FT_UShort                        flags;
1478       GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
1479 
1480 
1481       GXV_LIMIT_CHECK( 2 + 2 );
1482       newState_idx = FT_NEXT_USHORT( p );
1483       flags        = FT_NEXT_USHORT( p );
1484 
1485       if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) )
1486       {
1487         GXV_TRACE(( "  newState index 0x%04x points out of stateArray\n",
1488                     newState_idx ));
1489         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1490       }
1491 
1492       state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) );
1493       if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
1494       {
1495         FT_TRACE4(( "-> new state = %d (supposed)\n",
1496                     state ));
1497         FT_TRACE4(( "but newState index 0x%04x"
1498                     " is not aligned to %d-classes\n",
1499                     newState_idx, 1 + maxClassID ));
1500         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1501       }
1502 
1503       switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
1504       {
1505       case GXV_GLYPHOFFSET_NONE:
1506         glyphOffset.uc = 0; /* make compiler happy */
1507         break;
1508 
1509       case GXV_GLYPHOFFSET_UCHAR:
1510         glyphOffset.uc = FT_NEXT_BYTE( p );
1511         break;
1512 
1513       case GXV_GLYPHOFFSET_CHAR:
1514         glyphOffset.c = FT_NEXT_CHAR( p );
1515         break;
1516 
1517       case GXV_GLYPHOFFSET_USHORT:
1518         glyphOffset.u = FT_NEXT_USHORT( p );
1519         break;
1520 
1521       case GXV_GLYPHOFFSET_SHORT:
1522         glyphOffset.s = FT_NEXT_SHORT( p );
1523         break;
1524 
1525       case GXV_GLYPHOFFSET_ULONG:
1526         glyphOffset.ul = FT_NEXT_ULONG( p );
1527         break;
1528 
1529       case GXV_GLYPHOFFSET_LONG:
1530         glyphOffset.l = FT_NEXT_LONG( p );
1531         break;
1532 
1533       default:
1534         GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT );
1535         goto Exit;
1536       }
1537 
1538       if ( gxvalid->xstatetable.entry_validate_func )
1539         gxvalid->xstatetable.entry_validate_func( state,
1540                                                   flags,
1541                                                   &glyphOffset,
1542                                                   xstatetable_table,
1543                                                   xstatetable_limit,
1544                                                   gxvalid );
1545     }
1546 
1547   Exit:
1548     *length_p = (FT_ULong)( p - table );
1549 
1550     GXV_EXIT;
1551   }
1552 
1553 
1554   FT_LOCAL_DEF( void )
gxv_XStateTable_validate(FT_Bytes table,FT_Bytes limit,GXV_Validator gxvalid)1555   gxv_XStateTable_validate( FT_Bytes       table,
1556                             FT_Bytes       limit,
1557                             GXV_Validator  gxvalid )
1558   {
1559     /* StateHeader members */
1560     FT_ULong   classTable;      /* offset to Class(Sub)Table */
1561     FT_ULong   stateArray;      /* offset to StateArray */
1562     FT_ULong   entryTable;      /* offset to EntryTable */
1563 
1564     FT_ULong   classTable_length;
1565     FT_ULong   stateArray_length;
1566     FT_ULong   entryTable_length;
1567     FT_UShort  maxState;
1568     FT_UShort  maxEntry;
1569 
1570     GXV_XStateTable_Subtable_Setup_Func  setup_func;
1571 
1572     FT_Bytes   p = table;
1573 
1574 
1575     GXV_NAME_ENTER( "XStateTable" );
1576 
1577     GXV_TRACE(( "XStateTable header\n" ));
1578 
1579     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
1580     gxvalid->xstatetable.nClasses = FT_NEXT_ULONG( p );
1581     classTable = FT_NEXT_ULONG( p );
1582     stateArray = FT_NEXT_ULONG( p );
1583     entryTable = FT_NEXT_ULONG( p );
1584 
1585     GXV_TRACE(( "nClasses =0x%08lx\n", gxvalid->xstatetable.nClasses ));
1586     GXV_TRACE(( "offset to classTable=0x%08lx\n", classTable ));
1587     GXV_TRACE(( "offset to stateArray=0x%08lx\n", stateArray ));
1588     GXV_TRACE(( "offset to entryTable=0x%08lx\n", entryTable ));
1589 
1590     if ( gxvalid->xstatetable.nClasses > 0xFFFFU )
1591       FT_INVALID_DATA;
1592 
1593     GXV_TRACE(( "StateTable Subtables\n" ));
1594 
1595     if ( gxvalid->xstatetable.optdata_load_func )
1596       gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid );
1597 
1598     if ( gxvalid->xstatetable.subtable_setup_func )
1599       setup_func = gxvalid->xstatetable.subtable_setup_func;
1600     else
1601       setup_func = gxv_XStateTable_subtable_setup;
1602 
1603     setup_func( (FT_ULong)( limit - table ),
1604                 classTable,
1605                 stateArray,
1606                 entryTable,
1607                 &classTable_length,
1608                 &stateArray_length,
1609                 &entryTable_length,
1610                 gxvalid );
1611 
1612     if ( classTable != 0 )
1613     {
1614       gxvalid->xstatetable.maxClassID = 0;
1615       gxvalid->lookupval_sign         = GXV_LOOKUPVALUE_UNSIGNED;
1616       gxvalid->lookupval_func         = gxv_XClassTable_lookupval_validate;
1617       gxvalid->lookupfmt4_trans       = gxv_XClassTable_lookupfmt4_transit;
1618       gxv_LookupTable_validate( table + classTable,
1619                                 table + classTable + classTable_length,
1620                                 gxvalid );
1621 #if 0
1622       if ( gxvalid->subtable_length < classTable_length )
1623         classTable_length = gxvalid->subtable_length;
1624 #endif
1625     }
1626     else
1627     {
1628       /* XXX: check range? */
1629       gxvalid->xstatetable.maxClassID =
1630         (FT_UShort)( gxvalid->xstatetable.nClasses - 1 );
1631     }
1632 
1633     if ( stateArray != 0 )
1634       gxv_XStateArray_validate( table + stateArray,
1635                                 &stateArray_length,
1636                                 gxvalid->xstatetable.maxClassID,
1637                                 gxvalid->xstatetable.nClasses,
1638                                 &maxState,
1639                                 &maxEntry,
1640                                 gxvalid );
1641     else
1642     {
1643 #if 0
1644       maxState = 1; /* 0:start of text, 1:start of line are predefined */
1645 #endif
1646       maxEntry = 0;
1647     }
1648 
1649     if ( maxEntry > 0 && entryTable == 0 )
1650       FT_INVALID_OFFSET;
1651 
1652     if ( entryTable != 0 )
1653       gxv_XEntryTable_validate( table + entryTable,
1654                                 &entryTable_length,
1655                                 maxEntry,
1656                                 stateArray_length,
1657                                 gxvalid->xstatetable.maxClassID,
1658                                 table,
1659                                 limit,
1660                                 gxvalid );
1661 
1662     GXV_EXIT;
1663   }
1664 
1665 
1666   /*************************************************************************/
1667   /*************************************************************************/
1668   /*****                                                               *****/
1669   /*****                        Table overlapping                      *****/
1670   /*****                                                               *****/
1671   /*************************************************************************/
1672   /*************************************************************************/
1673 
1674   static int
gxv_compare_ranges(FT_Bytes table1_start,FT_ULong table1_length,FT_Bytes table2_start,FT_ULong table2_length)1675   gxv_compare_ranges( FT_Bytes  table1_start,
1676                       FT_ULong  table1_length,
1677                       FT_Bytes  table2_start,
1678                       FT_ULong  table2_length )
1679   {
1680     if ( table1_start == table2_start )
1681     {
1682       if ( ( table1_length == 0 || table2_length == 0 ) )
1683         goto Out;
1684     }
1685     else if ( table1_start < table2_start )
1686     {
1687       if ( ( table1_start + table1_length ) <= table2_start )
1688         goto Out;
1689     }
1690     else if ( table1_start > table2_start )
1691     {
1692       if ( ( table1_start >= table2_start + table2_length ) )
1693         goto Out;
1694     }
1695     return 1;
1696 
1697   Out:
1698     return 0;
1699   }
1700 
1701 
1702   FT_LOCAL_DEF( void )
gxv_odtect_add_range(FT_Bytes start,FT_ULong length,const FT_String * name,GXV_odtect_Range odtect)1703   gxv_odtect_add_range( FT_Bytes          start,
1704                         FT_ULong          length,
1705                         const FT_String*  name,
1706                         GXV_odtect_Range  odtect )
1707   {
1708     odtect->range[odtect->nRanges].start  = start;
1709     odtect->range[odtect->nRanges].length = length;
1710     odtect->range[odtect->nRanges].name   = (FT_String*)name;
1711     odtect->nRanges++;
1712   }
1713 
1714 
1715   FT_LOCAL_DEF( void )
gxv_odtect_validate(GXV_odtect_Range odtect,GXV_Validator gxvalid)1716   gxv_odtect_validate( GXV_odtect_Range  odtect,
1717                        GXV_Validator     gxvalid )
1718   {
1719     FT_UInt  i, j;
1720 
1721 
1722     GXV_NAME_ENTER( "check overlap among multi ranges" );
1723 
1724     for ( i = 0; i < odtect->nRanges; i++ )
1725       for ( j = 0; j < i; j++ )
1726         if ( 0 != gxv_compare_ranges( odtect->range[i].start,
1727                                       odtect->range[i].length,
1728                                       odtect->range[j].start,
1729                                       odtect->range[j].length ) )
1730         {
1731 #ifdef FT_DEBUG_LEVEL_TRACE
1732           if ( odtect->range[i].name || odtect->range[j].name )
1733             GXV_TRACE(( "found overlap between range %d and range %d\n",
1734                         i, j ));
1735           else
1736             GXV_TRACE(( "found overlap between `%s' and `%s\'\n",
1737                         odtect->range[i].name,
1738                         odtect->range[j].name ));
1739 #endif
1740           FT_INVALID_OFFSET;
1741         }
1742 
1743     GXV_EXIT;
1744   }
1745 
1746 
1747 /* END */
1748