Imported Upstream version 2.10.4
[platform/upstream/freetype2.git] / src / gxvalid / gxvcommn.c
1 /****************************************************************************
2  *
3  * gxvcommn.c
4  *
5  *   TrueTypeGX/AAT common tables validation (body).
6  *
7  * Copyright (C) 2004-2020 by
8  * suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
9  * David Turner, Robert Wilhelm, and Werner Lemberg.
10  *
11  * This file is part of the FreeType project, and may only be used,
12  * modified, and distributed under the terms of the FreeType project
13  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
14  * this file you indicate that you have read the license and
15  * understand and accept it fully.
16  *
17  */
18
19 /****************************************************************************
20  *
21  * gxvalid is derived from both gxlayout module and otvalid module.
22  * Development of gxlayout is supported by the Information-technology
23  * Promotion Agency(IPA), Japan.
24  *
25  */
26
27
28 #include "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   static int
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 )
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
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 )
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 )
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 )
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
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 )
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
387   gxv_lookup_value_load( FT_Bytes                  p,
388                          GXV_LookupValue_SignSpec  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
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 Lookup 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
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
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
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
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
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
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 )
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 )
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 )
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 )
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 )
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
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_MEM_ZERO( nGlyphInClass, 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
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
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 ( 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 )
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 )
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 )
1248       gxvalid->statetable.optdata_load_func( p, limit, gxvalid );
1249
1250     if ( gxvalid->statetable.subtable_setup_func )
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 )
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
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
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
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
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 ( 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 )
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 )
1595       gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid );
1596
1597     if ( gxvalid->xstatetable.subtable_setup_func )
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
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 )
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 )
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 */