tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gxvkern.c (27203B)


      1 /****************************************************************************
      2 *
      3 * gxvkern.c
      4 *
      5 *   TrueTypeGX/AAT kern table validation (body).
      6 *
      7 * Copyright (C) 2004-2025 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 %u/%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 */