Initialize Tizen 2.3
[framework/graphics/freetype.git] / src / gxvalid / gxvcommn.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  gxvcommn.c                                                             */
4 /*                                                                         */
5 /*    TrueTypeGX/AAT common tables validation (body).                      */
6 /*                                                                         */
7 /*  Copyright 2004, 2005, 2009, 2010                                       */
8 /*  by 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
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  valid )
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  valid)
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  valid )
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     valid->subtable_length = 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  valid )
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     valid->subtable_length = 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       valid )
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  valid )
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, valid );
363
364     if ( *unitSize_p == 0 )
365       *unitSize_p = binSrchHeader.unitSize;
366
367     if ( *nUnits_p == 0 )
368       *nUnits_p = binSrchHeader.nUnits;
369
370     valid->subtable_length = 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                          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
423   gxv_LookupTable_fmt0_validate( FT_Bytes       table,
424                                  FT_Bytes       limit,
425                                  GXV_Validator  valid )
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 * valid->face->num_glyphs );
436
437     for ( i = 0; i < valid->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, valid->face->num_glyphs ));
444         GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
445         break;
446       }
447
448       value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
449       valid->lookupval_func( i, &value, valid );
450     }
451
452     valid->subtable_length = 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
474   gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes       table,
475                                         FT_UShort      unitSize,
476                                         GXV_Validator  valid )
477   {
478     FT_Bytes  p = table;
479
480
481     while ( ( p + 4 ) < valid->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     valid->subtable_length = p - table;
490   }
491
492
493   static void
494   gxv_LookupTable_fmt2_validate( FT_Bytes       table,
495                                  FT_Bytes       limit,
496                                  GXV_Validator  valid )
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, valid );
513     p += valid->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, valid->lookupval_sign );
523
524       gxv_glyphid_validate( firstGlyph, valid );
525       gxv_glyphid_validate( lastGlyph, valid );
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 ( valid->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         valid->lookupval_func( gid, &value, valid );
553     }
554
555     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
556     p += valid->subtable_length;
557
558     valid->subtable_length = 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  valid )
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, valid );
585     p += valid->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, valid );
596       gxv_glyphid_validate( lastGlyph, valid );
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 ( valid->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 = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ),
628                                          &base_value,
629                                          limit,
630                                          valid );
631
632         valid->lookupval_func( gid, &value, valid );
633       }
634     }
635
636     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
637     p += valid->subtable_length;
638
639     valid->subtable_length = 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  valid )
649   {
650     FT_Bytes  p = table;
651
652
653     while ( p < valid->root->limit )
654     {
655       if ( p[0] != 0xFF || p[1] != 0xFF )
656         break;
657       p += unitSize;
658     }
659
660     valid->subtable_length = p - table;
661   }
662
663
664   static void
665   gxv_LookupTable_fmt6_validate( FT_Bytes       table,
666                                  FT_Bytes       limit,
667                                  GXV_Validator  valid )
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, valid );
683     p += valid->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, valid->lookupval_sign );
692
693       if ( gxv_glyphid_validate( glyph, valid ) )
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       valid->lookupval_func( glyph, &value, valid );
707     }
708
709     gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid );
710     p += valid->subtable_length;
711
712     valid->subtable_length = 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  valid )
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, valid );
739     gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid );
740
741     /* valueArray */
742     for ( i = 0; i < glyphCount; i++ )
743     {
744       GXV_LIMIT_CHECK( 2 );
745       value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
746       valid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, valid );
747     }
748
749     valid->subtable_length = 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  valid )
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     valid->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, valid );
796     p += valid->subtable_length;
797
798     valid->subtable_length = 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  valid )
815   {
816     FT_Face  face;
817
818
819     if ( gid == 0xFFFFU )
820     {
821       GXV_EXIT;
822       return 1;
823     }
824
825     face = valid->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_Short       ctl_point,
848                          GXV_Validator  valid )
849   {
850     FT_Face       face;
851     FT_Error      error;
852
853     FT_GlyphSlot  glyph;
854     FT_Outline    outline;
855     short         n_points;
856
857
858     face = valid->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 = outline.n_points;
869
870
871     if ( !( ctl_point < n_points ) )
872       FT_INVALID_DATA;
873   }
874
875
876   /*************************************************************************/
877   /*************************************************************************/
878   /*****                                                               *****/
879   /*****                          SFNT NAME                            *****/
880   /*****                                                               *****/
881   /*************************************************************************/
882   /*************************************************************************/
883
884   FT_LOCAL_DEF( void )
885   gxv_sfntName_validate( FT_UShort      name_index,
886                          FT_UShort      min_index,
887                          FT_UShort      max_index,
888                          GXV_Validator  valid )
889   {
890     FT_SfntName  name;
891     FT_UInt      i;
892     FT_UInt      nnames;
893
894
895     GXV_NAME_ENTER( "sfntName" );
896
897     if ( name_index < min_index || max_index < name_index )
898       FT_INVALID_FORMAT;
899
900     nnames = FT_Get_Sfnt_Name_Count( valid->face );
901     for ( i = 0; i < nnames; i++ )
902     {
903       if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != GXV_Err_Ok )
904         continue ;
905
906       if ( name.name_id == name_index )
907         goto Out;
908     }
909
910     GXV_TRACE(( "  nameIndex = %d (UNTITLED)\n", name_index ));
911     FT_INVALID_DATA;
912     goto Exit;  /* make compiler happy */
913
914   Out:
915     FT_TRACE1(( "  nameIndex = %d (", name_index ));
916     GXV_TRACE_HEXDUMP_SFNTNAME( name );
917     FT_TRACE1(( ")\n" ));
918
919   Exit:
920     GXV_EXIT;
921   }
922
923
924   /*************************************************************************/
925   /*************************************************************************/
926   /*****                                                               *****/
927   /*****                          STATE TABLE                          *****/
928   /*****                                                               *****/
929   /*************************************************************************/
930   /*************************************************************************/
931
932   /* -------------------------- Class Table --------------------------- */
933
934   /*
935    * highestClass specifies how many classes are defined in this
936    * Class Subtable.  Apple spec does not mention whether undefined
937    * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used)
938    * are permitted.  At present, holes in a defined class are not checked.
939    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
940    */
941
942   static void
943   gxv_ClassTable_validate( FT_Bytes       table,
944                            FT_UShort*     length_p,
945                            FT_UShort      stateSize,
946                            FT_Byte*       maxClassID_p,
947                            GXV_Validator  valid )
948   {
949     FT_Bytes   p     = table;
950     FT_Bytes   limit = table + *length_p;
951     FT_UShort  firstGlyph;
952     FT_UShort  nGlyphs;
953
954
955     GXV_NAME_ENTER( "ClassTable" );
956
957     *maxClassID_p = 3;  /* Classes 0, 2, and 3 are predefined */
958
959     GXV_LIMIT_CHECK( 2 + 2 );
960     firstGlyph = FT_NEXT_USHORT( p );
961     nGlyphs    = FT_NEXT_USHORT( p );
962
963     GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
964
965     if ( !nGlyphs )
966       goto Out;
967
968     gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid );
969
970     {
971       FT_Byte    nGlyphInClass[256];
972       FT_Byte    classID;
973       FT_UShort  i;
974
975
976       ft_memset( nGlyphInClass, 0, 256 );
977
978
979       for ( i = 0; i < nGlyphs; i++ )
980       {
981         GXV_LIMIT_CHECK( 1 );
982         classID = FT_NEXT_BYTE( p );
983         switch ( classID )
984         {
985           /* following classes should not appear in class array */
986         case 0:             /* end of text */
987         case 2:             /* out of bounds */
988         case 3:             /* end of line */
989           FT_INVALID_DATA;
990           break;
991
992         case 1:             /* out of bounds */
993         default:            /* user-defined: 4 - ( stateSize - 1 ) */
994           if ( classID >= stateSize )
995             FT_INVALID_DATA;   /* assign glyph to undefined state */
996
997           nGlyphInClass[classID]++;
998           break;
999         }
1000       }
1001       *length_p = (FT_UShort)( p - table );
1002
1003       /* scan max ClassID in use */
1004       for ( i = 0; i < stateSize; i++ )
1005         if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) )
1006           *maxClassID_p = (FT_Byte)i;  /* XXX: Check Range? */
1007     }
1008
1009   Out:
1010     GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
1011                 stateSize, *maxClassID_p ));
1012     GXV_EXIT;
1013   }
1014
1015
1016   /* --------------------------- State Array ----------------------------- */
1017
1018   static void
1019   gxv_StateArray_validate( FT_Bytes       table,
1020                            FT_UShort*     length_p,
1021                            FT_Byte        maxClassID,
1022                            FT_UShort      stateSize,
1023                            FT_Byte*       maxState_p,
1024                            FT_Byte*       maxEntry_p,
1025                            GXV_Validator  valid )
1026   {
1027     FT_Bytes  p = table;
1028     FT_Bytes  limit = table + *length_p;
1029     FT_Byte   clazz;
1030     FT_Byte   entry;
1031
1032     FT_UNUSED( stateSize ); /* for the non-debugging case */
1033
1034
1035     GXV_NAME_ENTER( "StateArray" );
1036
1037     GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
1038                 (int)(*length_p), stateSize, (int)(maxClassID) ));
1039
1040     /*
1041      * 2 states are predefined and must be described in StateArray:
1042      * state 0 (start of text), 1 (start of line)
1043      */
1044     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
1045
1046     *maxState_p = 0;
1047     *maxEntry_p = 0;
1048
1049     /* read if enough to read another state */
1050     while ( p + ( 1 + maxClassID ) <= limit )
1051     {
1052       (*maxState_p)++;
1053       for ( clazz = 0; clazz <= maxClassID; clazz++ )
1054       {
1055         entry = FT_NEXT_BYTE( p );
1056         *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
1057       }
1058     }
1059     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1060                 *maxState_p, *maxEntry_p ));
1061
1062     *length_p = (FT_UShort)( p - table );
1063
1064     GXV_EXIT;
1065   }
1066
1067
1068   /* --------------------------- Entry Table ----------------------------- */
1069
1070   static void
1071   gxv_EntryTable_validate( FT_Bytes       table,
1072                            FT_UShort*     length_p,
1073                            FT_Byte        maxEntry,
1074                            FT_UShort      stateArray,
1075                            FT_UShort      stateArray_length,
1076                            FT_Byte        maxClassID,
1077                            FT_Bytes       statetable_table,
1078                            FT_Bytes       statetable_limit,
1079                            GXV_Validator  valid )
1080   {
1081     FT_Bytes  p     = table;
1082     FT_Bytes  limit = table + *length_p;
1083     FT_Byte   entry;
1084     FT_Byte   state;
1085     FT_Int    entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
1086
1087     GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
1088
1089
1090     GXV_NAME_ENTER( "EntryTable" );
1091
1092     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1093
1094     if ( ( maxEntry + 1 ) * entrySize > *length_p )
1095     {
1096       GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT );
1097
1098       /* ftxvalidator and FontValidator both warn and continue */
1099       maxEntry = (FT_Byte)( *length_p / entrySize - 1 );
1100       GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n",
1101                   maxEntry ));
1102     }
1103
1104     for ( entry = 0; entry <= maxEntry; entry++ )
1105     {
1106       FT_UShort  newState;
1107       FT_UShort  flags;
1108
1109
1110       GXV_LIMIT_CHECK( 2 + 2 );
1111       newState = FT_NEXT_USHORT( p );
1112       flags    = FT_NEXT_USHORT( p );
1113
1114
1115       if ( newState < stateArray                     ||
1116            stateArray + stateArray_length < newState )
1117       {
1118         GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
1119                     newState ));
1120         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1121         continue;
1122       }
1123
1124       if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
1125       {
1126         GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
1127                     newState,  1 + maxClassID ));
1128         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1129         continue;
1130       }
1131
1132       state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
1133
1134       switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
1135       {
1136       case GXV_GLYPHOFFSET_NONE:
1137         glyphOffset.uc = 0;  /* make compiler happy */
1138         break;
1139
1140       case GXV_GLYPHOFFSET_UCHAR:
1141         glyphOffset.uc = FT_NEXT_BYTE( p );
1142         break;
1143
1144       case GXV_GLYPHOFFSET_CHAR:
1145         glyphOffset.c = FT_NEXT_CHAR( p );
1146         break;
1147
1148       case GXV_GLYPHOFFSET_USHORT:
1149         glyphOffset.u = FT_NEXT_USHORT( p );
1150         break;
1151
1152       case GXV_GLYPHOFFSET_SHORT:
1153         glyphOffset.s = FT_NEXT_SHORT( p );
1154         break;
1155
1156       case GXV_GLYPHOFFSET_ULONG:
1157         glyphOffset.ul = FT_NEXT_ULONG( p );
1158         break;
1159
1160       case GXV_GLYPHOFFSET_LONG:
1161         glyphOffset.l = FT_NEXT_LONG( p );
1162         break;
1163
1164       default:
1165         GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT );
1166         goto Exit;
1167       }
1168
1169       if ( NULL != valid->statetable.entry_validate_func )
1170         valid->statetable.entry_validate_func( state,
1171                                                flags,
1172                                                &glyphOffset,
1173                                                statetable_table,
1174                                                statetable_limit,
1175                                                valid );
1176     }
1177
1178   Exit:
1179     *length_p = (FT_UShort)( p - table );
1180
1181     GXV_EXIT;
1182   }
1183
1184
1185   /* =========================== State Table ============================= */
1186
1187   FT_LOCAL_DEF( void )
1188   gxv_StateTable_subtable_setup( FT_UShort      table_size,
1189                                  FT_UShort      classTable,
1190                                  FT_UShort      stateArray,
1191                                  FT_UShort      entryTable,
1192                                  FT_UShort*     classTable_length_p,
1193                                  FT_UShort*     stateArray_length_p,
1194                                  FT_UShort*     entryTable_length_p,
1195                                  GXV_Validator  valid )
1196   {
1197     FT_UShort   o[3];
1198     FT_UShort*  l[3];
1199     FT_UShort   buff[4];
1200
1201
1202     o[0] = classTable;
1203     o[1] = stateArray;
1204     o[2] = entryTable;
1205     l[0] = classTable_length_p;
1206     l[1] = stateArray_length_p;
1207     l[2] = entryTable_length_p;
1208
1209     gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid );
1210   }
1211
1212
1213   FT_LOCAL_DEF( void )
1214   gxv_StateTable_validate( FT_Bytes       table,
1215                            FT_Bytes       limit,
1216                            GXV_Validator  valid )
1217   {
1218     FT_UShort   stateSize;
1219     FT_UShort   classTable;     /* offset to Class(Sub)Table */
1220     FT_UShort   stateArray;     /* offset to StateArray */
1221     FT_UShort   entryTable;     /* offset to EntryTable */
1222
1223     FT_UShort   classTable_length;
1224     FT_UShort   stateArray_length;
1225     FT_UShort   entryTable_length;
1226     FT_Byte     maxClassID;
1227     FT_Byte     maxState;
1228     FT_Byte     maxEntry;
1229
1230     GXV_StateTable_Subtable_Setup_Func  setup_func;
1231
1232     FT_Bytes    p = table;
1233
1234
1235     GXV_NAME_ENTER( "StateTable" );
1236
1237     GXV_TRACE(( "StateTable header\n" ));
1238
1239     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
1240     stateSize  = FT_NEXT_USHORT( p );
1241     classTable = FT_NEXT_USHORT( p );
1242     stateArray = FT_NEXT_USHORT( p );
1243     entryTable = FT_NEXT_USHORT( p );
1244
1245     GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
1246     GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
1247     GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
1248     GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
1249
1250     if ( stateSize > 0xFF )
1251       FT_INVALID_DATA;
1252
1253     if ( valid->statetable.optdata_load_func != NULL )
1254       valid->statetable.optdata_load_func( p, limit, valid );
1255
1256     if ( valid->statetable.subtable_setup_func != NULL)
1257       setup_func = valid->statetable.subtable_setup_func;
1258     else
1259       setup_func = gxv_StateTable_subtable_setup;
1260
1261     setup_func( (FT_UShort)( limit - table ),
1262                 classTable,
1263                 stateArray,
1264                 entryTable,
1265                 &classTable_length,
1266                 &stateArray_length,
1267                 &entryTable_length,
1268                 valid );
1269
1270     GXV_TRACE(( "StateTable Subtables\n" ));
1271
1272     if ( classTable != 0 )
1273       gxv_ClassTable_validate( table + classTable,
1274                                &classTable_length,
1275                                stateSize,
1276                                &maxClassID,
1277                                valid );
1278     else
1279       maxClassID = (FT_Byte)( stateSize - 1 );
1280
1281     if ( stateArray != 0 )
1282       gxv_StateArray_validate( table + stateArray,
1283                                &stateArray_length,
1284                                maxClassID,
1285                                stateSize,
1286                                &maxState,
1287                                &maxEntry,
1288                                valid );
1289     else
1290     {
1291       maxState = 1;     /* 0:start of text, 1:start of line are predefined */
1292       maxEntry = 0;
1293     }
1294
1295     if ( maxEntry > 0 && entryTable == 0 )
1296       FT_INVALID_OFFSET;
1297
1298     if ( entryTable != 0 )
1299       gxv_EntryTable_validate( table + entryTable,
1300                                &entryTable_length,
1301                                maxEntry,
1302                                stateArray,
1303                                stateArray_length,
1304                                maxClassID,
1305                                table,
1306                                limit,
1307                                valid );
1308
1309     GXV_EXIT;
1310   }
1311
1312
1313   /* ================= eXtended State Table (for morx) =================== */
1314
1315   FT_LOCAL_DEF( void )
1316   gxv_XStateTable_subtable_setup( FT_ULong       table_size,
1317                                   FT_ULong       classTable,
1318                                   FT_ULong       stateArray,
1319                                   FT_ULong       entryTable,
1320                                   FT_ULong*      classTable_length_p,
1321                                   FT_ULong*      stateArray_length_p,
1322                                   FT_ULong*      entryTable_length_p,
1323                                   GXV_Validator  valid )
1324   {
1325     FT_ULong   o[3];
1326     FT_ULong*  l[3];
1327     FT_ULong   buff[4];
1328
1329
1330     o[0] = classTable;
1331     o[1] = stateArray;
1332     o[2] = entryTable;
1333     l[0] = classTable_length_p;
1334     l[1] = stateArray_length_p;
1335     l[2] = entryTable_length_p;
1336
1337     gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, valid );
1338   }
1339
1340
1341   static void
1342   gxv_XClassTable_lookupval_validate( FT_UShort            glyph,
1343                                       GXV_LookupValueCPtr  value_p,
1344                                       GXV_Validator        valid )
1345   {
1346     FT_UNUSED( glyph );
1347
1348     if ( value_p->u >= valid->xstatetable.nClasses )
1349       FT_INVALID_DATA;
1350     if ( value_p->u > valid->xstatetable.maxClassID )
1351       valid->xstatetable.maxClassID = value_p->u;
1352   }
1353
1354
1355   /*
1356     +===============+ --------+
1357     | lookup header |         |
1358     +===============+         |
1359     | BinSrchHeader |         |
1360     +===============+         |
1361     | lastGlyph[0]  |         |
1362     +---------------+         |
1363     | firstGlyph[0] |         |    head of lookup table
1364     +---------------+         |             +
1365     | offset[0]     |    ->   |          offset            [byte]
1366     +===============+         |             +
1367     | lastGlyph[1]  |         | (glyphID - firstGlyph) * 2 [byte]
1368     +---------------+         |
1369     | firstGlyph[1] |         |
1370     +---------------+         |
1371     | offset[1]     |         |
1372     +===============+         |
1373                               |
1374      ....                     |
1375                               |
1376     16bit value array         |
1377     +===============+         |
1378     |     value     | <-------+
1379      ....
1380   */
1381   static GXV_LookupValueDesc
1382   gxv_XClassTable_lookupfmt4_transit( FT_UShort            relative_gindex,
1383                                       GXV_LookupValueCPtr  base_value_p,
1384                                       FT_Bytes             lookuptbl_limit,
1385                                       GXV_Validator        valid )
1386   {
1387     FT_Bytes             p;
1388     FT_Bytes             limit;
1389     FT_UShort            offset;
1390     GXV_LookupValueDesc  value;
1391
1392     /* XXX: check range? */
1393     offset = (FT_UShort)( base_value_p->u +
1394                           relative_gindex * sizeof ( FT_UShort ) );
1395
1396     p     = valid->lookuptbl_head + offset;
1397     limit = lookuptbl_limit;
1398
1399     GXV_LIMIT_CHECK ( 2 );
1400     value.u = FT_NEXT_USHORT( p );
1401
1402     return value;
1403   }
1404
1405
1406   static void
1407   gxv_XStateArray_validate( FT_Bytes       table,
1408                             FT_ULong*      length_p,
1409                             FT_UShort      maxClassID,
1410                             FT_ULong       stateSize,
1411                             FT_UShort*     maxState_p,
1412                             FT_UShort*     maxEntry_p,
1413                             GXV_Validator  valid )
1414   {
1415     FT_Bytes   p = table;
1416     FT_Bytes   limit = table + *length_p;
1417     FT_UShort  clazz;
1418     FT_UShort  entry;
1419
1420     FT_UNUSED( stateSize ); /* for the non-debugging case */
1421
1422
1423     GXV_NAME_ENTER( "XStateArray" );
1424
1425     GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
1426                 (int)(*length_p), stateSize, (int)(maxClassID) ));
1427
1428     /*
1429      * 2 states are predefined and must be described:
1430      * state 0 (start of text), 1 (start of line)
1431      */
1432     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
1433
1434     *maxState_p = 0;
1435     *maxEntry_p = 0;
1436
1437     /* read if enough to read another state */
1438     while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
1439     {
1440       (*maxState_p)++;
1441       for ( clazz = 0; clazz <= maxClassID; clazz++ )
1442       {
1443         entry = FT_NEXT_USHORT( p );
1444         *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry );
1445       }
1446     }
1447     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
1448                 *maxState_p, *maxEntry_p ));
1449
1450     *length_p = p - table;
1451
1452     GXV_EXIT;
1453   }
1454
1455
1456   static void
1457   gxv_XEntryTable_validate( FT_Bytes       table,
1458                             FT_ULong*      length_p,
1459                             FT_UShort      maxEntry,
1460                             FT_ULong       stateArray_length,
1461                             FT_UShort      maxClassID,
1462                             FT_Bytes       xstatetable_table,
1463                             FT_Bytes       xstatetable_limit,
1464                             GXV_Validator  valid )
1465   {
1466     FT_Bytes   p = table;
1467     FT_Bytes   limit = table + *length_p;
1468     FT_UShort  entry;
1469     FT_UShort  state;
1470     FT_Int     entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
1471
1472
1473     GXV_NAME_ENTER( "XEntryTable" );
1474     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
1475
1476     if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
1477       FT_INVALID_TOO_SHORT;
1478
1479     for (entry = 0; entry <= maxEntry ; entry++ )
1480     {
1481       FT_UShort                        newState_idx;
1482       FT_UShort                        flags;
1483       GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
1484
1485
1486       GXV_LIMIT_CHECK( 2 + 2 );
1487       newState_idx = FT_NEXT_USHORT( p );
1488       flags        = FT_NEXT_USHORT( p );
1489
1490       if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) )
1491       {
1492         GXV_TRACE(( "  newState index 0x%04x points out of stateArray\n",
1493                     newState_idx ));
1494         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1495       }
1496
1497       state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) );
1498       if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
1499       {
1500         FT_TRACE4(( "-> new state = %d (supposed)\n"
1501                     "but newState index 0x%04x is not aligned to %d-classes\n",
1502                     state, newState_idx,  1 + maxClassID ));
1503         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
1504       }
1505
1506       switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
1507       {
1508       case GXV_GLYPHOFFSET_NONE:
1509         glyphOffset.uc = 0; /* make compiler happy */
1510         break;
1511
1512       case GXV_GLYPHOFFSET_UCHAR:
1513         glyphOffset.uc = FT_NEXT_BYTE( p );
1514         break;
1515
1516       case GXV_GLYPHOFFSET_CHAR:
1517         glyphOffset.c = FT_NEXT_CHAR( p );
1518         break;
1519
1520       case GXV_GLYPHOFFSET_USHORT:
1521         glyphOffset.u = FT_NEXT_USHORT( p );
1522         break;
1523
1524       case GXV_GLYPHOFFSET_SHORT:
1525         glyphOffset.s = FT_NEXT_SHORT( p );
1526         break;
1527
1528       case GXV_GLYPHOFFSET_ULONG:
1529         glyphOffset.ul = FT_NEXT_ULONG( p );
1530         break;
1531
1532       case GXV_GLYPHOFFSET_LONG:
1533         glyphOffset.l = FT_NEXT_LONG( p );
1534         break;
1535
1536       default:
1537         GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT );
1538         goto Exit;
1539       }
1540
1541       if ( NULL != valid->xstatetable.entry_validate_func )
1542         valid->xstatetable.entry_validate_func( state,
1543                                                 flags,
1544                                                 &glyphOffset,
1545                                                 xstatetable_table,
1546                                                 xstatetable_limit,
1547                                                 valid );
1548     }
1549
1550   Exit:
1551     *length_p = p - table;
1552
1553     GXV_EXIT;
1554   }
1555
1556
1557   FT_LOCAL_DEF( void )
1558   gxv_XStateTable_validate( FT_Bytes       table,
1559                             FT_Bytes       limit,
1560                             GXV_Validator  valid )
1561   {
1562     /* StateHeader members */
1563     FT_ULong   classTable;      /* offset to Class(Sub)Table */
1564     FT_ULong   stateArray;      /* offset to StateArray */
1565     FT_ULong   entryTable;      /* offset to EntryTable */
1566
1567     FT_ULong   classTable_length;
1568     FT_ULong   stateArray_length;
1569     FT_ULong   entryTable_length;
1570     FT_UShort  maxState;
1571     FT_UShort  maxEntry;
1572
1573     GXV_XStateTable_Subtable_Setup_Func  setup_func;
1574
1575     FT_Bytes   p = table;
1576
1577
1578     GXV_NAME_ENTER( "XStateTable" );
1579
1580     GXV_TRACE(( "XStateTable header\n" ));
1581
1582     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
1583     valid->xstatetable.nClasses = FT_NEXT_ULONG( p );
1584     classTable = FT_NEXT_ULONG( p );
1585     stateArray = FT_NEXT_ULONG( p );
1586     entryTable = FT_NEXT_ULONG( p );
1587
1588     GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses ));
1589     GXV_TRACE(( "offset to classTable=0x%08x\n", classTable ));
1590     GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray ));
1591     GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable ));
1592
1593     if ( valid->xstatetable.nClasses > 0xFFFFU )
1594       FT_INVALID_DATA;
1595
1596     GXV_TRACE(( "StateTable Subtables\n" ));
1597
1598     if ( valid->xstatetable.optdata_load_func != NULL )
1599       valid->xstatetable.optdata_load_func( p, limit, valid );
1600
1601     if ( valid->xstatetable.subtable_setup_func != NULL )
1602       setup_func = valid->xstatetable.subtable_setup_func;
1603     else
1604       setup_func = gxv_XStateTable_subtable_setup;
1605
1606     setup_func( limit - table,
1607                 classTable,
1608                 stateArray,
1609                 entryTable,
1610                 &classTable_length,
1611                 &stateArray_length,
1612                 &entryTable_length,
1613                 valid );
1614
1615     if ( classTable != 0 )
1616     {
1617       valid->xstatetable.maxClassID = 0;
1618       valid->lookupval_sign         = GXV_LOOKUPVALUE_UNSIGNED;
1619       valid->lookupval_func         = gxv_XClassTable_lookupval_validate;
1620       valid->lookupfmt4_trans       = gxv_XClassTable_lookupfmt4_transit;
1621       gxv_LookupTable_validate( table + classTable,
1622                                 table + classTable + classTable_length,
1623                                 valid );
1624       if ( valid->subtable_length < classTable_length )
1625         classTable_length = valid->subtable_length;
1626     }
1627     else
1628     {
1629       /* XXX: check range? */
1630       valid->xstatetable.maxClassID =
1631         (FT_UShort)( valid->xstatetable.nClasses - 1 );
1632     }
1633
1634     if ( stateArray != 0 )
1635       gxv_XStateArray_validate( table + stateArray,
1636                                 &stateArray_length,
1637                                 valid->xstatetable.maxClassID,
1638                                 valid->xstatetable.nClasses,
1639                                 &maxState,
1640                                 &maxEntry,
1641                                 valid );
1642     else
1643     {
1644       maxState = 1; /* 0:start of text, 1:start of line are predefined */
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                                 valid->xstatetable.maxClassID,
1657                                 table,
1658                                 limit,
1659                                 valid );
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     valid )
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           if ( odtect->range[i].name || odtect->range[j].name )
1731             GXV_TRACE(( "found overlap between range %d and range %d\n",
1732                         i, j ));
1733           else
1734             GXV_TRACE(( "found overlap between `%s' and `%s\'\n",
1735                         odtect->range[i].name,
1736                         odtect->range[j].name ));
1737           FT_INVALID_OFFSET;
1738         }
1739
1740     GXV_EXIT;
1741   }
1742
1743
1744 /* END */