tor-browser

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

otvgsub.c (18463B)


      1 /****************************************************************************
      2 *
      3 * otvgsub.c
      4 *
      5 *   OpenType GSUB table validation (body).
      6 *
      7 * Copyright (C) 2004-2025 by
      8 * David Turner, Robert Wilhelm, and Werner Lemberg.
      9 *
     10 * This file is part of the FreeType project, and may only be used,
     11 * modified, and distributed under the terms of the FreeType project
     12 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     13 * this file you indicate that you have read the license and
     14 * understand and accept it fully.
     15 *
     16 */
     17 
     18 
     19 #include "otvalid.h"
     20 #include "otvcommn.h"
     21 
     22 
     23  /**************************************************************************
     24   *
     25   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     26   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     27   * messages during execution.
     28   */
     29 #undef  FT_COMPONENT
     30 #define FT_COMPONENT  otvgsub
     31 
     32 
     33  /*************************************************************************/
     34  /*************************************************************************/
     35  /*****                                                               *****/
     36  /*****                  GSUB LOOKUP TYPE 1                           *****/
     37  /*****                                                               *****/
     38  /*************************************************************************/
     39  /*************************************************************************/
     40 
     41  /* uses otvalid->glyph_count */
     42 
     43  static void
     44  otv_SingleSubst_validate( FT_Bytes       table,
     45                            OTV_Validator  otvalid )
     46  {
     47    FT_Bytes  p = table;
     48    FT_UInt   SubstFormat;
     49 
     50 
     51    OTV_NAME_ENTER( "SingleSubst" );
     52 
     53    OTV_LIMIT_CHECK( 2 );
     54    SubstFormat = FT_NEXT_USHORT( p );
     55 
     56    OTV_TRACE(( " (format %u)\n", SubstFormat ));
     57 
     58    switch ( SubstFormat )
     59    {
     60    case 1:     /* SingleSubstFormat1 */
     61      {
     62        FT_Bytes  Coverage;
     63        FT_Int    DeltaGlyphID;
     64        FT_UInt   first_cov, last_cov;
     65        FT_UInt   first_idx, last_idx;
     66 
     67 
     68        OTV_LIMIT_CHECK( 4 );
     69        Coverage     = table + FT_NEXT_USHORT( p );
     70        DeltaGlyphID = FT_NEXT_SHORT( p );
     71 
     72        otv_Coverage_validate( Coverage, otvalid, -1 );
     73 
     74        first_cov = otv_Coverage_get_first( Coverage );
     75        last_cov  = otv_Coverage_get_last( Coverage );
     76 
     77        /* These additions are modulo 65536. */
     78        first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU;
     79        last_idx  = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU;
     80 
     81        /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */
     82        /* the largest possible glyph index is 65534.  For this    */
     83        /* reason there can't be a wrap-around region, which would */
     84        /* imply the use of the invalid glyph index 65535.         */
     85        if ( first_idx > last_idx )
     86          FT_INVALID_DATA;
     87 
     88        if ( last_idx >= otvalid->glyph_count )
     89          FT_INVALID_DATA;
     90      }
     91      break;
     92 
     93    case 2:     /* SingleSubstFormat2 */
     94      {
     95        FT_UInt  Coverage, GlyphCount;
     96 
     97 
     98        OTV_LIMIT_CHECK( 4 );
     99        Coverage   = FT_NEXT_USHORT( p );
    100        GlyphCount = FT_NEXT_USHORT( p );
    101 
    102        OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount ));
    103 
    104        otv_Coverage_validate( table + Coverage,
    105                               otvalid,
    106                               (FT_Int)GlyphCount );
    107 
    108        OTV_LIMIT_CHECK( GlyphCount * 2 );
    109 
    110        /* Substitute */
    111        for ( ; GlyphCount > 0; GlyphCount-- )
    112          if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
    113            FT_INVALID_GLYPH_ID;
    114      }
    115      break;
    116 
    117    default:
    118      FT_INVALID_FORMAT;
    119    }
    120 
    121    OTV_EXIT;
    122  }
    123 
    124 
    125  /*************************************************************************/
    126  /*************************************************************************/
    127  /*****                                                               *****/
    128  /*****                  GSUB LOOKUP TYPE 2                           *****/
    129  /*****                                                               *****/
    130  /*************************************************************************/
    131  /*************************************************************************/
    132 
    133  /* sets otvalid->extra1 (glyph count) */
    134 
    135  static void
    136  otv_MultipleSubst_validate( FT_Bytes       table,
    137                              OTV_Validator  otvalid )
    138  {
    139    FT_Bytes  p = table;
    140    FT_UInt   SubstFormat;
    141 
    142 
    143    OTV_NAME_ENTER( "MultipleSubst" );
    144 
    145    OTV_LIMIT_CHECK( 2 );
    146    SubstFormat = FT_NEXT_USHORT( p );
    147 
    148    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    149 
    150    switch ( SubstFormat )
    151    {
    152    case 1:
    153      otvalid->extra1 = otvalid->glyph_count;
    154      OTV_NEST2( MultipleSubstFormat1, Sequence );
    155      OTV_RUN( table, otvalid );
    156      break;
    157 
    158    default:
    159      FT_INVALID_FORMAT;
    160    }
    161 
    162    OTV_EXIT;
    163  }
    164 
    165 
    166  /*************************************************************************/
    167  /*************************************************************************/
    168  /*****                                                               *****/
    169  /*****                    GSUB LOOKUP TYPE 3                         *****/
    170  /*****                                                               *****/
    171  /*************************************************************************/
    172  /*************************************************************************/
    173 
    174  /* sets otvalid->extra1 (glyph count) */
    175 
    176  static void
    177  otv_AlternateSubst_validate( FT_Bytes       table,
    178                               OTV_Validator  otvalid )
    179  {
    180    FT_Bytes  p = table;
    181    FT_UInt   SubstFormat;
    182 
    183 
    184    OTV_NAME_ENTER( "AlternateSubst" );
    185 
    186    OTV_LIMIT_CHECK( 2 );
    187    SubstFormat = FT_NEXT_USHORT( p );
    188 
    189    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    190 
    191    switch ( SubstFormat )
    192    {
    193    case 1:
    194      otvalid->extra1 = otvalid->glyph_count;
    195      OTV_NEST2( AlternateSubstFormat1, AlternateSet );
    196      OTV_RUN( table, otvalid );
    197      break;
    198 
    199    default:
    200      FT_INVALID_FORMAT;
    201    }
    202 
    203    OTV_EXIT;
    204  }
    205 
    206 
    207  /*************************************************************************/
    208  /*************************************************************************/
    209  /*****                                                               *****/
    210  /*****                    GSUB LOOKUP TYPE 4                         *****/
    211  /*****                                                               *****/
    212  /*************************************************************************/
    213  /*************************************************************************/
    214 
    215 #define LigatureFunc  otv_Ligature_validate
    216 
    217  /* uses otvalid->glyph_count */
    218 
    219  static void
    220  otv_Ligature_validate( FT_Bytes       table,
    221                         OTV_Validator  otvalid )
    222  {
    223    FT_Bytes  p = table;
    224    FT_UInt   LigatureGlyph, CompCount;
    225 
    226 
    227    OTV_ENTER;
    228 
    229    OTV_LIMIT_CHECK( 4 );
    230    LigatureGlyph = FT_NEXT_USHORT( p );
    231    if ( LigatureGlyph >= otvalid->glyph_count )
    232      FT_INVALID_DATA;
    233 
    234    CompCount = FT_NEXT_USHORT( p );
    235 
    236    OTV_TRACE(( " (CompCount = %u)\n", CompCount ));
    237 
    238    if ( CompCount == 0 )
    239      FT_INVALID_DATA;
    240 
    241    CompCount--;
    242 
    243    OTV_LIMIT_CHECK( CompCount * 2 );     /* Component */
    244 
    245    /* no need to check the Component glyph indices */
    246 
    247    OTV_EXIT;
    248  }
    249 
    250 
    251  static void
    252  otv_LigatureSubst_validate( FT_Bytes       table,
    253                              OTV_Validator  otvalid )
    254  {
    255    FT_Bytes  p = table;
    256    FT_UInt   SubstFormat;
    257 
    258 
    259    OTV_NAME_ENTER( "LigatureSubst" );
    260 
    261    OTV_LIMIT_CHECK( 2 );
    262    SubstFormat = FT_NEXT_USHORT( p );
    263 
    264    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    265 
    266    switch ( SubstFormat )
    267    {
    268    case 1:
    269      OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature );
    270      OTV_RUN( table, otvalid );
    271      break;
    272 
    273    default:
    274      FT_INVALID_FORMAT;
    275    }
    276 
    277    OTV_EXIT;
    278  }
    279 
    280 
    281  /*************************************************************************/
    282  /*************************************************************************/
    283  /*****                                                               *****/
    284  /*****                  GSUB LOOKUP TYPE 5                           *****/
    285  /*****                                                               *****/
    286  /*************************************************************************/
    287  /*************************************************************************/
    288 
    289  /* sets otvalid->extra1 (lookup count) */
    290 
    291  static void
    292  otv_ContextSubst_validate( FT_Bytes       table,
    293                             OTV_Validator  otvalid )
    294  {
    295    FT_Bytes  p = table;
    296    FT_UInt   SubstFormat;
    297 
    298 
    299    OTV_NAME_ENTER( "ContextSubst" );
    300 
    301    OTV_LIMIT_CHECK( 2 );
    302    SubstFormat = FT_NEXT_USHORT( p );
    303 
    304    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    305 
    306    switch ( SubstFormat )
    307    {
    308    case 1:
    309      /* no need to check glyph indices/classes used as input for these */
    310      /* context rules since even invalid glyph indices/classes return  */
    311      /* meaningful results                                             */
    312 
    313      otvalid->extra1 = otvalid->lookup_count;
    314      OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
    315      OTV_RUN( table, otvalid );
    316      break;
    317 
    318    case 2:
    319      /* no need to check glyph indices/classes used as input for these */
    320      /* context rules since even invalid glyph indices/classes return  */
    321      /* meaningful results                                             */
    322 
    323      OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule );
    324      OTV_RUN( table, otvalid );
    325      break;
    326 
    327    case 3:
    328      OTV_NEST1( ContextSubstFormat3 );
    329      OTV_RUN( table, otvalid );
    330      break;
    331 
    332    default:
    333      FT_INVALID_FORMAT;
    334    }
    335 
    336    OTV_EXIT;
    337  }
    338 
    339 
    340  /*************************************************************************/
    341  /*************************************************************************/
    342  /*****                                                               *****/
    343  /*****                    GSUB LOOKUP TYPE 6                         *****/
    344  /*****                                                               *****/
    345  /*************************************************************************/
    346  /*************************************************************************/
    347 
    348  /* sets otvalid->extra1 (lookup count)            */
    349 
    350  static void
    351  otv_ChainContextSubst_validate( FT_Bytes       table,
    352                                  OTV_Validator  otvalid )
    353  {
    354    FT_Bytes  p = table;
    355    FT_UInt   SubstFormat;
    356 
    357 
    358    OTV_NAME_ENTER( "ChainContextSubst" );
    359 
    360    OTV_LIMIT_CHECK( 2 );
    361    SubstFormat = FT_NEXT_USHORT( p );
    362 
    363    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    364 
    365    switch ( SubstFormat )
    366    {
    367    case 1:
    368      /* no need to check glyph indices/classes used as input for these */
    369      /* context rules since even invalid glyph indices/classes return  */
    370      /* meaningful results                                             */
    371 
    372      otvalid->extra1 = otvalid->lookup_count;
    373      OTV_NEST3( ChainContextSubstFormat1,
    374                 ChainSubRuleSet, ChainSubRule );
    375      OTV_RUN( table, otvalid );
    376      break;
    377 
    378    case 2:
    379      /* no need to check glyph indices/classes used as input for these */
    380      /* context rules since even invalid glyph indices/classes return  */
    381      /* meaningful results                                             */
    382 
    383      OTV_NEST3( ChainContextSubstFormat2,
    384                 ChainSubClassSet, ChainSubClassRule );
    385      OTV_RUN( table, otvalid );
    386      break;
    387 
    388    case 3:
    389      OTV_NEST1( ChainContextSubstFormat3 );
    390      OTV_RUN( table, otvalid );
    391      break;
    392 
    393    default:
    394      FT_INVALID_FORMAT;
    395    }
    396 
    397    OTV_EXIT;
    398  }
    399 
    400 
    401  /*************************************************************************/
    402  /*************************************************************************/
    403  /*****                                                               *****/
    404  /*****                    GSUB LOOKUP TYPE 7                         *****/
    405  /*****                                                               *****/
    406  /*************************************************************************/
    407  /*************************************************************************/
    408 
    409  /* uses otvalid->type_funcs */
    410 
    411  static void
    412  otv_ExtensionSubst_validate( FT_Bytes       table,
    413                               OTV_Validator  otvalid )
    414  {
    415    FT_Bytes  p = table;
    416    FT_UInt   SubstFormat;
    417 
    418 
    419    OTV_NAME_ENTER( "ExtensionSubst" );
    420 
    421    OTV_LIMIT_CHECK( 2 );
    422    SubstFormat = FT_NEXT_USHORT( p );
    423 
    424    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    425 
    426    switch ( SubstFormat )
    427    {
    428    case 1:     /* ExtensionSubstFormat1 */
    429      {
    430        FT_UInt            ExtensionLookupType;
    431        FT_ULong           ExtensionOffset;
    432        OTV_Validate_Func  validate;
    433 
    434 
    435        OTV_LIMIT_CHECK( 6 );
    436        ExtensionLookupType = FT_NEXT_USHORT( p );
    437        ExtensionOffset     = FT_NEXT_ULONG( p );
    438 
    439        if ( ExtensionLookupType == 0 ||
    440             ExtensionLookupType == 7 ||
    441             ExtensionLookupType > 8  )
    442          FT_INVALID_DATA;
    443 
    444        validate = otvalid->type_funcs[ExtensionLookupType - 1];
    445        validate( table + ExtensionOffset, otvalid );
    446      }
    447      break;
    448 
    449    default:
    450      FT_INVALID_FORMAT;
    451    }
    452 
    453    OTV_EXIT;
    454  }
    455 
    456 
    457  /*************************************************************************/
    458  /*************************************************************************/
    459  /*****                                                               *****/
    460  /*****                    GSUB LOOKUP TYPE 8                         *****/
    461  /*****                                                               *****/
    462  /*************************************************************************/
    463  /*************************************************************************/
    464 
    465  /* uses otvalid->glyph_count */
    466 
    467  static void
    468  otv_ReverseChainSingleSubst_validate( FT_Bytes       table,
    469                                        OTV_Validator  otvalid )
    470  {
    471    FT_Bytes  p = table, Coverage;
    472    FT_UInt   SubstFormat;
    473    FT_UInt   BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount;
    474 
    475 
    476    OTV_NAME_ENTER( "ReverseChainSingleSubst" );
    477 
    478    OTV_LIMIT_CHECK( 2 );
    479    SubstFormat = FT_NEXT_USHORT( p );
    480 
    481    OTV_TRACE(( " (format %u)\n", SubstFormat ));
    482 
    483    switch ( SubstFormat )
    484    {
    485    case 1:     /* ReverseChainSingleSubstFormat1 */
    486      OTV_LIMIT_CHECK( 4 );
    487      Coverage            = table + FT_NEXT_USHORT( p );
    488      BacktrackGlyphCount = FT_NEXT_USHORT( p );
    489 
    490      OTV_TRACE(( " (BacktrackGlyphCount = %u)\n", BacktrackGlyphCount ));
    491 
    492      otv_Coverage_validate( Coverage, otvalid, -1 );
    493 
    494      OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
    495 
    496      for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
    497        otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
    498 
    499      LookaheadGlyphCount = FT_NEXT_USHORT( p );
    500 
    501      OTV_TRACE(( " (LookaheadGlyphCount = %u)\n", LookaheadGlyphCount ));
    502 
    503      OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
    504 
    505      for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
    506        otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
    507 
    508      GlyphCount = FT_NEXT_USHORT( p );
    509 
    510      OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount ));
    511 
    512      if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
    513        FT_INVALID_DATA;
    514 
    515      OTV_LIMIT_CHECK( GlyphCount * 2 );
    516 
    517      /* Substitute */
    518      for ( ; GlyphCount > 0; GlyphCount-- )
    519        if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
    520          FT_INVALID_DATA;
    521 
    522      break;
    523 
    524    default:
    525      FT_INVALID_FORMAT;
    526    }
    527 
    528    OTV_EXIT;
    529  }
    530 
    531 
    532  static const OTV_Validate_Func  otv_gsub_validate_funcs[8] =
    533  {
    534    otv_SingleSubst_validate,
    535    otv_MultipleSubst_validate,
    536    otv_AlternateSubst_validate,
    537    otv_LigatureSubst_validate,
    538    otv_ContextSubst_validate,
    539    otv_ChainContextSubst_validate,
    540    otv_ExtensionSubst_validate,
    541    otv_ReverseChainSingleSubst_validate
    542  };
    543 
    544 
    545  /*************************************************************************/
    546  /*************************************************************************/
    547  /*****                                                               *****/
    548  /*****                          GSUB TABLE                           *****/
    549  /*****                                                               *****/
    550  /*************************************************************************/
    551  /*************************************************************************/
    552 
    553  /* sets otvalid->type_count  */
    554  /* sets otvalid->type_funcs  */
    555  /* sets otvalid->glyph_count */
    556 
    557  FT_LOCAL_DEF( void )
    558  otv_GSUB_validate( FT_Bytes      table,
    559                     FT_UInt       glyph_count,
    560                     FT_Validator  ftvalid )
    561  {
    562    OTV_ValidatorRec  otvalidrec;
    563    OTV_Validator     otvalid = &otvalidrec;
    564    FT_Bytes          p       = table;
    565    FT_UInt           table_size;
    566    FT_UShort         version;
    567    FT_UInt           ScriptList, FeatureList, LookupList;
    568 
    569    OTV_OPTIONAL_TABLE32( featureVariations );
    570 
    571 
    572    otvalid->root = ftvalid;
    573 
    574    FT_TRACE3(( "validating GSUB table\n" ));
    575    OTV_INIT;
    576 
    577    OTV_LIMIT_CHECK( 4 );
    578 
    579    if ( FT_NEXT_USHORT( p ) != 1 )  /* majorVersion */
    580      FT_INVALID_FORMAT;
    581 
    582    version = FT_NEXT_USHORT( p );   /* minorVersion */
    583 
    584    table_size = 10;
    585    switch ( version )
    586    {
    587    case 0:
    588      OTV_LIMIT_CHECK( 6 );
    589      break;
    590 
    591    case 1:
    592      OTV_LIMIT_CHECK( 10 );
    593      table_size += 4;
    594      break;
    595 
    596    default:
    597      FT_INVALID_FORMAT;
    598    }
    599 
    600    ScriptList  = FT_NEXT_USHORT( p );
    601    FeatureList = FT_NEXT_USHORT( p );
    602    LookupList  = FT_NEXT_USHORT( p );
    603 
    604    otvalid->type_count  = 8;
    605    otvalid->type_funcs  = (OTV_Validate_Func*)otv_gsub_validate_funcs;
    606    otvalid->glyph_count = glyph_count;
    607 
    608    otv_LookupList_validate( table + LookupList,
    609                             otvalid );
    610    otv_FeatureList_validate( table + FeatureList, table + LookupList,
    611                              otvalid );
    612    otv_ScriptList_validate( table + ScriptList, table + FeatureList,
    613                             otvalid );
    614 
    615    if ( version > 0 )
    616    {
    617      OTV_OPTIONAL_OFFSET32( featureVariations );
    618      OTV_SIZE_CHECK32( featureVariations );
    619      if ( featureVariations )
    620        OTV_TRACE(( "  [omitting featureVariations validation]\n" )); /* XXX */
    621    }
    622 
    623    FT_TRACE4(( "\n" ));
    624  }
    625 
    626 
    627 /* END */