Edit

kc3-lang/freetype/src/otvalid/otvgsub.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2021-01-17 07:18:48
    Hash : b6e8a712
    Message : Update all copyright notices.

  • src/otvalid/otvgsub.c
  • /****************************************************************************
     *
     * otvgsub.c
     *
     *   OpenType GSUB table validation (body).
     *
     * Copyright (C) 2004-2021 by
     * David Turner, Robert Wilhelm, and Werner Lemberg.
     *
     * This file is part of the FreeType project, and may only be used,
     * modified, and distributed under the terms of the FreeType project
     * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     * this file you indicate that you have read the license and
     * understand and accept it fully.
     *
     */
    
    
    #include "otvalid.h"
    #include "otvcommn.h"
    
    
      /**************************************************************************
       *
       * The macro FT_COMPONENT is used in trace mode.  It is an implicit
       * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
       * messages during execution.
       */
    #undef  FT_COMPONENT
    #define FT_COMPONENT  otvgsub
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                  GSUB LOOKUP TYPE 1                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* uses otvalid->glyph_count */
    
      static void
      otv_SingleSubst_validate( FT_Bytes       table,
                                OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "SingleSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:     /* SingleSubstFormat1 */
          {
            FT_Bytes  Coverage;
            FT_Int    DeltaGlyphID;
            FT_Long   idx;
    
    
            OTV_LIMIT_CHECK( 4 );
            Coverage     = table + FT_NEXT_USHORT( p );
            DeltaGlyphID = FT_NEXT_SHORT( p );
    
            otv_Coverage_validate( Coverage, otvalid, -1 );
    
            idx = (FT_Long)otv_Coverage_get_first( Coverage ) + DeltaGlyphID;
            if ( idx < 0 )
              FT_INVALID_DATA;
    
            idx = (FT_Long)otv_Coverage_get_last( Coverage ) + DeltaGlyphID;
            if ( (FT_UInt)idx >= otvalid->glyph_count )
              FT_INVALID_DATA;
          }
          break;
    
        case 2:     /* SingleSubstFormat2 */
          {
            FT_UInt  Coverage, GlyphCount;
    
    
            OTV_LIMIT_CHECK( 4 );
            Coverage   = FT_NEXT_USHORT( p );
            GlyphCount = FT_NEXT_USHORT( p );
    
            OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
    
            otv_Coverage_validate( table + Coverage,
                                   otvalid,
                                   (FT_Int)GlyphCount );
    
            OTV_LIMIT_CHECK( GlyphCount * 2 );
    
            /* Substitute */
            for ( ; GlyphCount > 0; GlyphCount-- )
              if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
                FT_INVALID_GLYPH_ID;
          }
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                  GSUB LOOKUP TYPE 2                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* sets otvalid->extra1 (glyph count) */
    
      static void
      otv_MultipleSubst_validate( FT_Bytes       table,
                                  OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "MultipleSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:
          otvalid->extra1 = otvalid->glyph_count;
          OTV_NEST2( MultipleSubstFormat1, Sequence );
          OTV_RUN( table, otvalid );
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    GSUB LOOKUP TYPE 3                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* sets otvalid->extra1 (glyph count) */
    
      static void
      otv_AlternateSubst_validate( FT_Bytes       table,
                                   OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "AlternateSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:
          otvalid->extra1 = otvalid->glyph_count;
          OTV_NEST2( AlternateSubstFormat1, AlternateSet );
          OTV_RUN( table, otvalid );
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    GSUB LOOKUP TYPE 4                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
    #define LigatureFunc  otv_Ligature_validate
    
      /* uses otvalid->glyph_count */
    
      static void
      otv_Ligature_validate( FT_Bytes       table,
                             OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   LigatureGlyph, CompCount;
    
    
        OTV_ENTER;
    
        OTV_LIMIT_CHECK( 4 );
        LigatureGlyph = FT_NEXT_USHORT( p );
        if ( LigatureGlyph >= otvalid->glyph_count )
          FT_INVALID_DATA;
    
        CompCount = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (CompCount = %d)\n", CompCount ));
    
        if ( CompCount == 0 )
          FT_INVALID_DATA;
    
        CompCount--;
    
        OTV_LIMIT_CHECK( CompCount * 2 );     /* Component */
    
        /* no need to check the Component glyph indices */
    
        OTV_EXIT;
      }
    
    
      static void
      otv_LigatureSubst_validate( FT_Bytes       table,
                                  OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "LigatureSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:
          OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature );
          OTV_RUN( table, otvalid );
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                  GSUB LOOKUP TYPE 5                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* sets otvalid->extra1 (lookup count) */
    
      static void
      otv_ContextSubst_validate( FT_Bytes       table,
                                 OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "ContextSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:
          /* no need to check glyph indices/classes used as input for these */
          /* context rules since even invalid glyph indices/classes return  */
          /* meaningful results                                             */
    
          otvalid->extra1 = otvalid->lookup_count;
          OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
          OTV_RUN( table, otvalid );
          break;
    
        case 2:
          /* no need to check glyph indices/classes used as input for these */
          /* context rules since even invalid glyph indices/classes return  */
          /* meaningful results                                             */
    
          OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule );
          OTV_RUN( table, otvalid );
          break;
    
        case 3:
          OTV_NEST1( ContextSubstFormat3 );
          OTV_RUN( table, otvalid );
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    GSUB LOOKUP TYPE 6                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* sets otvalid->extra1 (lookup count)            */
    
      static void
      otv_ChainContextSubst_validate( FT_Bytes       table,
                                      OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "ChainContextSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:
          /* no need to check glyph indices/classes used as input for these */
          /* context rules since even invalid glyph indices/classes return  */
          /* meaningful results                                             */
    
          otvalid->extra1 = otvalid->lookup_count;
          OTV_NEST3( ChainContextSubstFormat1,
                     ChainSubRuleSet, ChainSubRule );
          OTV_RUN( table, otvalid );
          break;
    
        case 2:
          /* no need to check glyph indices/classes used as input for these */
          /* context rules since even invalid glyph indices/classes return  */
          /* meaningful results                                             */
    
          OTV_NEST3( ChainContextSubstFormat2,
                     ChainSubClassSet, ChainSubClassRule );
          OTV_RUN( table, otvalid );
          break;
    
        case 3:
          OTV_NEST1( ChainContextSubstFormat3 );
          OTV_RUN( table, otvalid );
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    GSUB LOOKUP TYPE 7                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* uses otvalid->type_funcs */
    
      static void
      otv_ExtensionSubst_validate( FT_Bytes       table,
                                   OTV_Validator  otvalid )
      {
        FT_Bytes  p = table;
        FT_UInt   SubstFormat;
    
    
        OTV_NAME_ENTER( "ExtensionSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:     /* ExtensionSubstFormat1 */
          {
            FT_UInt            ExtensionLookupType;
            FT_ULong           ExtensionOffset;
            OTV_Validate_Func  validate;
    
    
            OTV_LIMIT_CHECK( 6 );
            ExtensionLookupType = FT_NEXT_USHORT( p );
            ExtensionOffset     = FT_NEXT_ULONG( p );
    
            if ( ExtensionLookupType == 0 ||
                 ExtensionLookupType == 7 ||
                 ExtensionLookupType > 8  )
              FT_INVALID_DATA;
    
            validate = otvalid->type_funcs[ExtensionLookupType - 1];
            validate( table + ExtensionOffset, otvalid );
          }
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    GSUB LOOKUP TYPE 8                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* uses otvalid->glyph_count */
    
      static void
      otv_ReverseChainSingleSubst_validate( FT_Bytes       table,
                                            OTV_Validator  otvalid )
      {
        FT_Bytes  p = table, Coverage;
        FT_UInt   SubstFormat;
        FT_UInt   BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount;
    
    
        OTV_NAME_ENTER( "ReverseChainSingleSubst" );
    
        OTV_LIMIT_CHECK( 2 );
        SubstFormat = FT_NEXT_USHORT( p );
    
        OTV_TRACE(( " (format %d)\n", SubstFormat ));
    
        switch ( SubstFormat )
        {
        case 1:     /* ReverseChainSingleSubstFormat1 */
          OTV_LIMIT_CHECK( 4 );
          Coverage            = table + FT_NEXT_USHORT( p );
          BacktrackGlyphCount = FT_NEXT_USHORT( p );
    
          OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount ));
    
          otv_Coverage_validate( Coverage, otvalid, -1 );
    
          OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
    
          for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
            otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
    
          LookaheadGlyphCount = FT_NEXT_USHORT( p );
    
          OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount ));
    
          OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
    
          for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
            otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
    
          GlyphCount = FT_NEXT_USHORT( p );
    
          OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
    
          if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
            FT_INVALID_DATA;
    
          OTV_LIMIT_CHECK( GlyphCount * 2 );
    
          /* Substitute */
          for ( ; GlyphCount > 0; GlyphCount-- )
            if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
              FT_INVALID_DATA;
    
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        OTV_EXIT;
      }
    
    
      static const OTV_Validate_Func  otv_gsub_validate_funcs[8] =
      {
        otv_SingleSubst_validate,
        otv_MultipleSubst_validate,
        otv_AlternateSubst_validate,
        otv_LigatureSubst_validate,
        otv_ContextSubst_validate,
        otv_ChainContextSubst_validate,
        otv_ExtensionSubst_validate,
        otv_ReverseChainSingleSubst_validate
      };
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                          GSUB TABLE                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* sets otvalid->type_count  */
      /* sets otvalid->type_funcs  */
      /* sets otvalid->glyph_count */
    
      FT_LOCAL_DEF( void )
      otv_GSUB_validate( FT_Bytes      table,
                         FT_UInt       glyph_count,
                         FT_Validator  ftvalid )
      {
        OTV_ValidatorRec  otvalidrec;
        OTV_Validator     otvalid = &otvalidrec;
        FT_Bytes          p       = table;
        FT_UInt           table_size;
        FT_UShort         version;
        FT_UInt           ScriptList, FeatureList, LookupList;
    
        OTV_OPTIONAL_TABLE32( featureVariations );
    
    
        otvalid->root = ftvalid;
    
        FT_TRACE3(( "validating GSUB table\n" ));
        OTV_INIT;
    
        OTV_LIMIT_CHECK( 4 );
    
        if ( FT_NEXT_USHORT( p ) != 1 )  /* majorVersion */
          FT_INVALID_FORMAT;
    
        version = FT_NEXT_USHORT( p );   /* minorVersion */
    
        table_size = 10;
        switch ( version )
        {
        case 0:
          OTV_LIMIT_CHECK( 6 );
          break;
    
        case 1:
          OTV_LIMIT_CHECK( 10 );
          table_size += 4;
          break;
    
        default:
          FT_INVALID_FORMAT;
        }
    
        ScriptList  = FT_NEXT_USHORT( p );
        FeatureList = FT_NEXT_USHORT( p );
        LookupList  = FT_NEXT_USHORT( p );
    
        otvalid->type_count  = 8;
        otvalid->type_funcs  = (OTV_Validate_Func*)otv_gsub_validate_funcs;
        otvalid->glyph_count = glyph_count;
    
        otv_LookupList_validate( table + LookupList,
                                 otvalid );
        otv_FeatureList_validate( table + FeatureList, table + LookupList,
                                  otvalid );
        otv_ScriptList_validate( table + ScriptList, table + FeatureList,
                                 otvalid );
    
        if ( version > 0 )
        {
          OTV_OPTIONAL_OFFSET32( featureVariations );
          OTV_SIZE_CHECK32( featureVariations );
          if ( featureVariations )
            OTV_TRACE(( "  [omitting featureVariations validation]\n" )); /* XXX */
        }
    
        FT_TRACE4(( "\n" ));
      }
    
    
    /* END */