Home | History | Annotate | Download | only in gxvalid
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  gxvcommn.c                                                             */
      4 /*                                                                         */
      5 /*    TrueTypeGX/AAT common tables validation (body).                      */
      6 /*                                                                         */
      7 /*  Copyright 2004-2018 by                                                 */
      8 /*  suzuki toshiya, Masatake YAMATO, Red Hat K.K.,                         */
      9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
     10 /*                                                                         */
     11 /*  This file is part of the FreeType project, and may only be used,       */
     12 /*  modified, and distributed under the terms of the FreeType project      */
     13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     14 /*  this file you indicate that you have read the license and              */
     15 /*  understand and accept it fully.                                        */
     16 /*                                                                         */
     17 /***************************************************************************/
     18 
     19 /***************************************************************************/
     20 /*                                                                         */
     21 /* gxvalid is derived from both gxlayout module and otvalid module.        */
     22 /* Development of gxlayout is supported by the Information-technology      */
     23 /* Promotion Agency(IPA), Japan.                                           */
     24 /*                                                                         */
     25 /***************************************************************************/
     26 
     27 
     28 #include "gxvcommn.h"
     29 
     30 
     31   /*************************************************************************/
     32   /*                                                                       */
     33   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     34   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     35   /* messages during execution.                                            */
     36   /*                                                                       */
     37 #undef  FT_COMPONENT
     38 #define FT_COMPONENT  trace_gxvcommon
     39 
     40 
     41   /*************************************************************************/
     42   /*************************************************************************/
     43   /*****                                                               *****/
     44   /*****                       16bit offset sorter                     *****/
     45   /*****                                                               *****/
     46   /*************************************************************************/
     47   /*************************************************************************/
     48 
     49   static int
     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 (at) 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                          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  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 (at) 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 (at) 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 */
   1747