Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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