(root)/
freetype-2.13.2/
src/
gxvalid/
gxvkern.c
       1  /****************************************************************************
       2   *
       3   * gxvkern.c
       4   *
       5   *   TrueTypeGX/AAT kern table validation (body).
       6   *
       7   * Copyright (C) 2004-2023 by
       8   * suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
       9   * David Turner, Robert Wilhelm, and Werner Lemberg.
      10   *
      11   * This file is part of the FreeType project, and may only be used,
      12   * modified, and distributed under the terms of the FreeType project
      13   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      14   * this file you indicate that you have read the license and
      15   * understand and accept it fully.
      16   *
      17   */
      18  
      19  /****************************************************************************
      20   *
      21   * gxvalid is derived from both gxlayout module and otvalid module.
      22   * Development of gxlayout is supported by the Information-technology
      23   * Promotion Agency(IPA), Japan.
      24   *
      25   */
      26  
      27  
      28  #include "gxvalid.h"
      29  #include "gxvcommn.h"
      30  
      31  #include <freetype/ftsnames.h>
      32  #include <freetype/internal/services/svgxval.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  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( gxvalid )                               \
      83            ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
      84  #define KERN_IS_NEW( gxvalid )                                   \
      85            ( KERN_VERSION_NEW     == GXV_KERN_DATA( version ) )
      86  
      87  #define KERN_DIALECT( gxvalid )              \
      88            GXV_KERN_DATA( dialect_request )
      89  #define KERN_ALLOWS_MS( gxvalid )                       \
      90            ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_MS )
      91  #define KERN_ALLOWS_APPLE( gxvalid )                       \
      92            ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_APPLE )
      93  
      94  #define GXV_KERN_HEADER_SIZE           ( KERN_IS_NEW( gxvalid ) ? 8 : 4 )
      95  #define GXV_KERN_SUBTABLE_HEADER_SIZE  ( KERN_IS_NEW( gxvalid ) ? 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  gxvalid )
     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, gxvalid );
     138  
     139        /* right */
     140        gid_right = FT_NEXT_USHORT( p );
     141        gxv_glyphid_validate( gid_right, gxvalid );
     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  gxvalid )
     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, gxvalid );
     190      p += 2 + 2 + 2 + 2;
     191  
     192      gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, gxvalid );
     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  gxvalid )
     213    {
     214      FT_Bytes                       p = table;
     215      GXV_kern_fmt1_StateOptRecData  optdata =
     216        (GXV_kern_fmt1_StateOptRecData)gxvalid->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  gxvalid )
     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)gxvalid->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, gxvalid );
     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                   gxvalid )
     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)gxvalid->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  gxvalid )
     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      gxvalid->statetable.optdata =
     323        &vt_rec;
     324      gxvalid->statetable.optdata_load_func =
     325        gxv_kern_subtable_fmt1_valueTable_load;
     326      gxvalid->statetable.subtable_setup_func =
     327        gxv_kern_subtable_fmt1_subtable_setup;
     328      gxvalid->statetable.entry_glyphoffset_fmt =
     329        GXV_GLYPHOFFSET_NONE;
     330      gxvalid->statetable.entry_validate_func =
     331        gxv_kern_subtable_fmt1_entry_validate;
     332  
     333      gxv_StateTable_validate( p, limit, gxvalid );
     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       gxvalid )
     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, gxvalid );
     395      gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), gxvalid );
     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                                  gxvalid );
     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  gxvalid )
     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, gxvalid );
     443  
     444      gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
     445                                              GXV_KERN_CLS_R, gxvalid );
     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, gxvalid );
     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  gxvalid )
     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 ( gxvalid->face->num_glyphs != glyphCount )
     489      {
     490        GXV_TRACE(( "maxGID=%ld, but glyphCount=%d\n",
     491                    gxvalid->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, gxvalid );
     513        p += gxvalid->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, gxvalid );
     528        p += gxvalid->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      gxvalid->subtable_length = (FT_ULong)( 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  gxvalid )
     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( gxvalid );
     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  gxvalid )
     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( gxvalid ) )
     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  gxvalid )
     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( gxvalid );
     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  gxvalid )
     690    {
     691      GXV_kern_Dialect  result = KERN_DIALECT_UNKNOWN;
     692  
     693  
     694      GXV_NAME_ENTER( "validating coverage" );
     695  
     696      GXV_TRACE(( "interpret coverage 0x%04x by Apple style\n", coverage ));
     697  
     698      if ( KERN_IS_NEW( gxvalid ) )
     699      {
     700        if ( gxv_kern_coverage_new_apple_validate( coverage,
     701                                                   format,
     702                                                   gxvalid ) )
     703        {
     704          result = KERN_DIALECT_APPLE;
     705          goto Exit;
     706        }
     707      }
     708  
     709      if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_APPLE( gxvalid ) )
     710      {
     711        if ( gxv_kern_coverage_classic_apple_validate( coverage,
     712                                                       format,
     713                                                       gxvalid ) )
     714        {
     715          result = KERN_DIALECT_APPLE;
     716          goto Exit;
     717        }
     718      }
     719  
     720      if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_MS( gxvalid ) )
     721      {
     722        if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
     723                                                           format,
     724                                                           gxvalid ) )
     725        {
     726          result = KERN_DIALECT_MS;
     727          goto Exit;
     728        }
     729      }
     730  
     731      GXV_TRACE(( "cannot interpret 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  gxvalid )
     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, gxvalid ) )
     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 = %lu\n", length ));
     776        break;
     777  
     778      case KERN_DIALECT_APPLE:
     779  #ifdef GXV_LOAD_TRACE_VARS
     780        version    = 0;
     781  #endif
     782        length     = ( (FT_ULong)u16[0] << 16 ) + u16[1];
     783  #ifdef GXV_LOAD_TRACE_VARS
     784        tupleIndex = 0;
     785  #endif
     786        GXV_TRACE(( "Subtable length = %lu\n", length ));
     787  
     788        if ( KERN_IS_NEW( gxvalid ) )
     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 %lu 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, gxvalid );
     810      else if ( format == 1 )
     811        gxv_kern_subtable_fmt1_validate( table, table + length, gxvalid );
     812      else if ( format == 2 )
     813        gxv_kern_subtable_fmt2_validate( table, table + length, gxvalid );
     814      else if ( format == 3 )
     815        gxv_kern_subtable_fmt3_validate( table, table + length, gxvalid );
     816      else
     817        FT_INVALID_DATA;
     818  
     819    Exit:
     820      gxvalid->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   gxvalidrec;
     841      GXV_Validator      gxvalid = &gxvalidrec;
     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      gxvalid->root       = ftvalid;
     854      gxvalid->table_data = kern;
     855      gxvalid->face       = face;
     856  
     857      FT_TRACE3(( "validating `kern' table\n" ));
     858      GXV_INIT;
     859      KERN_DIALECT( gxvalid ) = 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( gxvalid ) )
     869      {
     870        GXV_LIMIT_CHECK( 2 );
     871        nTables = FT_NEXT_USHORT( p );
     872      }
     873      else if ( KERN_IS_NEW( gxvalid ) )
     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/%lu\n", i, nTables ));
     888        /* p should be 32bit-aligned? */
     889        gxv_kern_subtable_validate( p, 0, gxvalid );
     890        p += gxvalid->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 */