(root)/
freetype-2.13.2/
src/
otvalid/
otvgsub.c
       1  /****************************************************************************
       2   *
       3   * otvgsub.c
       4   *
       5   *   OpenType GSUB table validation (body).
       6   *
       7   * Copyright (C) 2004-2023 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 %d)\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 = %d)\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 %d)\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 %d)\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 = %d)\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 %d)\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 %d)\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 %d)\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 %d)\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 %d)\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 = %d)\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 = %d)\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 = %d)\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 */