Home | History | Annotate | Download | only in gxvalid
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  gxvmorx2.c                                                             */
      4 /*                                                                         */
      5 /*    TrueTypeGX/AAT morx table validation                                 */
      6 /*    body for type2 (Ligature Substitution) subtable.                     */
      7 /*                                                                         */
      8 /*  Copyright 2005-2018 by                                                 */
      9 /*  suzuki toshiya, Masatake YAMATO, Red Hat K.K.,                         */
     10 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
     11 /*                                                                         */
     12 /*  This file is part of the FreeType project, and may only be used,       */
     13 /*  modified, and distributed under the terms of the FreeType project      */
     14 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     15 /*  this file you indicate that you have read the license and              */
     16 /*  understand and accept it fully.                                        */
     17 /*                                                                         */
     18 /***************************************************************************/
     19 
     20 /***************************************************************************/
     21 /*                                                                         */
     22 /* gxvalid is derived from both gxlayout module and otvalid module.        */
     23 /* Development of gxlayout is supported by the Information-technology      */
     24 /* Promotion Agency(IPA), Japan.                                           */
     25 /*                                                                         */
     26 /***************************************************************************/
     27 
     28 
     29 #include "gxvmorx.h"
     30 
     31 
     32   /*************************************************************************/
     33   /*                                                                       */
     34   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     35   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     36   /* messages during execution.                                            */
     37   /*                                                                       */
     38 #undef  FT_COMPONENT
     39 #define FT_COMPONENT  trace_gxvmorx
     40 
     41 
     42   typedef struct  GXV_morx_subtable_type2_StateOptRec_
     43   {
     44     FT_ULong  ligActionTable;
     45     FT_ULong  componentTable;
     46     FT_ULong  ligatureTable;
     47     FT_ULong  ligActionTable_length;
     48     FT_ULong  componentTable_length;
     49     FT_ULong  ligatureTable_length;
     50 
     51   }  GXV_morx_subtable_type2_StateOptRec,
     52     *GXV_morx_subtable_type2_StateOptRecData;
     53 
     54 
     55 #define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \
     56           ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 )
     57 
     58 
     59   static void
     60   gxv_morx_subtable_type2_opttable_load( FT_Bytes       table,
     61                                          FT_Bytes       limit,
     62                                          GXV_Validator  gxvalid )
     63   {
     64     FT_Bytes  p = table;
     65 
     66     GXV_morx_subtable_type2_StateOptRecData  optdata =
     67       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
     68 
     69 
     70     GXV_LIMIT_CHECK( 4 + 4 + 4 );
     71     optdata->ligActionTable = FT_NEXT_ULONG( p );
     72     optdata->componentTable = FT_NEXT_ULONG( p );
     73     optdata->ligatureTable  = FT_NEXT_ULONG( p );
     74 
     75     GXV_TRACE(( "offset to ligActionTable=0x%08x\n",
     76                 optdata->ligActionTable ));
     77     GXV_TRACE(( "offset to componentTable=0x%08x\n",
     78                 optdata->componentTable ));
     79     GXV_TRACE(( "offset to ligatureTable=0x%08x\n",
     80                 optdata->ligatureTable ));
     81   }
     82 
     83 
     84   static void
     85   gxv_morx_subtable_type2_subtable_setup( FT_ULong       table_size,
     86                                           FT_ULong       classTable,
     87                                           FT_ULong       stateArray,
     88                                           FT_ULong       entryTable,
     89                                           FT_ULong*      classTable_length_p,
     90                                           FT_ULong*      stateArray_length_p,
     91                                           FT_ULong*      entryTable_length_p,
     92                                           GXV_Validator  gxvalid )
     93   {
     94     FT_ULong   o[6];
     95     FT_ULong*  l[6];
     96     FT_ULong   buff[7];
     97 
     98     GXV_morx_subtable_type2_StateOptRecData  optdata =
     99       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
    100 
    101 
    102     GXV_NAME_ENTER( "subtable boundaries setup" );
    103 
    104     o[0] = classTable;
    105     o[1] = stateArray;
    106     o[2] = entryTable;
    107     o[3] = optdata->ligActionTable;
    108     o[4] = optdata->componentTable;
    109     o[5] = optdata->ligatureTable;
    110     l[0] = classTable_length_p;
    111     l[1] = stateArray_length_p;
    112     l[2] = entryTable_length_p;
    113     l[3] = &(optdata->ligActionTable_length);
    114     l[4] = &(optdata->componentTable_length);
    115     l[5] = &(optdata->ligatureTable_length);
    116 
    117     gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, gxvalid );
    118 
    119     GXV_TRACE(( "classTable: offset=0x%08x length=0x%08x\n",
    120                 classTable, *classTable_length_p ));
    121     GXV_TRACE(( "stateArray: offset=0x%08x length=0x%08x\n",
    122                 stateArray, *stateArray_length_p ));
    123     GXV_TRACE(( "entryTable: offset=0x%08x length=0x%08x\n",
    124                 entryTable, *entryTable_length_p ));
    125     GXV_TRACE(( "ligActionTable: offset=0x%08x length=0x%08x\n",
    126                 optdata->ligActionTable,
    127                 optdata->ligActionTable_length ));
    128     GXV_TRACE(( "componentTable: offset=0x%08x length=0x%08x\n",
    129                 optdata->componentTable,
    130                 optdata->componentTable_length ));
    131     GXV_TRACE(( "ligatureTable:  offset=0x%08x length=0x%08x\n",
    132                 optdata->ligatureTable,
    133                 optdata->ligatureTable_length ));
    134 
    135     GXV_EXIT;
    136   }
    137 
    138 
    139 #define GXV_MORX_LIGACTION_ENTRY_SIZE  4
    140 
    141 
    142   static void
    143   gxv_morx_subtable_type2_ligActionIndex_validate(
    144     FT_Bytes       table,
    145     FT_UShort      ligActionIndex,
    146     GXV_Validator  gxvalid )
    147   {
    148     /* access ligActionTable */
    149     GXV_morx_subtable_type2_StateOptRecData optdata =
    150       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
    151 
    152     FT_Bytes lat_base  = table + optdata->ligActionTable;
    153     FT_Bytes p         = lat_base +
    154                          ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE;
    155     FT_Bytes lat_limit = lat_base + optdata->ligActionTable;
    156 
    157 
    158     if ( p < lat_base )
    159     {
    160       GXV_TRACE(( "p < lat_base (%d byte rewind)\n", lat_base - p ));
    161       FT_INVALID_OFFSET;
    162     }
    163     else if ( lat_limit < p )
    164     {
    165       GXV_TRACE(( "lat_limit < p (%d byte overrun)\n", p - lat_limit ));
    166       FT_INVALID_OFFSET;
    167     }
    168 
    169     {
    170       /* validate entry in ligActionTable */
    171       FT_ULong   lig_action;
    172 #ifdef GXV_LOAD_UNUSED_VARS
    173       FT_UShort  last;
    174       FT_UShort  store;
    175 #endif
    176       FT_ULong   offset;
    177       FT_Long    gid_limit;
    178 
    179 
    180       lig_action = FT_NEXT_ULONG( p );
    181 #ifdef GXV_LOAD_UNUSED_VARS
    182       last       = (FT_UShort)( ( lig_action >> 31 ) & 1 );
    183       store      = (FT_UShort)( ( lig_action >> 30 ) & 1 );
    184 #endif
    185 
    186       offset = lig_action & 0x3FFFFFFFUL;
    187 
    188       /* this offset is 30-bit signed value to add to GID */
    189       /* it is different from the location offset in mort */
    190       if ( ( offset & 0x3FFF0000UL ) == 0x3FFF0000UL )
    191       { /* negative offset */
    192         gid_limit = gxvalid->face->num_glyphs -
    193                     (FT_Long)( offset & 0x0000FFFFUL );
    194         if ( gid_limit > 0 )
    195           return;
    196 
    197         GXV_TRACE(( "ligature action table includes"
    198                     " too negative offset moving all GID"
    199                     " below defined range: 0x%04x\n",
    200                     offset & 0xFFFFU ));
    201         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
    202       }
    203       else if ( ( offset & 0x3FFF0000UL ) == 0x00000000UL )
    204       { /* positive offset */
    205         if ( (FT_Long)offset < gxvalid->face->num_glyphs )
    206           return;
    207 
    208         GXV_TRACE(( "ligature action table includes"
    209                     " too large offset moving all GID"
    210                     " over defined range: 0x%04x\n",
    211                     offset & 0xFFFFU ));
    212         GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
    213       }
    214 
    215       GXV_TRACE(( "ligature action table includes"
    216                   " invalid offset to add to 16-bit GID:"
    217                   " 0x%08x\n", offset ));
    218       GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET );
    219     }
    220   }
    221 
    222 
    223   static void
    224   gxv_morx_subtable_type2_entry_validate(
    225     FT_UShort                       state,
    226     FT_UShort                       flags,
    227     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
    228     FT_Bytes                        table,
    229     FT_Bytes                        limit,
    230     GXV_Validator                   gxvalid )
    231   {
    232 #ifdef GXV_LOAD_UNUSED_VARS
    233     FT_UShort  setComponent;
    234     FT_UShort  dontAdvance;
    235     FT_UShort  performAction;
    236 #endif
    237     FT_UShort  reserved;
    238     FT_UShort  ligActionIndex;
    239 
    240     FT_UNUSED( state );
    241     FT_UNUSED( limit );
    242 
    243 
    244 #ifdef GXV_LOAD_UNUSED_VARS
    245     setComponent   = (FT_UShort)( ( flags >> 15 ) & 1 );
    246     dontAdvance    = (FT_UShort)( ( flags >> 14 ) & 1 );
    247     performAction  = (FT_UShort)( ( flags >> 13 ) & 1 );
    248 #endif
    249 
    250     reserved       = (FT_UShort)( flags & 0x1FFF );
    251     ligActionIndex = glyphOffset_p->u;
    252 
    253     if ( reserved > 0 )
    254       GXV_TRACE(( "  reserved 14bit is non-zero\n" ));
    255 
    256     if ( 0 < ligActionIndex )
    257       gxv_morx_subtable_type2_ligActionIndex_validate(
    258         table, ligActionIndex, gxvalid );
    259   }
    260 
    261 
    262   static void
    263   gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes       table,
    264                                                   GXV_Validator  gxvalid )
    265   {
    266     GXV_morx_subtable_type2_StateOptRecData  optdata =
    267       (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata;
    268 
    269     FT_Bytes p     = table + optdata->ligatureTable;
    270     FT_Bytes limit = table + optdata->ligatureTable
    271                            + optdata->ligatureTable_length;
    272 
    273 
    274     GXV_NAME_ENTER( "morx chain subtable type2 - substitutionTable" );
    275 
    276     if ( 0 != optdata->ligatureTable )
    277     {
    278       /* Apple does not give specification of ligatureTable format */
    279       while ( p < limit )
    280       {
    281         FT_UShort  lig_gid;
    282 
    283 
    284         GXV_LIMIT_CHECK( 2 );
    285         lig_gid = FT_NEXT_USHORT( p );
    286         if ( lig_gid < gxvalid->face->num_glyphs )
    287           GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
    288       }
    289     }
    290 
    291     GXV_EXIT;
    292   }
    293 
    294 
    295   FT_LOCAL_DEF( void )
    296   gxv_morx_subtable_type2_validate( FT_Bytes       table,
    297                                     FT_Bytes       limit,
    298                                     GXV_Validator  gxvalid )
    299   {
    300     FT_Bytes  p = table;
    301 
    302     GXV_morx_subtable_type2_StateOptRec  lig_rec;
    303 
    304 
    305     GXV_NAME_ENTER( "morx chain subtable type2 (Ligature Substitution)" );
    306 
    307     GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE );
    308 
    309     gxvalid->xstatetable.optdata =
    310       &lig_rec;
    311     gxvalid->xstatetable.optdata_load_func =
    312       gxv_morx_subtable_type2_opttable_load;
    313     gxvalid->xstatetable.subtable_setup_func =
    314       gxv_morx_subtable_type2_subtable_setup;
    315     gxvalid->xstatetable.entry_glyphoffset_fmt =
    316       GXV_GLYPHOFFSET_USHORT;
    317     gxvalid->xstatetable.entry_validate_func =
    318       gxv_morx_subtable_type2_entry_validate;
    319 
    320     gxv_XStateTable_validate( p, limit, gxvalid );
    321 
    322 #if 0
    323     p += gxvalid->subtable_length;
    324 #endif
    325     gxv_morx_subtable_type2_ligatureTable_validate( table, gxvalid );
    326 
    327     GXV_EXIT;
    328   }
    329 
    330 
    331 /* END */
    332