gxvcommn.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  gxvcommn.c                                                             */
00004 /*                                                                         */
00005 /*    TrueTypeGX/AAT common tables validation (body).                      */
00006 /*                                                                         */
00007 /*  Copyright 2004, 2005, 2009                                             */
00008 /*  by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,                      */
00009 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00010 /*                                                                         */
00011 /*  This file is part of the FreeType project, and may only be used,       */
00012 /*  modified, and distributed under the terms of the FreeType project      */
00013 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00014 /*  this file you indicate that you have read the license and              */
00015 /*  understand and accept it fully.                                        */
00016 /*                                                                         */
00017 /***************************************************************************/
00018 
00019 /***************************************************************************/
00020 /*                                                                         */
00021 /* gxvalid is derived from both gxlayout module and otvalid module.        */
00022 /* Development of gxlayout is supported by the Information-technology      */
00023 /* Promotion Agency(IPA), Japan.                                           */
00024 /*                                                                         */
00025 /***************************************************************************/
00026 
00027 
00028 #include "gxvcommn.h"
00029 
00030 
00031   /*************************************************************************/
00032   /*                                                                       */
00033   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00034   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00035   /* messages during execution.                                            */
00036   /*                                                                       */
00037 #undef  FT_COMPONENT
00038 #define FT_COMPONENT  trace_gxvcommon
00039 
00040 
00041   /*************************************************************************/
00042   /*************************************************************************/
00043   /*****                                                               *****/
00044   /*****                       16bit offset sorter                     *****/
00045   /*****                                                               *****/
00046   /*************************************************************************/
00047   /*************************************************************************/
00048 
00049   static int
00050   gxv_compare_ushort_offset( FT_UShort*  a,
00051                              FT_UShort*  b )
00052   {
00053     if ( *a < *b )
00054       return -1;
00055     else if ( *a > *b )
00056       return 1;
00057     else
00058       return 0;
00059   }
00060 
00061 
00062   FT_LOCAL_DEF( void )
00063   gxv_set_length_by_ushort_offset( FT_UShort*     offset,
00064                                    FT_UShort**    length,
00065                                    FT_UShort*     buff,
00066                                    FT_UInt        nmemb,
00067                                    FT_UShort      limit,
00068                                    GXV_Validator  valid )
00069   {
00070     FT_UInt  i;
00071 
00072 
00073     for ( i = 0; i < nmemb; i++ )
00074       *(length[i]) = 0;
00075 
00076     for ( i = 0; i < nmemb; i++ )
00077       buff[i] = offset[i];
00078     buff[nmemb] = limit;
00079 
00080     ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ),
00081               ( int(*)(const void*, const void*) )gxv_compare_ushort_offset );
00082 
00083     if ( buff[nmemb] > limit )
00084       FT_INVALID_OFFSET;
00085 
00086     for ( i = 0; i < nmemb; i++ )
00087     {
00088       FT_UInt  j;
00089 
00090 
00091       for ( j = 0; j < nmemb; j++ )
00092         if ( buff[j] == offset[i] )
00093           break;
00094 
00095       if ( j == nmemb )
00096         FT_INVALID_OFFSET;
00097 
00098       *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] );
00099 
00100       if ( 0 != offset[i] && 0 == *(length[i]) )
00101         FT_INVALID_OFFSET;
00102     }
00103   }
00104 
00105 
00106   /*************************************************************************/
00107   /*************************************************************************/
00108   /*****                                                               *****/
00109   /*****                       32bit offset sorter                     *****/
00110   /*****                                                               *****/
00111   /*************************************************************************/
00112   /*************************************************************************/
00113 
00114   static int
00115   gxv_compare_ulong_offset( FT_ULong*  a,
00116                             FT_ULong*  b )
00117   {
00118     if ( *a < *b )
00119       return -1;
00120     else if ( *a > *b )
00121       return 1;
00122     else
00123       return 0;
00124   }
00125 
00126 
00127   FT_LOCAL_DEF( void )
00128   gxv_set_length_by_ulong_offset( FT_ULong*      offset,
00129                                   FT_ULong**     length,
00130                                   FT_ULong*      buff,
00131                                   FT_UInt        nmemb,
00132                                   FT_ULong       limit,
00133                                   GXV_Validator  valid)
00134   {
00135     FT_UInt  i;
00136 
00137 
00138     for ( i = 0; i < nmemb; i++ )
00139       *(length[i]) = 0;
00140 
00141     for ( i = 0; i < nmemb; i++ )
00142       buff[i] = offset[i];
00143     buff[nmemb] = limit;
00144 
00145     ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ),
00146               ( int(*)(const void*, const void*) )gxv_compare_ulong_offset );
00147 
00148     if ( buff[nmemb] > limit )
00149       FT_INVALID_OFFSET;
00150 
00151     for ( i = 0; i < nmemb; i++ )
00152     {
00153       FT_UInt  j;
00154 
00155 
00156       for ( j = 0; j < nmemb; j++ )
00157         if ( buff[j] == offset[i] )
00158           break;
00159 
00160       if ( j == nmemb )
00161         FT_INVALID_OFFSET;
00162 
00163       *(length[i]) = buff[j + 1] - buff[j];
00164 
00165       if ( 0 != offset[i] && 0 == *(length[i]) )
00166         FT_INVALID_OFFSET;
00167     }
00168   }
00169 
00170 
00171   /*************************************************************************/
00172   /*************************************************************************/
00173   /*****                                                               *****/
00174   /*****               scan value array and get min & max              *****/
00175   /*****                                                               *****/
00176   /*************************************************************************/
00177   /*************************************************************************/
00178 
00179 
00180   FT_LOCAL_DEF( void )
00181   gxv_array_getlimits_byte( FT_Bytes       table,
00182                             FT_Bytes       limit,
00183                             FT_Byte*       min,
00184                             FT_Byte*       max,
00185                             GXV_Validator  valid )
00186   {
00187     FT_Bytes  p = table;
00188 
00189 
00190     *min = 0xFF;
00191     *max = 0x00;
00192 
00193     while ( p < limit )
00194     {
00195       FT_Byte  val;
00196 
00197 
00198       GXV_LIMIT_CHECK( 1 );
00199       val = FT_NEXT_BYTE( p );
00200 
00201       *min = (FT_Byte)FT_MIN( *min, val );
00202       *max = (FT_Byte)FT_MAX( *max, val );
00203     }
00204 
00205     valid->subtable_length = p - table;
00206   }
00207 
00208 
00209   FT_LOCAL_DEF( void )
00210   gxv_array_getlimits_ushort( FT_Bytes       table,
00211                               FT_Bytes       limit,
00212                               FT_UShort*     min,
00213                               FT_UShort*     max,
00214                               GXV_Validator  valid )
00215   {
00216     FT_Bytes  p = table;
00217 
00218 
00219     *min = 0xFFFFU;
00220     *max = 0x0000;
00221 
00222     while ( p < limit )
00223     {
00224       FT_UShort  val;
00225 
00226 
00227       GXV_LIMIT_CHECK( 2 );
00228       val = FT_NEXT_USHORT( p );
00229 
00230       *min = (FT_Byte)FT_MIN( *min, val );
00231       *max = (FT_Byte)FT_MAX( *max, val );
00232     }
00233 
00234     valid->subtable_length = p - table;
00235   }
00236 
00237 
00238   /*************************************************************************/
00239   /*************************************************************************/
00240   /*****                                                               *****/
00241   /*****                       BINSEARCHHEADER                         *****/
00242   /*****                                                               *****/
00243   /*************************************************************************/
00244   /*************************************************************************/
00245 
00246   typedef struct  GXV_BinSrchHeader_
00247   {
00248     FT_UShort  unitSize;
00249     FT_UShort  nUnits;
00250     FT_UShort  searchRange;
00251     FT_UShort  entrySelector;
00252     FT_UShort  rangeShift;
00253 
00254   } GXV_BinSrchHeader;
00255 
00256 
00257   static void
00258   gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader*  binSrchHeader,
00259                                        GXV_Validator       valid )
00260   {
00261     FT_UShort  searchRange;
00262     FT_UShort  entrySelector;
00263     FT_UShort  rangeShift;
00264 
00265 
00266     if ( binSrchHeader->unitSize == 0 )
00267       FT_INVALID_DATA;
00268 
00269     if ( binSrchHeader->nUnits == 0 )
00270     {
00271       if ( binSrchHeader->searchRange   == 0 &&
00272            binSrchHeader->entrySelector == 0 &&
00273            binSrchHeader->rangeShift    == 0 )
00274         return;
00275       else
00276         FT_INVALID_DATA;
00277     }
00278 
00279     for ( searchRange = 1, entrySelector = 1;
00280           ( searchRange * 2 ) <= binSrchHeader->nUnits &&
00281             searchRange < 0x8000U;
00282           searchRange *= 2, entrySelector++ )
00283       ;
00284 
00285     entrySelector--;
00286     searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize );
00287     rangeShift  = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize
00288                                - searchRange );
00289 
00290     if ( searchRange   != binSrchHeader->searchRange   ||
00291          entrySelector != binSrchHeader->entrySelector ||
00292          rangeShift    != binSrchHeader->rangeShift    )
00293     {
00294       GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" ));
00295       GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, "
00296                   "searchRange=%d, entrySelector=%d, "
00297                   "rangeShift=%d\n",
00298                   binSrchHeader->unitSize, binSrchHeader->nUnits,
00299                   binSrchHeader->searchRange, binSrchHeader->entrySelector,
00300                   binSrchHeader->rangeShift ));
00301       GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, "
00302                   "searchRange=%d, entrySelector=%d, "
00303                   "rangeShift=%d\n",
00304                   binSrchHeader->unitSize, binSrchHeader->nUnits,
00305                   searchRange, entrySelector, rangeShift ));
00306 
00307       if ( valid->root->level >= FT_VALIDATE_PARANOID )
00308         FT_INVALID_DATA;
00309     }
00310   }
00311 
00312 
00313   /*
00314    * parser & validator of BinSrchHeader
00315    * which is used in LookupTable format 2, 4, 6.
00316    *
00317    * Essential parameters (unitSize, nUnits) are returned by
00318    * given pointer, others (searchRange, entrySelector, rangeShift)
00319    * can be calculated by essential parameters, so they are just
00320    * validated and discarded.
00321    *
00322    * However, wrong values in searchRange, entrySelector, rangeShift
00323    * won't cause fatal errors, because these parameters might be
00324    * only used in old m68k font driver in MacOS.
00325    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
00326    */
00327 
00328   FT_LOCAL_DEF( void )
00329   gxv_BinSrchHeader_validate( FT_Bytes       table,
00330                               FT_Bytes       limit,
00331                               FT_UShort*     unitSize_p,
00332                               FT_UShort*     nUnits_p,
00333                               GXV_Validator  valid )
00334   {
00335     FT_Bytes           p = table;
00336     GXV_BinSrchHeader  binSrchHeader;
00337 
00338 
00339     GXV_NAME_ENTER( "BinSrchHeader validate" );
00340 
00341     if ( *unitSize_p == 0 )
00342     {
00343       GXV_LIMIT_CHECK( 2 );
00344       binSrchHeader.unitSize =  FT_NEXT_USHORT( p );
00345     }
00346     else
00347       binSrchHeader.unitSize = *unitSize_p;
00348 
00349     if ( *nUnits_p == 0 )
00350     {
00351       GXV_LIMIT_CHECK( 2 );
00352       binSrchHeader.nUnits = FT_NEXT_USHORT( p );
00353     }
00354     else
00355       binSrchHeader.nUnits = *nUnits_p;
00356 
00357     GXV_LIMIT_CHECK( 2 + 2 + 2 );
00358     binSrchHeader.searchRange   = FT_NEXT_USHORT( p );
00359     binSrchHeader.entrySelector = FT_NEXT_USHORT( p );
00360     binSrchHeader.rangeShift    = FT_NEXT_USHORT( p );
00361     GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits ));
00362 
00363     gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid );
00364 
00365     if ( *unitSize_p == 0 )
00366       *unitSize_p = binSrchHeader.unitSize;
00367 
00368     if ( *nUnits_p == 0 )
00369       *nUnits_p = binSrchHeader.nUnits;
00370 
00371     valid->subtable_length = p - table;
00372     GXV_EXIT;
00373   }
00374 
00375 
00376   /*************************************************************************/
00377   /*************************************************************************/
00378   /*****                                                               *****/
00379   /*****                         LOOKUP TABLE                          *****/
00380   /*****                                                               *****/
00381   /*************************************************************************/
00382   /*************************************************************************/
00383 
00384 #define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC )                   \
00385           ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) )
00386 
00387   static GXV_LookupValueDesc
00388   gxv_lookup_value_load( FT_Bytes  p,
00389                          int       signspec )
00390   {
00391     GXV_LookupValueDesc  v;
00392 
00393 
00394     if ( signspec == GXV_LOOKUPVALUE_UNSIGNED )
00395       v.u = FT_NEXT_USHORT( p );
00396     else
00397       v.s = FT_NEXT_SHORT( p );
00398 
00399     return v;
00400   }
00401 
00402 
00403 #define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \
00404           FT_BEGIN_STMNT                                               \
00405             if ( UNITSIZE != CORRECTSIZE )                             \
00406             {                                                          \
00407               FT_ERROR(( "unitSize=%d differs from"                    \
00408                          " expected unitSize=%d"                       \
00409                          " in LookupTable %s\n",                       \
00410                           UNITSIZE, CORRECTSIZE, FORMAT ));            \
00411               if ( UNITSIZE != 0 && NUNITS != 0 )                      \
00412               {                                                        \
00413                 FT_ERROR(( " cannot validate anymore\n" ));            \
00414                 FT_INVALID_FORMAT;                                     \
00415               }                                                        \
00416               else                                                     \
00417                 FT_ERROR(( " forcibly continues\n" ));                 \
00418             }                                                          \
00419           FT_END_STMNT
00420 
00421 
00422   /* ================= Simple Array Format 0 Lookup Table ================ */
00423   static void
00424   gxv_LookupTable_fmt0_validate( FT_Bytes       table,
00425                                  FT_Bytes       limit,
00426                                  GXV_Validator  valid )
00427   {
00428     FT_Bytes   p = table;
00429     FT_UShort  i;
00430 
00431     GXV_LookupValueDesc  value;
00432 
00433 
00434     GXV_NAME_ENTER( "LookupTable format 0" );
00435 
00436     GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs );
00437 
00438     for ( i = 0; i < valid->face->num_glyphs; i++ )
00439     {
00440       GXV_LIMIT_CHECK( 2 );
00441       if ( p + 2 >= limit )     /* some fonts have too-short fmt0 array */
00442       {
00443         GXV_TRACE(( "too short, glyphs %d - %d are missing\n",
00444                     i, valid->face->num_glyphs ));
00445         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00446           FT_INVALID_GLYPH_ID;
00447         break;
00448       }
00449 
00450       value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00451       valid->lookupval_func( i, &value, valid );
00452     }
00453 
00454     valid->subtable_length = p - table;
00455     GXV_EXIT;
00456   }
00457 
00458 
00459   /* ================= Segment Single Format 2 Loolup Table ============== */
00460   /*
00461    * Apple spec says:
00462    *
00463    *   To guarantee that a binary search terminates, you must include one or
00464    *   more special `end of search table' values at the end of the data to
00465    *   be searched.  The number of termination values that need to be
00466    *   included is table-specific.  The value that indicates binary search
00467    *   termination is 0xFFFF.
00468    *
00469    * The problem is that nUnits does not include this end-marker.  It's
00470    * quite difficult to discriminate whether the following 0xFFFF comes from
00471    * the end-marker or some next data.
00472    *
00473    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
00474    */
00475   static void
00476   gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes       table,
00477                                         FT_UShort      unitSize,
00478                                         GXV_Validator  valid )
00479   {
00480     FT_Bytes  p = table;
00481 
00482 
00483     while ( ( p + 4 ) < valid->root->limit )
00484     {
00485       if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */
00486            p[2] != 0xFF || p[3] != 0xFF )  /* firstGlyph */
00487         break;
00488       p += unitSize;
00489     }
00490 
00491     valid->subtable_length = p - table;
00492   }
00493 
00494 
00495   static void
00496   gxv_LookupTable_fmt2_validate( FT_Bytes       table,
00497                                  FT_Bytes       limit,
00498                                  GXV_Validator  valid )
00499   {
00500     FT_Bytes             p = table;
00501     FT_UShort            gid;
00502 
00503     FT_UShort            unitSize;
00504     FT_UShort            nUnits;
00505     FT_UShort            unit;
00506     FT_UShort            lastGlyph;
00507     FT_UShort            firstGlyph;
00508     GXV_LookupValueDesc  value;
00509 
00510 
00511     GXV_NAME_ENTER( "LookupTable format 2" );
00512 
00513     unitSize = nUnits = 0;
00514     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00515     p += valid->subtable_length;
00516 
00517     GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 );
00518 
00519     for ( unit = 0, gid = 0; unit < nUnits; unit++ )
00520     {
00521       GXV_LIMIT_CHECK( 2 + 2 + 2 );
00522       lastGlyph  = FT_NEXT_USHORT( p );
00523       firstGlyph = FT_NEXT_USHORT( p );
00524       value      = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00525 
00526       gxv_glyphid_validate( firstGlyph, valid );
00527       gxv_glyphid_validate( lastGlyph, valid );
00528 
00529       if ( lastGlyph < gid )
00530       {
00531         GXV_TRACE(( "reverse ordered segment specification:"
00532                     " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
00533                     unit, lastGlyph, unit - 1 , gid ));
00534         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00535           FT_INVALID_GLYPH_ID;
00536       }
00537 
00538       if ( lastGlyph < firstGlyph )
00539       {
00540         GXV_TRACE(( "reverse ordered range specification at unit %d:",
00541                     " lastGlyph %d < firstGlyph %d ",
00542                     unit, lastGlyph, firstGlyph ));
00543         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00544           FT_INVALID_GLYPH_ID;
00545 
00546         if ( valid->root->level == FT_VALIDATE_TIGHT )
00547           continue;     /* ftxvalidator silently skips such an entry */
00548 
00549         FT_TRACE4(( "continuing with exchanged values\n" ));
00550         gid        = firstGlyph;
00551         firstGlyph = lastGlyph;
00552         lastGlyph  = gid;
00553       }
00554 
00555       for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
00556         valid->lookupval_func( gid, &value, valid );
00557     }
00558 
00559     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
00560     p += valid->subtable_length;
00561 
00562     valid->subtable_length = p - table;
00563     GXV_EXIT;
00564   }
00565 
00566 
00567   /* ================= Segment Array Format 4 Lookup Table =============== */
00568   static void
00569   gxv_LookupTable_fmt4_validate( FT_Bytes       table,
00570                                  FT_Bytes       limit,
00571                                  GXV_Validator  valid )
00572   {
00573     FT_Bytes             p = table;
00574     FT_UShort            unit;
00575     FT_UShort            gid;
00576 
00577     FT_UShort            unitSize;
00578     FT_UShort            nUnits;
00579     FT_UShort            lastGlyph;
00580     FT_UShort            firstGlyph;
00581     GXV_LookupValueDesc  base_value;
00582     GXV_LookupValueDesc  value;
00583 
00584 
00585     GXV_NAME_ENTER( "LookupTable format 4" );
00586 
00587     unitSize = nUnits = 0;
00588     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00589     p += valid->subtable_length;
00590 
00591     GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 );
00592 
00593     for ( unit = 0, gid = 0; unit < nUnits; unit++ )
00594     {
00595       GXV_LIMIT_CHECK( 2 + 2 );
00596       lastGlyph  = FT_NEXT_USHORT( p );
00597       firstGlyph = FT_NEXT_USHORT( p );
00598 
00599       gxv_glyphid_validate( firstGlyph, valid );
00600       gxv_glyphid_validate( lastGlyph, valid );
00601 
00602       if ( lastGlyph < gid )
00603       {
00604         GXV_TRACE(( "reverse ordered segment specification:"
00605                     " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
00606                     unit, lastGlyph, unit - 1 , gid ));
00607         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00608           FT_INVALID_GLYPH_ID;
00609       }
00610 
00611       if ( lastGlyph < firstGlyph )
00612       {
00613         GXV_TRACE(( "reverse ordered range specification at unit %d:",
00614                     " lastGlyph %d < firstGlyph %d ",
00615                     unit, lastGlyph, firstGlyph ));
00616         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00617           FT_INVALID_GLYPH_ID;
00618 
00619         if ( valid->root->level == FT_VALIDATE_TIGHT )
00620           continue; /* ftxvalidator silently skips such an entry */
00621 
00622         FT_TRACE4(( "continuing with exchanged values\n" ));
00623         gid        = firstGlyph;
00624         firstGlyph = lastGlyph;
00625         lastGlyph  = gid;
00626       }
00627 
00628       GXV_LIMIT_CHECK( 2 );
00629       base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED );
00630 
00631       for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
00632       {
00633         value = valid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ),
00634                                          &base_value,
00635                                          limit,
00636                                          valid );
00637 
00638         valid->lookupval_func( gid, &value, valid );
00639       }
00640     }
00641 
00642     gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
00643     p += valid->subtable_length;
00644 
00645     valid->subtable_length = p - table;
00646     GXV_EXIT;
00647   }
00648 
00649 
00650   /* ================= Segment Table Format 6 Lookup Table =============== */
00651   static void
00652   gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes       table,
00653                                         FT_UShort      unitSize,
00654                                         GXV_Validator  valid )
00655   {
00656     FT_Bytes  p = table;
00657 
00658 
00659     while ( p < valid->root->limit )
00660     {
00661       if ( p[0] != 0xFF || p[1] != 0xFF )
00662         break;
00663       p += unitSize;
00664     }
00665 
00666     valid->subtable_length = p - table;
00667   }
00668 
00669 
00670   static void
00671   gxv_LookupTable_fmt6_validate( FT_Bytes       table,
00672                                  FT_Bytes       limit,
00673                                  GXV_Validator  valid )
00674   {
00675     FT_Bytes             p = table;
00676     FT_UShort            unit;
00677     FT_UShort            prev_glyph;
00678 
00679     FT_UShort            unitSize;
00680     FT_UShort            nUnits;
00681     FT_UShort            glyph;
00682     GXV_LookupValueDesc  value;
00683 
00684 
00685     GXV_NAME_ENTER( "LookupTable format 6" );
00686 
00687     unitSize = nUnits = 0;
00688     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
00689     p += valid->subtable_length;
00690 
00691     GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 );
00692 
00693     for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ )
00694     {
00695       GXV_LIMIT_CHECK( 2 + 2 );
00696       glyph = FT_NEXT_USHORT( p );
00697       value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00698 
00699       if ( gxv_glyphid_validate( glyph, valid ) )
00700         GXV_TRACE(( " endmarker found within defined range"
00701                     " (entry %d < nUnits=%d)\n",
00702                     unit, nUnits ));
00703 
00704       if ( prev_glyph > glyph )
00705       {
00706         GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n",
00707                     glyph, prev_glyph ));
00708         if ( valid->root->level >= FT_VALIDATE_PARANOID )
00709           FT_INVALID_GLYPH_ID;
00710       }
00711       prev_glyph = glyph;
00712 
00713       valid->lookupval_func( glyph, &value, valid );
00714     }
00715 
00716     gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid );
00717     p += valid->subtable_length;
00718 
00719     valid->subtable_length = p - table;
00720     GXV_EXIT;
00721   }
00722 
00723 
00724   /* ================= Trimmed Array Format 8 Lookup Table =============== */
00725   static void
00726   gxv_LookupTable_fmt8_validate( FT_Bytes       table,
00727                                  FT_Bytes       limit,
00728                                  GXV_Validator  valid )
00729   {
00730     FT_Bytes              p = table;
00731     FT_UShort             i;
00732 
00733     GXV_LookupValueDesc   value;
00734     FT_UShort             firstGlyph;
00735     FT_UShort             glyphCount;
00736 
00737 
00738     GXV_NAME_ENTER( "LookupTable format 8" );
00739 
00740     /* firstGlyph + glyphCount */
00741     GXV_LIMIT_CHECK( 2 + 2 );
00742     firstGlyph = FT_NEXT_USHORT( p );
00743     glyphCount = FT_NEXT_USHORT( p );
00744 
00745     gxv_glyphid_validate( firstGlyph, valid );
00746     gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), valid );
00747 
00748     /* valueArray */
00749     for ( i = 0; i < glyphCount; i++ )
00750     {
00751       GXV_LIMIT_CHECK( 2 );
00752       value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
00753       valid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, valid );
00754     }
00755 
00756     valid->subtable_length = p - table;
00757     GXV_EXIT;
00758   }
00759 
00760 
00761   FT_LOCAL_DEF( void )
00762   gxv_LookupTable_validate( FT_Bytes       table,
00763                             FT_Bytes       limit,
00764                             GXV_Validator  valid )
00765   {
00766     FT_Bytes   p = table;
00767     FT_UShort  format;
00768 
00769     GXV_Validate_Func  fmt_funcs_table[] =
00770     {
00771       gxv_LookupTable_fmt0_validate, /* 0 */
00772       NULL,                          /* 1 */
00773       gxv_LookupTable_fmt2_validate, /* 2 */
00774       NULL,                          /* 3 */
00775       gxv_LookupTable_fmt4_validate, /* 4 */
00776       NULL,                          /* 5 */
00777       gxv_LookupTable_fmt6_validate, /* 6 */
00778       NULL,                          /* 7 */
00779       gxv_LookupTable_fmt8_validate, /* 8 */
00780     };
00781 
00782     GXV_Validate_Func  func;
00783 
00784 
00785     GXV_NAME_ENTER( "LookupTable" );
00786 
00787     /* lookuptbl_head may be used in fmt4 transit function. */
00788     valid->lookuptbl_head = table;
00789 
00790     /* format */
00791     GXV_LIMIT_CHECK( 2 );
00792     format = FT_NEXT_USHORT( p );
00793     GXV_TRACE(( " (format %d)\n", format ));
00794 
00795     if ( format > 8 )
00796       FT_INVALID_FORMAT;
00797 
00798     func = fmt_funcs_table[format];
00799     if ( func == NULL )
00800       FT_INVALID_FORMAT;
00801 
00802     func( p, limit, valid );
00803     p += valid->subtable_length;
00804 
00805     valid->subtable_length = p - table;
00806 
00807     GXV_EXIT;
00808   }
00809 
00810 
00811   /*************************************************************************/
00812   /*************************************************************************/
00813   /*****                                                               *****/
00814   /*****                          Glyph ID                             *****/
00815   /*****                                                               *****/
00816   /*************************************************************************/
00817   /*************************************************************************/
00818 
00819   FT_LOCAL_DEF( FT_Int )
00820   gxv_glyphid_validate( FT_UShort      gid,
00821                         GXV_Validator  valid )
00822   {
00823     FT_Face  face;
00824 
00825 
00826     if ( gid == 0xFFFFU )
00827     {
00828       GXV_EXIT;
00829       return 1;
00830     }
00831 
00832     face = valid->face;
00833     if ( face->num_glyphs < gid )
00834     {
00835       GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n",
00836                   face->num_glyphs, gid ));
00837       if ( valid->root->level >= FT_VALIDATE_PARANOID )
00838         FT_INVALID_GLYPH_ID;
00839     }
00840 
00841     return 0;
00842   }
00843 
00844 
00845   /*************************************************************************/
00846   /*************************************************************************/
00847   /*****                                                               *****/
00848   /*****                        CONTROL POINT                          *****/
00849   /*****                                                               *****/
00850   /*************************************************************************/
00851   /*************************************************************************/
00852 
00853   FT_LOCAL_DEF( void )
00854   gxv_ctlPoint_validate( FT_UShort      gid,
00855                          FT_Short       ctl_point,
00856                          GXV_Validator  valid )
00857   {
00858     FT_Face       face;
00859     FT_Error      error;
00860 
00861     FT_GlyphSlot  glyph;
00862     FT_Outline    outline;
00863     short         n_points;
00864 
00865 
00866     face = valid->face;
00867 
00868     error = FT_Load_Glyph( face,
00869                            gid,
00870                            FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM );
00871     if ( error )
00872       FT_INVALID_GLYPH_ID;
00873 
00874     glyph    = face->glyph;
00875     outline  = glyph->outline;
00876     n_points = outline.n_points;
00877 
00878 
00879     if ( !( ctl_point < n_points ) )
00880       FT_INVALID_DATA;
00881   }
00882 
00883 
00884   /*************************************************************************/
00885   /*************************************************************************/
00886   /*****                                                               *****/
00887   /*****                          SFNT NAME                            *****/
00888   /*****                                                               *****/
00889   /*************************************************************************/
00890   /*************************************************************************/
00891 
00892   FT_LOCAL_DEF( void )
00893   gxv_sfntName_validate( FT_UShort      name_index,
00894                          FT_UShort      min_index,
00895                          FT_UShort      max_index,
00896                          GXV_Validator  valid )
00897   {
00898     FT_SfntName  name;
00899     FT_UInt      i;
00900     FT_UInt      nnames;
00901 
00902 
00903     GXV_NAME_ENTER( "sfntName" );
00904 
00905     if ( name_index < min_index || max_index < name_index )
00906       FT_INVALID_FORMAT;
00907 
00908     nnames = FT_Get_Sfnt_Name_Count( valid->face );
00909     for ( i = 0; i < nnames; i++ )
00910     {
00911       if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok )
00912         continue ;
00913 
00914       if ( name.name_id == name_index )
00915         goto Out;
00916     }
00917 
00918     GXV_TRACE(( "  nameIndex = %d (UNTITLED)\n", name_index ));
00919     FT_INVALID_DATA;
00920     goto Exit;  /* make compiler happy */
00921 
00922   Out:
00923     FT_TRACE1(( "  nameIndex = %d (", name_index ));
00924     GXV_TRACE_HEXDUMP_SFNTNAME( name );
00925     FT_TRACE1(( ")\n" ));
00926 
00927   Exit:
00928     GXV_EXIT;
00929   }
00930 
00931 
00932   /*************************************************************************/
00933   /*************************************************************************/
00934   /*****                                                               *****/
00935   /*****                          STATE TABLE                          *****/
00936   /*****                                                               *****/
00937   /*************************************************************************/
00938   /*************************************************************************/
00939 
00940   /* -------------------------- Class Table --------------------------- */
00941 
00942   /*
00943    * highestClass specifies how many classes are defined in this
00944    * Class Subtable.  Apple spec does not mention whether undefined
00945    * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used)
00946    * are permitted.  At present, holes in a defined class are not checked.
00947    *   -- suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
00948    */
00949 
00950   static void
00951   gxv_ClassTable_validate( FT_Bytes       table,
00952                            FT_UShort*     length_p,
00953                            FT_UShort      stateSize,
00954                            FT_Byte*       maxClassID_p,
00955                            GXV_Validator  valid )
00956   {
00957     FT_Bytes   p     = table;
00958     FT_Bytes   limit = table + *length_p;
00959     FT_UShort  firstGlyph;
00960     FT_UShort  nGlyphs;
00961 
00962 
00963     GXV_NAME_ENTER( "ClassTable" );
00964 
00965     *maxClassID_p = 3;  /* Classes 0, 2, and 3 are predefined */
00966 
00967     GXV_LIMIT_CHECK( 2 + 2 );
00968     firstGlyph = FT_NEXT_USHORT( p );
00969     nGlyphs    = FT_NEXT_USHORT( p );
00970 
00971     GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
00972 
00973     if ( !nGlyphs )
00974       goto Out;
00975 
00976     gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), valid );
00977 
00978     {
00979       FT_Byte    nGlyphInClass[256];
00980       FT_Byte    classID;
00981       FT_UShort  i;
00982 
00983 
00984       ft_memset( nGlyphInClass, 0, 256 );
00985 
00986 
00987       for ( i = 0; i < nGlyphs; i++ )
00988       {
00989         GXV_LIMIT_CHECK( 1 );
00990         classID = FT_NEXT_BYTE( p );
00991         switch ( classID )
00992         {
00993           /* following classes should not appear in class array */
00994         case 0:             /* end of text */
00995         case 2:             /* out of bounds */
00996         case 3:             /* end of line */
00997           FT_INVALID_DATA;
00998           break;
00999 
01000         case 1:             /* out of bounds */
01001         default:            /* user-defined: 4 - ( stateSize - 1 ) */
01002           if ( classID >= stateSize )
01003             FT_INVALID_DATA;   /* assign glyph to undefined state */
01004 
01005           nGlyphInClass[classID]++;
01006           break;
01007         }
01008       }
01009       *length_p = (FT_UShort)( p - table );
01010 
01011       /* scan max ClassID in use */
01012       for ( i = 0; i < stateSize; i++ )
01013         if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) )
01014           *maxClassID_p = (FT_Byte)i;  /* XXX: Check Range? */
01015     }
01016 
01017   Out:
01018     GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n",
01019                 stateSize, *maxClassID_p ));
01020     GXV_EXIT;
01021   }
01022 
01023 
01024   /* --------------------------- State Array ----------------------------- */
01025 
01026   static void
01027   gxv_StateArray_validate( FT_Bytes       table,
01028                            FT_UShort*     length_p,
01029                            FT_Byte        maxClassID,
01030                            FT_UShort      stateSize,
01031                            FT_Byte*       maxState_p,
01032                            FT_Byte*       maxEntry_p,
01033                            GXV_Validator  valid )
01034   {
01035     FT_Bytes  p = table;
01036     FT_Bytes  limit = table + *length_p;
01037     FT_Byte   clazz;
01038     FT_Byte   entry;
01039 
01040     FT_UNUSED( stateSize ); /* for the non-debugging case */
01041 
01042 
01043     GXV_NAME_ENTER( "StateArray" );
01044 
01045     GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
01046                 (int)(*length_p), stateSize, (int)(maxClassID) ));
01047 
01048     /*
01049      * 2 states are predefined and must be described in StateArray:
01050      * state 0 (start of text), 1 (start of line)
01051      */
01052     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
01053 
01054     *maxState_p = 0;
01055     *maxEntry_p = 0;
01056 
01057     /* read if enough to read another state */
01058     while ( p + ( 1 + maxClassID ) <= limit )
01059     {
01060       (*maxState_p)++;
01061       for ( clazz = 0; clazz <= maxClassID; clazz++ )
01062       {
01063         entry = FT_NEXT_BYTE( p );
01064         *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry );
01065       }
01066     }
01067     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
01068                 *maxState_p, *maxEntry_p ));
01069 
01070     *length_p = (FT_UShort)( p - table );
01071 
01072     GXV_EXIT;
01073   }
01074 
01075 
01076   /* --------------------------- Entry Table ----------------------------- */
01077 
01078   static void
01079   gxv_EntryTable_validate( FT_Bytes       table,
01080                            FT_UShort*     length_p,
01081                            FT_Byte        maxEntry,
01082                            FT_UShort      stateArray,
01083                            FT_UShort      stateArray_length,
01084                            FT_Byte        maxClassID,
01085                            FT_Bytes       statetable_table,
01086                            FT_Bytes       statetable_limit,
01087                            GXV_Validator  valid )
01088   {
01089     FT_Bytes  p     = table;
01090     FT_Bytes  limit = table + *length_p;
01091     FT_Byte   entry;
01092     FT_Byte   state;
01093     FT_Int    entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
01094 
01095     GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
01096 
01097 
01098     GXV_NAME_ENTER( "EntryTable" );
01099 
01100     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
01101 
01102     if ( ( maxEntry + 1 ) * entrySize > *length_p )
01103     {
01104       if ( valid->root->level >= FT_VALIDATE_PARANOID )
01105         FT_INVALID_TOO_SHORT;
01106 
01107       /* ftxvalidator and FontValidator both warn and continue */
01108       maxEntry = (FT_Byte)( *length_p / entrySize - 1 );
01109       GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n",
01110                   maxEntry ));
01111     }
01112 
01113     for ( entry = 0; entry <= maxEntry; entry++ )
01114     {
01115       FT_UShort  newState;
01116       FT_UShort  flags;
01117 
01118 
01119       GXV_LIMIT_CHECK( 2 + 2 );
01120       newState = FT_NEXT_USHORT( p );
01121       flags    = FT_NEXT_USHORT( p );
01122 
01123 
01124       if ( newState < stateArray                     ||
01125            stateArray + stateArray_length < newState )
01126       {
01127         GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n",
01128                     newState ));
01129         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01130           FT_INVALID_OFFSET;
01131         continue;
01132       }
01133 
01134       if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) )
01135       {
01136         GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
01137                     newState,  1 + maxClassID ));
01138         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01139           FT_INVALID_OFFSET;
01140         continue;
01141       }
01142 
01143       state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) );
01144 
01145       switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
01146       {
01147       case GXV_GLYPHOFFSET_NONE:
01148         glyphOffset.uc = 0;  /* make compiler happy */
01149         break;
01150 
01151       case GXV_GLYPHOFFSET_UCHAR:
01152         glyphOffset.uc = FT_NEXT_BYTE( p );
01153         break;
01154 
01155       case GXV_GLYPHOFFSET_CHAR:
01156         glyphOffset.c = FT_NEXT_CHAR( p );
01157         break;
01158 
01159       case GXV_GLYPHOFFSET_USHORT:
01160         glyphOffset.u = FT_NEXT_USHORT( p );
01161         break;
01162 
01163       case GXV_GLYPHOFFSET_SHORT:
01164         glyphOffset.s = FT_NEXT_SHORT( p );
01165         break;
01166 
01167       case GXV_GLYPHOFFSET_ULONG:
01168         glyphOffset.ul = FT_NEXT_ULONG( p );
01169         break;
01170 
01171       case GXV_GLYPHOFFSET_LONG:
01172         glyphOffset.l = FT_NEXT_LONG( p );
01173         break;
01174 
01175       default:
01176         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01177           FT_INVALID_FORMAT;
01178         goto Exit;
01179       }
01180 
01181       if ( NULL != valid->statetable.entry_validate_func )
01182         valid->statetable.entry_validate_func( state,
01183                                                flags,
01184                                                &glyphOffset,
01185                                                statetable_table,
01186                                                statetable_limit,
01187                                                valid );
01188     }
01189 
01190   Exit:
01191     *length_p = (FT_UShort)( p - table );
01192 
01193     GXV_EXIT;
01194   }
01195 
01196 
01197   /* =========================== State Table ============================= */
01198 
01199   FT_LOCAL_DEF( void )
01200   gxv_StateTable_subtable_setup( FT_UShort      table_size,
01201                                  FT_UShort      classTable,
01202                                  FT_UShort      stateArray,
01203                                  FT_UShort      entryTable,
01204                                  FT_UShort*     classTable_length_p,
01205                                  FT_UShort*     stateArray_length_p,
01206                                  FT_UShort*     entryTable_length_p,
01207                                  GXV_Validator  valid )
01208   {
01209     FT_UShort   o[3];
01210     FT_UShort*  l[3];
01211     FT_UShort   buff[4];
01212 
01213 
01214     o[0] = classTable;
01215     o[1] = stateArray;
01216     o[2] = entryTable;
01217     l[0] = classTable_length_p;
01218     l[1] = stateArray_length_p;
01219     l[2] = entryTable_length_p;
01220 
01221     gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid );
01222   }
01223 
01224 
01225   FT_LOCAL_DEF( void )
01226   gxv_StateTable_validate( FT_Bytes       table,
01227                            FT_Bytes       limit,
01228                            GXV_Validator  valid )
01229   {
01230     FT_UShort   stateSize;
01231     FT_UShort   classTable;     /* offset to Class(Sub)Table */
01232     FT_UShort   stateArray;     /* offset to StateArray */
01233     FT_UShort   entryTable;     /* offset to EntryTable */
01234 
01235     FT_UShort   classTable_length;
01236     FT_UShort   stateArray_length;
01237     FT_UShort   entryTable_length;
01238     FT_Byte     maxClassID;
01239     FT_Byte     maxState;
01240     FT_Byte     maxEntry;
01241 
01242     GXV_StateTable_Subtable_Setup_Func  setup_func;
01243 
01244     FT_Bytes    p = table;
01245 
01246 
01247     GXV_NAME_ENTER( "StateTable" );
01248 
01249     GXV_TRACE(( "StateTable header\n" ));
01250 
01251     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
01252     stateSize  = FT_NEXT_USHORT( p );
01253     classTable = FT_NEXT_USHORT( p );
01254     stateArray = FT_NEXT_USHORT( p );
01255     entryTable = FT_NEXT_USHORT( p );
01256 
01257     GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
01258     GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
01259     GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
01260     GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
01261 
01262     if ( stateSize > 0xFF )
01263       FT_INVALID_DATA;
01264 
01265     if ( valid->statetable.optdata_load_func != NULL )
01266       valid->statetable.optdata_load_func( p, limit, valid );
01267 
01268     if ( valid->statetable.subtable_setup_func != NULL)
01269       setup_func = valid->statetable.subtable_setup_func;
01270     else
01271       setup_func = gxv_StateTable_subtable_setup;
01272 
01273     setup_func( (FT_UShort)( limit - table ),
01274                 classTable,
01275                 stateArray,
01276                 entryTable,
01277                 &classTable_length,
01278                 &stateArray_length,
01279                 &entryTable_length,
01280                 valid );
01281 
01282     GXV_TRACE(( "StateTable Subtables\n" ));
01283 
01284     if ( classTable != 0 )
01285       gxv_ClassTable_validate( table + classTable,
01286                                &classTable_length,
01287                                stateSize,
01288                                &maxClassID,
01289                                valid );
01290     else
01291       maxClassID = (FT_Byte)( stateSize - 1 );
01292 
01293     if ( stateArray != 0 )
01294       gxv_StateArray_validate( table + stateArray,
01295                                &stateArray_length,
01296                                maxClassID,
01297                                stateSize,
01298                                &maxState,
01299                                &maxEntry,
01300                                valid );
01301     else
01302     {
01303       maxState = 1;     /* 0:start of text, 1:start of line are predefined */
01304       maxEntry = 0;
01305     }
01306 
01307     if ( maxEntry > 0 && entryTable == 0 )
01308       FT_INVALID_OFFSET;
01309 
01310     if ( entryTable != 0 )
01311       gxv_EntryTable_validate( table + entryTable,
01312                                &entryTable_length,
01313                                maxEntry,
01314                                stateArray,
01315                                stateArray_length,
01316                                maxClassID,
01317                                table,
01318                                limit,
01319                                valid );
01320 
01321     GXV_EXIT;
01322   }
01323 
01324 
01325   /* ================= eXtended State Table (for morx) =================== */
01326 
01327   FT_LOCAL_DEF( void )
01328   gxv_XStateTable_subtable_setup( FT_ULong       table_size,
01329                                   FT_ULong       classTable,
01330                                   FT_ULong       stateArray,
01331                                   FT_ULong       entryTable,
01332                                   FT_ULong*      classTable_length_p,
01333                                   FT_ULong*      stateArray_length_p,
01334                                   FT_ULong*      entryTable_length_p,
01335                                   GXV_Validator  valid )
01336   {
01337     FT_ULong   o[3];
01338     FT_ULong*  l[3];
01339     FT_ULong   buff[4];
01340 
01341 
01342     o[0] = classTable;
01343     o[1] = stateArray;
01344     o[2] = entryTable;
01345     l[0] = classTable_length_p;
01346     l[1] = stateArray_length_p;
01347     l[2] = entryTable_length_p;
01348 
01349     gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid );
01350   }
01351 
01352 
01353   static void
01354   gxv_XClassTable_lookupval_validate( FT_UShort            glyph,
01355                                       GXV_LookupValueCPtr  value_p,
01356                                       GXV_Validator        valid )
01357   {
01358     FT_UNUSED( glyph );
01359 
01360     if ( value_p->u >= valid->xstatetable.nClasses )
01361       FT_INVALID_DATA;
01362     if ( value_p->u > valid->xstatetable.maxClassID )
01363       valid->xstatetable.maxClassID = value_p->u;
01364   }
01365 
01366 
01367   /*
01368     +===============+ --------+
01369     | lookup header |         |
01370     +===============+         |
01371     | BinSrchHeader |         |
01372     +===============+         |
01373     | lastGlyph[0]  |         |
01374     +---------------+         |
01375     | firstGlyph[0] |         |    head of lookup table
01376     +---------------+         |             +
01377     | offset[0]     |    ->   |          offset            [byte]
01378     +===============+         |             +
01379     | lastGlyph[1]  |         | (glyphID - firstGlyph) * 2 [byte]
01380     +---------------+         |
01381     | firstGlyph[1] |         |
01382     +---------------+         |
01383     | offset[1]     |         |
01384     +===============+         |
01385                               |
01386      ....                     |
01387                               |
01388     16bit value array         |
01389     +===============+         |
01390     |     value     | <-------+
01391      ....
01392   */
01393   static GXV_LookupValueDesc
01394   gxv_XClassTable_lookupfmt4_transit( FT_UShort            relative_gindex,
01395                                       GXV_LookupValueCPtr  base_value_p,
01396                                       FT_Bytes             lookuptbl_limit,
01397                                       GXV_Validator        valid )
01398   {
01399     FT_Bytes             p;
01400     FT_Bytes             limit;
01401     FT_UShort            offset;
01402     GXV_LookupValueDesc  value;
01403 
01404     /* XXX: check range? */
01405     offset = (FT_UShort)( base_value_p->u +
01406                           relative_gindex * sizeof ( FT_UShort ) );
01407 
01408     p     = valid->lookuptbl_head + offset;
01409     limit = lookuptbl_limit;
01410 
01411     GXV_LIMIT_CHECK ( 2 );
01412     value.u = FT_NEXT_USHORT( p );
01413 
01414     return value;
01415   }
01416 
01417 
01418   static void
01419   gxv_XStateArray_validate( FT_Bytes       table,
01420                             FT_ULong*      length_p,
01421                             FT_UShort      maxClassID,
01422                             FT_ULong       stateSize,
01423                             FT_UShort*     maxState_p,
01424                             FT_UShort*     maxEntry_p,
01425                             GXV_Validator  valid )
01426   {
01427     FT_Bytes   p = table;
01428     FT_Bytes   limit = table + *length_p;
01429     FT_UShort  clazz;
01430     FT_UShort  entry;
01431 
01432     FT_UNUSED( stateSize ); /* for the non-debugging case */
01433 
01434 
01435     GXV_NAME_ENTER( "XStateArray" );
01436 
01437     GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
01438                 (int)(*length_p), stateSize, (int)(maxClassID) ));
01439 
01440     /*
01441      * 2 states are predefined and must be described:
01442      * state 0 (start of text), 1 (start of line)
01443      */
01444     GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
01445 
01446     *maxState_p = 0;
01447     *maxEntry_p = 0;
01448 
01449     /* read if enough to read another state */
01450     while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
01451     {
01452       (*maxState_p)++;
01453       for ( clazz = 0; clazz <= maxClassID; clazz++ )
01454       {
01455         entry = FT_NEXT_USHORT( p );
01456         *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry );
01457       }
01458     }
01459     GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
01460                 *maxState_p, *maxEntry_p ));
01461 
01462     *length_p = p - table;
01463 
01464     GXV_EXIT;
01465   }
01466 
01467 
01468   static void
01469   gxv_XEntryTable_validate( FT_Bytes       table,
01470                             FT_ULong*      length_p,
01471                             FT_UShort      maxEntry,
01472                             FT_ULong       stateArray_length,
01473                             FT_UShort      maxClassID,
01474                             FT_Bytes       xstatetable_table,
01475                             FT_Bytes       xstatetable_limit,
01476                             GXV_Validator  valid )
01477   {
01478     FT_Bytes   p = table;
01479     FT_Bytes   limit = table + *length_p;
01480     FT_UShort  entry;
01481     FT_UShort  state;
01482     FT_Int     entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
01483 
01484 
01485     GXV_NAME_ENTER( "XEntryTable" );
01486     GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
01487 
01488     if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
01489       FT_INVALID_TOO_SHORT;
01490 
01491     for (entry = 0; entry <= maxEntry ; entry++ )
01492     {
01493       FT_UShort                        newState_idx;
01494       FT_UShort                        flags;
01495       GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
01496 
01497 
01498       GXV_LIMIT_CHECK( 2 + 2 );
01499       newState_idx = FT_NEXT_USHORT( p );
01500       flags        = FT_NEXT_USHORT( p );
01501 
01502       if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) )
01503       {
01504         GXV_TRACE(( "  newState index 0x%04x points out of stateArray\n",
01505                     newState_idx ));
01506         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01507           FT_INVALID_OFFSET;
01508       }
01509 
01510       state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) );
01511       if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
01512       {
01513         FT_TRACE4(( "-> new state = %d (supposed)\n"
01514                     "but newState index 0x%04x is not aligned to %d-classes\n",
01515                     state, newState_idx,  1 + maxClassID ));
01516         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01517           FT_INVALID_OFFSET;
01518       }
01519 
01520       switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
01521       {
01522       case GXV_GLYPHOFFSET_NONE:
01523         glyphOffset.uc = 0; /* make compiler happy */
01524         break;
01525 
01526       case GXV_GLYPHOFFSET_UCHAR:
01527         glyphOffset.uc = FT_NEXT_BYTE( p );
01528         break;
01529 
01530       case GXV_GLYPHOFFSET_CHAR:
01531         glyphOffset.c = FT_NEXT_CHAR( p );
01532         break;
01533 
01534       case GXV_GLYPHOFFSET_USHORT:
01535         glyphOffset.u = FT_NEXT_USHORT( p );
01536         break;
01537 
01538       case GXV_GLYPHOFFSET_SHORT:
01539         glyphOffset.s = FT_NEXT_SHORT( p );
01540         break;
01541 
01542       case GXV_GLYPHOFFSET_ULONG:
01543         glyphOffset.ul = FT_NEXT_ULONG( p );
01544         break;
01545 
01546       case GXV_GLYPHOFFSET_LONG:
01547         glyphOffset.l = FT_NEXT_LONG( p );
01548         break;
01549 
01550       default:
01551         if ( valid->root->level >= FT_VALIDATE_PARANOID )
01552           FT_INVALID_FORMAT;
01553         goto Exit;
01554       }
01555 
01556       if ( NULL != valid->xstatetable.entry_validate_func )
01557         valid->xstatetable.entry_validate_func( state,
01558                                                 flags,
01559                                                 &glyphOffset,
01560                                                 xstatetable_table,
01561                                                 xstatetable_limit,
01562                                                 valid );
01563     }
01564 
01565   Exit:
01566     *length_p = p - table;
01567 
01568     GXV_EXIT;
01569   }
01570 
01571 
01572   FT_LOCAL_DEF( void )
01573   gxv_XStateTable_validate( FT_Bytes       table,
01574                             FT_Bytes       limit,
01575                             GXV_Validator  valid )
01576   {
01577     /* StateHeader members */
01578     FT_ULong   classTable;      /* offset to Class(Sub)Table */
01579     FT_ULong   stateArray;      /* offset to StateArray */
01580     FT_ULong   entryTable;      /* offset to EntryTable */
01581 
01582     FT_ULong   classTable_length;
01583     FT_ULong   stateArray_length;
01584     FT_ULong   entryTable_length;
01585     FT_UShort  maxState;
01586     FT_UShort  maxEntry;
01587 
01588     GXV_XStateTable_Subtable_Setup_Func  setup_func;
01589 
01590     FT_Bytes   p = table;
01591 
01592 
01593     GXV_NAME_ENTER( "XStateTable" );
01594 
01595     GXV_TRACE(( "XStateTable header\n" ));
01596 
01597     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
01598     valid->xstatetable.nClasses = FT_NEXT_ULONG( p );
01599     classTable = FT_NEXT_ULONG( p );
01600     stateArray = FT_NEXT_ULONG( p );
01601     entryTable = FT_NEXT_ULONG( p );
01602 
01603     GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses ));
01604     GXV_TRACE(( "offset to classTable=0x%08x\n", classTable ));
01605     GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray ));
01606     GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable ));
01607 
01608     if ( valid->xstatetable.nClasses > 0xFFFFU )
01609       FT_INVALID_DATA;
01610 
01611     GXV_TRACE(( "StateTable Subtables\n" ));
01612 
01613     if ( valid->xstatetable.optdata_load_func != NULL )
01614       valid->xstatetable.optdata_load_func( p, limit, valid );
01615 
01616     if ( valid->xstatetable.subtable_setup_func != NULL )
01617       setup_func = valid->xstatetable.subtable_setup_func;
01618     else
01619       setup_func = gxv_XStateTable_subtable_setup;
01620 
01621     setup_func( limit - table,
01622                 classTable,
01623                 stateArray,
01624                 entryTable,
01625                 &classTable_length,
01626                 &stateArray_length,
01627                 &entryTable_length,
01628                 valid );
01629 
01630     if ( classTable != 0 )
01631     {
01632       valid->xstatetable.maxClassID = 0;
01633       valid->lookupval_sign         = GXV_LOOKUPVALUE_UNSIGNED;
01634       valid->lookupval_func         = gxv_XClassTable_lookupval_validate;
01635       valid->lookupfmt4_trans       = gxv_XClassTable_lookupfmt4_transit;
01636       gxv_LookupTable_validate( table + classTable,
01637                                 table + classTable + classTable_length,
01638                                 valid );
01639       if ( valid->subtable_length < classTable_length )
01640         classTable_length = valid->subtable_length;
01641     }
01642     else
01643     {
01644       /* XXX: check range? */
01645       valid->xstatetable.maxClassID =
01646         (FT_UShort)( valid->xstatetable.nClasses - 1 );
01647     }
01648 
01649     if ( stateArray != 0 )
01650       gxv_XStateArray_validate( table + stateArray,
01651                                 &stateArray_length,
01652                                 valid->xstatetable.maxClassID,
01653                                 valid->xstatetable.nClasses,
01654                                 &maxState,
01655                                 &maxEntry,
01656                                 valid );
01657     else
01658     {
01659       maxState = 1; /* 0:start of text, 1:start of line are predefined */
01660       maxEntry = 0;
01661     }
01662 
01663     if ( maxEntry > 0 && entryTable == 0 )
01664       FT_INVALID_OFFSET;
01665 
01666     if ( entryTable != 0 )
01667       gxv_XEntryTable_validate( table + entryTable,
01668                                 &entryTable_length,
01669                                 maxEntry,
01670                                 stateArray_length,
01671                                 valid->xstatetable.maxClassID,
01672                                 table,
01673                                 limit,
01674                                 valid );
01675 
01676     GXV_EXIT;
01677   }
01678 
01679 
01680   /*************************************************************************/
01681   /*************************************************************************/
01682   /*****                                                               *****/
01683   /*****                        Table overlapping                      *****/
01684   /*****                                                               *****/
01685   /*************************************************************************/
01686   /*************************************************************************/
01687 
01688   static int
01689   gxv_compare_ranges( FT_Bytes  table1_start,
01690                       FT_ULong  table1_length,
01691                       FT_Bytes  table2_start,
01692                       FT_ULong  table2_length )
01693   {
01694     if ( table1_start == table2_start )
01695     {
01696       if ( ( table1_length == 0 || table2_length == 0 ) )
01697         goto Out;
01698     }
01699     else if ( table1_start < table2_start )
01700     {
01701       if ( ( table1_start + table1_length ) <= table2_start )
01702         goto Out;
01703     }
01704     else if ( table1_start > table2_start )
01705     {
01706       if ( ( table1_start >= table2_start + table2_length ) )
01707         goto Out;
01708     }
01709     return 1;
01710 
01711   Out:
01712     return 0;
01713   }
01714 
01715 
01716   FT_LOCAL_DEF( void )
01717   gxv_odtect_add_range( FT_Bytes          start,
01718                         FT_ULong          length,
01719                         const FT_String*  name,
01720                         GXV_odtect_Range  odtect )
01721   {
01722     odtect->range[ odtect->nRanges ].start  = start;
01723     odtect->range[ odtect->nRanges ].length = length;
01724     odtect->range[ odtect->nRanges ].name   = (FT_String*)name;
01725     odtect->nRanges++;
01726   }
01727 
01728 
01729   FT_LOCAL_DEF( void )
01730   gxv_odtect_validate( GXV_odtect_Range  odtect,
01731                        GXV_Validator     valid )
01732   {
01733     FT_UInt  i, j;
01734 
01735 
01736     GXV_NAME_ENTER( "check overlap among multi ranges" );
01737 
01738     for ( i = 0; i < odtect->nRanges; i++ )
01739       for ( j = 0; j < i; j++ )
01740         if ( 0 != gxv_compare_ranges( odtect->range[i].start,
01741                                       odtect->range[i].length,
01742                                       odtect->range[j].start,
01743                                       odtect->range[j].length ) )
01744         {
01745           if ( odtect->range[i].name || odtect->range[j].name )
01746             GXV_TRACE(( "found overlap between range %d and range %d\n",
01747                         i, j ));
01748           else
01749             GXV_TRACE(( "found overlap between `%s' and `%s\'\n",
01750                         odtect->range[i].name,
01751                         odtect->range[j].name ));
01752           FT_INVALID_OFFSET;
01753         }
01754 
01755     GXV_EXIT;
01756   }
01757 
01758 
01759 /* END */

Generated on Tue Jul 5 14:13:46 2011 for ROOT_528-00b_version by  doxygen 1.5.1