Subversion Repositories Kolibri OS

Rev

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

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  gxvkern.c                                                              */
  4. /*                                                                         */
  5. /*    TrueTypeGX/AAT kern table validation (body).                         */
  6. /*                                                                         */
  7. /*  Copyright 2004-2007, 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 "gxvalid.h"
  29. #include "gxvcommn.h"
  30.  
  31. #include FT_SFNT_NAMES_H
  32. #include FT_SERVICE_GX_VALIDATE_H
  33.  
  34.  
  35.   /*************************************************************************/
  36.   /*                                                                       */
  37.   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  38.   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  39.   /* messages during execution.                                            */
  40.   /*                                                                       */
  41. #undef  FT_COMPONENT
  42. #define FT_COMPONENT  trace_gxvkern
  43.  
  44.  
  45.   /*************************************************************************/
  46.   /*************************************************************************/
  47.   /*****                                                               *****/
  48.   /*****                      Data and Types                           *****/
  49.   /*****                                                               *****/
  50.   /*************************************************************************/
  51.   /*************************************************************************/
  52.  
  53.   typedef enum  GXV_kern_Version_
  54.   {
  55.     KERN_VERSION_CLASSIC = 0x0000,
  56.     KERN_VERSION_NEW     = 0x0001
  57.  
  58.   } GXV_kern_Version;
  59.  
  60.  
  61.   typedef enum GXV_kern_Dialect_
  62.   {
  63.     KERN_DIALECT_UNKNOWN = 0,
  64.     KERN_DIALECT_MS      = FT_VALIDATE_MS,
  65.     KERN_DIALECT_APPLE   = FT_VALIDATE_APPLE,
  66.     KERN_DIALECT_ANY     = FT_VALIDATE_CKERN
  67.  
  68.   } GXV_kern_Dialect;
  69.  
  70.  
  71.   typedef struct  GXV_kern_DataRec_
  72.   {
  73.     GXV_kern_Version  version;
  74.     void             *subtable_data;
  75.     GXV_kern_Dialect  dialect_request;
  76.  
  77.   } GXV_kern_DataRec, *GXV_kern_Data;
  78.  
  79.  
  80. #define GXV_KERN_DATA( field )  GXV_TABLE_DATA( kern, field )
  81.  
  82. #define KERN_IS_CLASSIC( valid )                               \
  83.           ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
  84. #define KERN_IS_NEW( valid )                                   \
  85.           ( KERN_VERSION_NEW     == GXV_KERN_DATA( version ) )
  86.  
  87. #define KERN_DIALECT( valid )              \
  88.           GXV_KERN_DATA( dialect_request )
  89. #define KERN_ALLOWS_MS( valid )                       \
  90.           ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
  91. #define KERN_ALLOWS_APPLE( valid )                       \
  92.           ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
  93.  
  94. #define GXV_KERN_HEADER_SIZE           ( KERN_IS_NEW( valid ) ? 8 : 4 )
  95. #define GXV_KERN_SUBTABLE_HEADER_SIZE  ( KERN_IS_NEW( valid ) ? 8 : 6 )
  96.  
  97.  
  98.   /*************************************************************************/
  99.   /*************************************************************************/
  100.   /*****                                                               *****/
  101.   /*****                      SUBTABLE VALIDATORS                      *****/
  102.   /*****                                                               *****/
  103.   /*************************************************************************/
  104.   /*************************************************************************/
  105.  
  106.  
  107.   /* ============================= format 0 ============================== */
  108.  
  109.   static void
  110.   gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes       table,
  111.                                          FT_Bytes       limit,
  112.                                          FT_UShort      nPairs,
  113.                                          GXV_Validator  valid )
  114.   {
  115.     FT_Bytes   p = table;
  116.     FT_UShort  i;
  117.  
  118.     FT_UShort  last_gid_left  = 0;
  119.     FT_UShort  last_gid_right = 0;
  120.  
  121.     FT_UNUSED( limit );
  122.  
  123.  
  124.     GXV_NAME_ENTER( "kern format 0 pairs" );
  125.  
  126.     for ( i = 0; i < nPairs; i++ )
  127.     {
  128.       FT_UShort  gid_left;
  129.       FT_UShort  gid_right;
  130. #ifdef GXV_LOAD_UNUSED_VARS
  131.       FT_Short   kernValue;
  132. #endif
  133.  
  134.  
  135.       /* left */
  136.       gid_left  = FT_NEXT_USHORT( p );
  137.       gxv_glyphid_validate( gid_left, valid );
  138.  
  139.       /* right */
  140.       gid_right = FT_NEXT_USHORT( p );
  141.       gxv_glyphid_validate( gid_right, valid );
  142.  
  143.       /* Pairs of left and right GIDs must be unique and sorted. */
  144.       GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right ));
  145.       if ( gid_left == last_gid_left )
  146.       {
  147.         if ( last_gid_right < gid_right )
  148.           last_gid_right = gid_right;
  149.         else
  150.           FT_INVALID_DATA;
  151.       }
  152.       else if ( last_gid_left < gid_left )
  153.       {
  154.         last_gid_left  = gid_left;
  155.         last_gid_right = gid_right;
  156.       }
  157.       else
  158.         FT_INVALID_DATA;
  159.  
  160.       /* skip the kern value */
  161. #ifdef GXV_LOAD_UNUSED_VARS
  162.       kernValue = FT_NEXT_SHORT( p );
  163. #else
  164.       p += 2;
  165. #endif
  166.     }
  167.  
  168.     GXV_EXIT;
  169.   }
  170.  
  171.   static void
  172.   gxv_kern_subtable_fmt0_validate( FT_Bytes       table,
  173.                                    FT_Bytes       limit,
  174.                                    GXV_Validator  valid )
  175.   {
  176.     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
  177.  
  178.     FT_UShort  nPairs;
  179.     FT_UShort  unitSize;
  180.  
  181.  
  182.     GXV_NAME_ENTER( "kern subtable format 0" );
  183.  
  184.     unitSize = 2 + 2 + 2;
  185.     nPairs   = 0;
  186.  
  187.     /* nPairs, searchRange, entrySelector, rangeShift */
  188.     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
  189.     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
  190.     p += 2 + 2 + 2 + 2;
  191.  
  192.     gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid );
  193.  
  194.     GXV_EXIT;
  195.   }
  196.  
  197.  
  198.   /* ============================= format 1 ============================== */
  199.  
  200.  
  201.   typedef struct  GXV_kern_fmt1_StateOptRec_
  202.   {
  203.     FT_UShort  valueTable;
  204.     FT_UShort  valueTable_length;
  205.  
  206.   } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
  207.  
  208.  
  209.   static void
  210.   gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes       table,
  211.                                           FT_Bytes       limit,
  212.                                           GXV_Validator  valid )
  213.   {
  214.     FT_Bytes                       p = table;
  215.     GXV_kern_fmt1_StateOptRecData  optdata =
  216.       (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
  217.  
  218.  
  219.     GXV_LIMIT_CHECK( 2 );
  220.     optdata->valueTable = FT_NEXT_USHORT( p );
  221.   }
  222.  
  223.  
  224.   /*
  225.    * passed tables_size covers whole StateTable, including kern fmt1 header
  226.    */
  227.   static void
  228.   gxv_kern_subtable_fmt1_subtable_setup( FT_UShort      table_size,
  229.                                          FT_UShort      classTable,
  230.                                          FT_UShort      stateArray,
  231.                                          FT_UShort      entryTable,
  232.                                          FT_UShort*     classTable_length_p,
  233.                                          FT_UShort*     stateArray_length_p,
  234.                                          FT_UShort*     entryTable_length_p,
  235.                                          GXV_Validator  valid )
  236.   {
  237.     FT_UShort  o[4];
  238.     FT_UShort  *l[4];
  239.     FT_UShort  buff[5];
  240.  
  241.     GXV_kern_fmt1_StateOptRecData  optdata =
  242.       (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
  243.  
  244.  
  245.     o[0] = classTable;
  246.     o[1] = stateArray;
  247.     o[2] = entryTable;
  248.     o[3] = optdata->valueTable;
  249.     l[0] = classTable_length_p;
  250.     l[1] = stateArray_length_p;
  251.     l[2] = entryTable_length_p;
  252.     l[3] = &(optdata->valueTable_length);
  253.  
  254.     gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
  255.   }
  256.  
  257.  
  258.   /*
  259.    * passed table & limit are of whole StateTable, not including subtables
  260.    */
  261.   static void
  262.   gxv_kern_subtable_fmt1_entry_validate(
  263.     FT_Byte                         state,
  264.     FT_UShort                       flags,
  265.     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
  266.     FT_Bytes                        table,
  267.     FT_Bytes                        limit,
  268.     GXV_Validator                   valid )
  269.   {
  270. #ifdef GXV_LOAD_UNUSED_VARS
  271.     FT_UShort  push;
  272.     FT_UShort  dontAdvance;
  273. #endif
  274.     FT_UShort  valueOffset;
  275. #ifdef GXV_LOAD_UNUSED_VARS
  276.     FT_UShort  kernAction;
  277.     FT_UShort  kernValue;
  278. #endif
  279.  
  280.     FT_UNUSED( state );
  281.     FT_UNUSED( glyphOffset_p );
  282.  
  283.  
  284. #ifdef GXV_LOAD_UNUSED_VARS
  285.     push        = (FT_UShort)( ( flags >> 15 ) & 1      );
  286.     dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1      );
  287. #endif
  288.     valueOffset = (FT_UShort)(   flags         & 0x3FFF );
  289.  
  290.     {
  291.       GXV_kern_fmt1_StateOptRecData  vt_rec =
  292.         (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
  293.       FT_Bytes  p;
  294.  
  295.  
  296.       if ( valueOffset < vt_rec->valueTable )
  297.         FT_INVALID_OFFSET;
  298.  
  299.       p     = table + valueOffset;
  300.       limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
  301.  
  302.       GXV_LIMIT_CHECK( 2 + 2 );
  303. #ifdef GXV_LOAD_UNUSED_VARS
  304.       kernAction = FT_NEXT_USHORT( p );
  305.       kernValue  = FT_NEXT_USHORT( p );
  306. #endif
  307.     }
  308.   }
  309.  
  310.  
  311.   static void
  312.   gxv_kern_subtable_fmt1_validate( FT_Bytes       table,
  313.                                    FT_Bytes       limit,
  314.                                    GXV_Validator  valid )
  315.   {
  316.     FT_Bytes                   p = table;
  317.     GXV_kern_fmt1_StateOptRec  vt_rec;
  318.  
  319.  
  320.     GXV_NAME_ENTER( "kern subtable format 1" );
  321.  
  322.     valid->statetable.optdata =
  323.       &vt_rec;
  324.     valid->statetable.optdata_load_func =
  325.       gxv_kern_subtable_fmt1_valueTable_load;
  326.     valid->statetable.subtable_setup_func =
  327.       gxv_kern_subtable_fmt1_subtable_setup;
  328.     valid->statetable.entry_glyphoffset_fmt =
  329.       GXV_GLYPHOFFSET_NONE;
  330.     valid->statetable.entry_validate_func =
  331.       gxv_kern_subtable_fmt1_entry_validate;
  332.  
  333.     gxv_StateTable_validate( p, limit, valid );
  334.  
  335.     GXV_EXIT;
  336.   }
  337.  
  338.  
  339.   /* ================ Data for Class-Based Subtables 2, 3 ================ */
  340.  
  341.   typedef enum  GXV_kern_ClassSpec_
  342.   {
  343.     GXV_KERN_CLS_L = 0,
  344.     GXV_KERN_CLS_R
  345.  
  346.   } GXV_kern_ClassSpec;
  347.  
  348.  
  349.   /* ============================= format 2 ============================== */
  350.  
  351.   /* ---------------------- format 2 specific data ----------------------- */
  352.  
  353.   typedef struct  GXV_kern_subtable_fmt2_DataRec_
  354.   {
  355.     FT_UShort         rowWidth;
  356.     FT_UShort         array;
  357.     FT_UShort         offset_min[2];
  358.     FT_UShort         offset_max[2];
  359.     const FT_String*  class_tag[2];
  360.     GXV_odtect_Range  odtect;
  361.  
  362.   } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
  363.  
  364.  
  365. #define GXV_KERN_FMT2_DATA( field )                         \
  366.         ( ( (GXV_kern_subtable_fmt2_DataRec *)              \
  367.               ( GXV_KERN_DATA( subtable_data ) ) )->field )
  368.  
  369.  
  370.   /* -------------------------- utility functions ----------------------- */
  371.  
  372.   static void
  373.   gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes            table,
  374.                                           FT_Bytes            limit,
  375.                                           GXV_kern_ClassSpec  spec,
  376.                                           GXV_Validator       valid )
  377.   {
  378.     const FT_String*  tag    = GXV_KERN_FMT2_DATA( class_tag[spec] );
  379.     GXV_odtect_Range  odtect = GXV_KERN_FMT2_DATA( odtect );
  380.  
  381.     FT_Bytes   p = table;
  382.     FT_UShort  firstGlyph;
  383.     FT_UShort  nGlyphs;
  384.  
  385.  
  386.     GXV_NAME_ENTER( "kern format 2 classTable" );
  387.  
  388.     GXV_LIMIT_CHECK( 2 + 2 );
  389.     firstGlyph = FT_NEXT_USHORT( p );
  390.     nGlyphs    = FT_NEXT_USHORT( p );
  391.     GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
  392.                 tag, firstGlyph, nGlyphs ));
  393.  
  394.     gxv_glyphid_validate( firstGlyph, valid );
  395.     gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid );
  396.  
  397.     gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
  398.                                 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
  399.                                 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
  400.                                 valid );
  401.  
  402.     gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect );
  403.  
  404.     GXV_EXIT;
  405.   }
  406.  
  407.  
  408.   static void
  409.   gxv_kern_subtable_fmt2_validate( FT_Bytes       table,
  410.                                    FT_Bytes       limit,
  411.                                    GXV_Validator  valid )
  412.   {
  413.     GXV_ODTECT( 3, odtect );
  414.     GXV_kern_subtable_fmt2_DataRec  fmt2_rec =
  415.       { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
  416.  
  417.     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
  418.     FT_UShort  leftOffsetTable;
  419.     FT_UShort  rightOffsetTable;
  420.  
  421.  
  422.     GXV_NAME_ENTER( "kern subtable format 2" );
  423.  
  424.     GXV_ODTECT_INIT( odtect );
  425.     fmt2_rec.odtect = odtect;
  426.     GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
  427.  
  428.     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
  429.     GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
  430.     leftOffsetTable                = FT_NEXT_USHORT( p );
  431.     rightOffsetTable               = FT_NEXT_USHORT( p );
  432.     GXV_KERN_FMT2_DATA( array )    = FT_NEXT_USHORT( p );
  433.  
  434.     GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
  435.  
  436.  
  437.     GXV_LIMIT_CHECK( leftOffsetTable );
  438.     GXV_LIMIT_CHECK( rightOffsetTable );
  439.     GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
  440.  
  441.     gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
  442.                                             GXV_KERN_CLS_L, valid );
  443.  
  444.     gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
  445.                                             GXV_KERN_CLS_R, valid );
  446.  
  447.     if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) +
  448.            GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
  449.          < GXV_KERN_FMT2_DATA( array )                      )
  450.       FT_INVALID_OFFSET;
  451.  
  452.     gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
  453.                           GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
  454.                             + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
  455.                             - GXV_KERN_FMT2_DATA( array ),
  456.                           "array", odtect );
  457.  
  458.     gxv_odtect_validate( odtect, valid );
  459.  
  460.     GXV_EXIT;
  461.   }
  462.  
  463.  
  464.   /* ============================= format 3 ============================== */
  465.  
  466.   static void
  467.   gxv_kern_subtable_fmt3_validate( FT_Bytes       table,
  468.                                    FT_Bytes       limit,
  469.                                    GXV_Validator  valid )
  470.   {
  471.     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
  472.     FT_UShort  glyphCount;
  473.     FT_Byte    kernValueCount;
  474.     FT_Byte    leftClassCount;
  475.     FT_Byte    rightClassCount;
  476.     FT_Byte    flags;
  477.  
  478.  
  479.     GXV_NAME_ENTER( "kern subtable format 3" );
  480.  
  481.     GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
  482.     glyphCount      = FT_NEXT_USHORT( p );
  483.     kernValueCount  = FT_NEXT_BYTE( p );
  484.     leftClassCount  = FT_NEXT_BYTE( p );
  485.     rightClassCount = FT_NEXT_BYTE( p );
  486.     flags           = FT_NEXT_BYTE( p );
  487.  
  488.     if ( valid->face->num_glyphs != glyphCount )
  489.     {
  490.       GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
  491.                   valid->face->num_glyphs, glyphCount ));
  492.       GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
  493.     }
  494.  
  495.     if ( flags != 0 )
  496.       GXV_TRACE(( "kern subtable fmt3 has nonzero value"
  497.                   " (%d) in unused flag\n", flags ));
  498.     /*
  499.      * just skip kernValue[kernValueCount]
  500.      */
  501.     GXV_LIMIT_CHECK( 2 * kernValueCount );
  502.     p += 2 * kernValueCount;
  503.  
  504.     /*
  505.      * check leftClass[gid] < leftClassCount
  506.      */
  507.     {
  508.       FT_Byte  min, max;
  509.  
  510.  
  511.       GXV_LIMIT_CHECK( glyphCount );
  512.       gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
  513.       p += valid->subtable_length;
  514.  
  515.       if ( leftClassCount < max )
  516.         FT_INVALID_DATA;
  517.     }
  518.  
  519.     /*
  520.      * check rightClass[gid] < rightClassCount
  521.      */
  522.     {
  523.       FT_Byte  min, max;
  524.  
  525.  
  526.       GXV_LIMIT_CHECK( glyphCount );
  527.       gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
  528.       p += valid->subtable_length;
  529.  
  530.       if ( rightClassCount < max )
  531.         FT_INVALID_DATA;
  532.     }
  533.  
  534.     /*
  535.      * check kernIndex[i, j] < kernValueCount
  536.      */
  537.     {
  538.       FT_UShort  i, j;
  539.  
  540.  
  541.       for ( i = 0; i < leftClassCount; i++ )
  542.       {
  543.         for ( j = 0; j < rightClassCount; j++ )
  544.         {
  545.           GXV_LIMIT_CHECK( 1 );
  546.           if ( kernValueCount < FT_NEXT_BYTE( p ) )
  547.             FT_INVALID_OFFSET;
  548.         }
  549.       }
  550.     }
  551.  
  552.     valid->subtable_length = p - table;
  553.  
  554.     GXV_EXIT;
  555.   }
  556.  
  557.  
  558.   static FT_Bool
  559.   gxv_kern_coverage_new_apple_validate( FT_UShort      coverage,
  560.                                         FT_UShort*     format,
  561.                                         GXV_Validator  valid )
  562.   {
  563.     /* new Apple-dialect */
  564. #ifdef GXV_LOAD_TRACE_VARS
  565.     FT_Bool  kernVertical;
  566.     FT_Bool  kernCrossStream;
  567.     FT_Bool  kernVariation;
  568. #endif
  569.  
  570.     FT_UNUSED( valid );
  571.  
  572.  
  573.     /* reserved bits = 0 */
  574.     if ( coverage & 0x1FFC )
  575.       return FALSE;
  576.  
  577. #ifdef GXV_LOAD_TRACE_VARS
  578.     kernVertical    = FT_BOOL( ( coverage >> 15 ) & 1 );
  579.     kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 );
  580.     kernVariation   = FT_BOOL( ( coverage >> 13 ) & 1 );
  581. #endif
  582.  
  583.     *format = (FT_UShort)( coverage & 0x0003 );
  584.  
  585.     GXV_TRACE(( "new Apple-dialect: "
  586.                 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
  587.                  !kernVertical, kernCrossStream, kernVariation, *format ));
  588.  
  589.     GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
  590.  
  591.     return TRUE;
  592.   }
  593.  
  594.  
  595.   static FT_Bool
  596.   gxv_kern_coverage_classic_apple_validate( FT_UShort      coverage,
  597.                                             FT_UShort*     format,
  598.                                             GXV_Validator  valid )
  599.   {
  600.     /* classic Apple-dialect */
  601. #ifdef GXV_LOAD_TRACE_VARS
  602.     FT_Bool  horizontal;
  603.     FT_Bool  cross_stream;
  604. #endif
  605.  
  606.  
  607.     /* check expected flags, but don't check if MS-dialect is impossible */
  608.     if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
  609.       return FALSE;
  610.  
  611.     /* reserved bits = 0 */
  612.     if ( coverage & 0x02FC )
  613.       return FALSE;
  614.  
  615. #ifdef GXV_LOAD_TRACE_VARS
  616.     horizontal   = FT_BOOL( ( coverage >> 15 ) & 1 );
  617.     cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 );
  618. #endif
  619.  
  620.     *format = (FT_UShort)( coverage & 0x0003 );
  621.  
  622.     GXV_TRACE(( "classic Apple-dialect: "
  623.                 "horizontal=%d, cross-stream=%d, format=%d\n",
  624.                  horizontal, cross_stream, *format ));
  625.  
  626.     /* format 1 requires GX State Machine, too new for classic */
  627.     if ( *format == 1 )
  628.       return FALSE;
  629.  
  630.     GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
  631.  
  632.     return TRUE;
  633.   }
  634.  
  635.  
  636.   static FT_Bool
  637.   gxv_kern_coverage_classic_microsoft_validate( FT_UShort      coverage,
  638.                                                 FT_UShort*     format,
  639.                                                 GXV_Validator  valid )
  640.   {
  641.     /* classic Microsoft-dialect */
  642. #ifdef GXV_LOAD_TRACE_VARS
  643.     FT_Bool  horizontal;
  644.     FT_Bool  minimum;
  645.     FT_Bool  cross_stream;
  646.     FT_Bool  override;
  647. #endif
  648.  
  649.     FT_UNUSED( valid );
  650.  
  651.  
  652.     /* reserved bits = 0 */
  653.     if ( coverage & 0xFDF0 )
  654.       return FALSE;
  655.  
  656. #ifdef GXV_LOAD_TRACE_VARS
  657.     horizontal   = FT_BOOL(   coverage        & 1 );
  658.     minimum      = FT_BOOL( ( coverage >> 1 ) & 1 );
  659.     cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 );
  660.     override     = FT_BOOL( ( coverage >> 3 ) & 1 );
  661. #endif
  662.  
  663.     *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 );
  664.  
  665.     GXV_TRACE(( "classic Microsoft-dialect: "
  666.                 "horizontal=%d, minimum=%d, cross-stream=%d, "
  667.                 "override=%d, format=%d\n",
  668.                 horizontal, minimum, cross_stream, override, *format ));
  669.  
  670.     if ( *format == 2 )
  671.       GXV_TRACE((
  672.         "kerning values in Microsoft format 2 subtable are ignored\n" ));
  673.  
  674.     return TRUE;
  675.   }
  676.  
  677.  
  678.   /*************************************************************************/
  679.   /*************************************************************************/
  680.   /*****                                                               *****/
  681.   /*****                            MAIN                               *****/
  682.   /*****                                                               *****/
  683.   /*************************************************************************/
  684.   /*************************************************************************/
  685.  
  686.   static GXV_kern_Dialect
  687.   gxv_kern_coverage_validate( FT_UShort      coverage,
  688.                               FT_UShort*     format,
  689.                               GXV_Validator  valid )
  690.   {
  691.     GXV_kern_Dialect  result = KERN_DIALECT_UNKNOWN;
  692.  
  693.  
  694.     GXV_NAME_ENTER( "validating coverage" );
  695.  
  696.     GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
  697.  
  698.     if ( KERN_IS_NEW( valid ) )
  699.     {
  700.       if ( gxv_kern_coverage_new_apple_validate( coverage,
  701.                                                  format,
  702.                                                  valid ) )
  703.       {
  704.         result = KERN_DIALECT_APPLE;
  705.         goto Exit;
  706.       }
  707.     }
  708.  
  709.     if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
  710.     {
  711.       if ( gxv_kern_coverage_classic_apple_validate( coverage,
  712.                                                      format,
  713.                                                      valid ) )
  714.       {
  715.         result = KERN_DIALECT_APPLE;
  716.         goto Exit;
  717.       }
  718.     }
  719.  
  720.     if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
  721.     {
  722.       if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
  723.                                                          format,
  724.                                                          valid ) )
  725.       {
  726.         result = KERN_DIALECT_MS;
  727.         goto Exit;
  728.       }
  729.     }
  730.  
  731.     GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
  732.  
  733.   Exit:
  734.     GXV_EXIT;
  735.     return result;
  736.   }
  737.  
  738.  
  739.   static void
  740.   gxv_kern_subtable_validate( FT_Bytes       table,
  741.                               FT_Bytes       limit,
  742.                               GXV_Validator  valid )
  743.   {
  744.     FT_Bytes   p = table;
  745. #ifdef GXV_LOAD_TRACE_VARS
  746.     FT_UShort  version = 0;    /* MS only: subtable version, unused */
  747. #endif
  748.     FT_ULong   length;         /* MS: 16bit, Apple: 32bit*/
  749.     FT_UShort  coverage;
  750. #ifdef GXV_LOAD_TRACE_VARS
  751.     FT_UShort  tupleIndex = 0; /* Apple only */
  752. #endif
  753.     FT_UShort  u16[2];
  754.     FT_UShort  format = 255;   /* subtable format */
  755.  
  756.  
  757.     GXV_NAME_ENTER( "kern subtable" );
  758.  
  759.     GXV_LIMIT_CHECK( 2 + 2 + 2 );
  760.     u16[0]   = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */
  761.     u16[1]   = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */
  762.     coverage = FT_NEXT_USHORT( p );
  763.  
  764.     switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
  765.     {
  766.     case KERN_DIALECT_MS:
  767. #ifdef GXV_LOAD_TRACE_VARS
  768.       version    = u16[0];
  769. #endif
  770.       length     = u16[1];
  771. #ifdef GXV_LOAD_TRACE_VARS
  772.       tupleIndex = 0;
  773. #endif
  774.       GXV_TRACE(( "Subtable version = %d\n", version ));
  775.       GXV_TRACE(( "Subtable length = %d\n", length ));
  776.       break;
  777.  
  778.     case KERN_DIALECT_APPLE:
  779. #ifdef GXV_LOAD_TRACE_VARS
  780.       version    = 0;
  781. #endif
  782.       length     = ( u16[0] << 16 ) + u16[1];
  783. #ifdef GXV_LOAD_TRACE_VARS
  784.       tupleIndex = 0;
  785. #endif
  786.       GXV_TRACE(( "Subtable length = %d\n", length ));
  787.  
  788.       if ( KERN_IS_NEW( valid ) )
  789.       {
  790.         GXV_LIMIT_CHECK( 2 );
  791. #ifdef GXV_LOAD_TRACE_VARS
  792.         tupleIndex = FT_NEXT_USHORT( p );
  793. #else
  794.         p += 2;
  795. #endif
  796.         GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
  797.       }
  798.       break;
  799.  
  800.     default:
  801.       length = u16[1];
  802.       GXV_TRACE(( "cannot detect subtable dialect, "
  803.                   "just skip %d byte\n", length ));
  804.       goto Exit;
  805.     }
  806.  
  807.     /* formats 1, 2, 3 require the position of the start of this subtable */
  808.     if ( format == 0 )
  809.       gxv_kern_subtable_fmt0_validate( table, table + length, valid );
  810.     else if ( format == 1 )
  811.       gxv_kern_subtable_fmt1_validate( table, table + length, valid );
  812.     else if ( format == 2 )
  813.       gxv_kern_subtable_fmt2_validate( table, table + length, valid );
  814.     else if ( format == 3 )
  815.       gxv_kern_subtable_fmt3_validate( table, table + length, valid );
  816.     else
  817.       FT_INVALID_DATA;
  818.  
  819.   Exit:
  820.     valid->subtable_length = length;
  821.     GXV_EXIT;
  822.   }
  823.  
  824.  
  825.   /*************************************************************************/
  826.   /*************************************************************************/
  827.   /*****                                                               *****/
  828.   /*****                         kern TABLE                            *****/
  829.   /*****                                                               *****/
  830.   /*************************************************************************/
  831.   /*************************************************************************/
  832.  
  833.   static void
  834.   gxv_kern_validate_generic( FT_Bytes          table,
  835.                              FT_Face           face,
  836.                              FT_Bool           classic_only,
  837.                              GXV_kern_Dialect  dialect_request,
  838.                              FT_Validator      ftvalid )
  839.   {
  840.     GXV_ValidatorRec   validrec;
  841.     GXV_Validator      valid = &validrec;
  842.  
  843.     GXV_kern_DataRec   kernrec;
  844.     GXV_kern_Data      kern = &kernrec;
  845.  
  846.     FT_Bytes           p     = table;
  847.     FT_Bytes           limit = 0;
  848.  
  849.     FT_ULong           nTables = 0;
  850.     FT_UInt            i;
  851.  
  852.  
  853.     valid->root       = ftvalid;
  854.     valid->table_data = kern;
  855.     valid->face       = face;
  856.  
  857.     FT_TRACE3(( "validating `kern' table\n" ));
  858.     GXV_INIT;
  859.     KERN_DIALECT( valid ) = dialect_request;
  860.  
  861.     GXV_LIMIT_CHECK( 2 );
  862.     GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p );
  863.     GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
  864.                 GXV_KERN_DATA( version ) ));
  865.  
  866.     if ( 0x0001 < GXV_KERN_DATA( version ) )
  867.       FT_INVALID_FORMAT;
  868.     else if ( KERN_IS_CLASSIC( valid ) )
  869.     {
  870.       GXV_LIMIT_CHECK( 2 );
  871.       nTables = FT_NEXT_USHORT( p );
  872.     }
  873.     else if ( KERN_IS_NEW( valid ) )
  874.     {
  875.       if ( classic_only )
  876.         FT_INVALID_FORMAT;
  877.  
  878.       if ( 0x0000 != FT_NEXT_USHORT( p ) )
  879.         FT_INVALID_FORMAT;
  880.  
  881.       GXV_LIMIT_CHECK( 4 );
  882.       nTables = FT_NEXT_ULONG( p );
  883.     }
  884.  
  885.     for ( i = 0; i < nTables; i++ )
  886.     {
  887.       GXV_TRACE(( "validating subtable %d/%d\n", i, nTables ));
  888.       /* p should be 32bit-aligned? */
  889.       gxv_kern_subtable_validate( p, 0, valid );
  890.       p += valid->subtable_length;
  891.     }
  892.  
  893.     FT_TRACE4(( "\n" ));
  894.   }
  895.  
  896.  
  897.   FT_LOCAL_DEF( void )
  898.   gxv_kern_validate( FT_Bytes      table,
  899.                      FT_Face       face,
  900.                      FT_Validator  ftvalid )
  901.   {
  902.     gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
  903.   }
  904.  
  905.  
  906.   FT_LOCAL_DEF( void )
  907.   gxv_kern_validate_classic( FT_Bytes      table,
  908.                              FT_Face       face,
  909.                              FT_Int        dialect_flags,
  910.                              FT_Validator  ftvalid )
  911.   {
  912.     GXV_kern_Dialect  dialect_request;
  913.  
  914.  
  915.     dialect_request = (GXV_kern_Dialect)dialect_flags;
  916.     gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
  917.   }
  918.  
  919.  
  920. /* END */
  921.