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