585 lines
18 KiB
C
585 lines
18 KiB
C
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* otvgsub.c */
|
||
|
/* */
|
||
|
/* OpenType GSUB table validation (body). */
|
||
|
/* */
|
||
|
/* Copyright 2004 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 trace_otvgsub
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 1 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* uses valid->glyph_count */
|
||
|
|
||
|
static void
|
||
|
otv_SingleSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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, valid );
|
||
|
|
||
|
idx = otv_Coverage_get_first( Coverage ) + DeltaGlyphID;
|
||
|
if ( idx < 0 )
|
||
|
FT_INVALID_DATA;
|
||
|
|
||
|
idx = otv_Coverage_get_last( Coverage ) + DeltaGlyphID;
|
||
|
if ( (FT_UInt)idx >= valid->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, valid );
|
||
|
|
||
|
OTV_LIMIT_CHECK( GlyphCount * 2 );
|
||
|
|
||
|
/* Substitute */
|
||
|
for ( ; GlyphCount > 0; GlyphCount-- )
|
||
|
if ( FT_NEXT_USHORT( p ) >= valid->glyph_count )
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 2 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* sets valid->extra1 (glyph count) */
|
||
|
|
||
|
static void
|
||
|
otv_MultipleSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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:
|
||
|
valid->extra1 = valid->glyph_count;
|
||
|
OTV_NEST2( MultipleSubstFormat1, Sequence );
|
||
|
OTV_RUN( table, valid );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 3 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* sets valid->extra1 (glyph count) */
|
||
|
|
||
|
static void
|
||
|
otv_AlternateSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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:
|
||
|
valid->extra1 = valid->glyph_count;
|
||
|
OTV_NEST2( AlternateSubstFormat1, AlternateSet );
|
||
|
OTV_RUN( table, valid );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 4 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
#define Ligature otv_Ligature_validate, "Ligature"
|
||
|
|
||
|
/* uses valid->glyph_count */
|
||
|
|
||
|
static void
|
||
|
otv_Ligature_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
FT_Bytes p = table;
|
||
|
FT_UInt LigatureGlyph, CompCount;
|
||
|
|
||
|
|
||
|
OTV_ENTER;
|
||
|
|
||
|
OTV_LIMIT_CHECK( 4 );
|
||
|
LigatureGlyph = FT_NEXT_USHORT( p );
|
||
|
if ( LigatureGlyph >= valid->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 valid )
|
||
|
{
|
||
|
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, valid );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 5 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* sets valid->extra1 (lookup count) */
|
||
|
|
||
|
static void
|
||
|
otv_ContextSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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 */
|
||
|
|
||
|
valid->extra1 = valid->lookup_count;
|
||
|
OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
|
||
|
OTV_RUN( table, valid );
|
||
|
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, valid );
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
OTV_NEST1( ContextSubstFormat3 );
|
||
|
OTV_RUN( table, valid );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 6 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* sets valid->extra1 (lookup count) */
|
||
|
|
||
|
static void
|
||
|
otv_ChainContextSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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 */
|
||
|
|
||
|
valid->extra1 = valid->lookup_count;
|
||
|
OTV_NEST3( ChainContextSubstFormat1,
|
||
|
ChainSubRuleSet, ChainSubRule );
|
||
|
OTV_RUN( table, valid );
|
||
|
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, valid );
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
OTV_NEST1( ChainContextSubstFormat3 );
|
||
|
OTV_RUN( table, valid );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 7 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* uses valid->type_funcs */
|
||
|
|
||
|
static void
|
||
|
otv_ExtensionSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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, 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 = valid->type_funcs[ExtensionLookupType - 1];
|
||
|
validate( table + ExtensionOffset, valid );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
/***** *****/
|
||
|
/***** GSUB LOOKUP TYPE 8 *****/
|
||
|
/***** *****/
|
||
|
/*************************************************************************/
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* uses valid->glyph_count */
|
||
|
|
||
|
static void
|
||
|
otv_ReverseChainSingleSubst_validate( FT_Bytes table,
|
||
|
OTV_Validator valid )
|
||
|
{
|
||
|
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, valid );
|
||
|
|
||
|
OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
|
||
|
|
||
|
for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
|
||
|
otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
|
||
|
|
||
|
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 ), valid );
|
||
|
|
||
|
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 ) >= valid->glyph_count )
|
||
|
FT_INVALID_DATA;
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
FT_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
OTV_EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
static 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 valid->type_count */
|
||
|
/* sets valid->type_funcs */
|
||
|
/* sets valid->glyph_count */
|
||
|
|
||
|
FT_LOCAL_DEF( void )
|
||
|
otv_GSUB_validate( FT_Bytes table,
|
||
|
FT_UInt glyph_count,
|
||
|
FT_Validator ftvalid )
|
||
|
{
|
||
|
OTV_ValidatorRec validrec;
|
||
|
OTV_Validator valid = &validrec;
|
||
|
FT_Bytes p = table;
|
||
|
FT_UInt ScriptList, FeatureList, LookupList;
|
||
|
|
||
|
|
||
|
valid->root = ftvalid;
|
||
|
|
||
|
FT_TRACE3(( "validating GSUB table\n" ));
|
||
|
OTV_INIT;
|
||
|
|
||
|
OTV_LIMIT_CHECK( 10 );
|
||
|
|
||
|
if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */
|
||
|
FT_INVALID_DATA;
|
||
|
|
||
|
ScriptList = FT_NEXT_USHORT( p );
|
||
|
FeatureList = FT_NEXT_USHORT( p );
|
||
|
LookupList = FT_NEXT_USHORT( p );
|
||
|
|
||
|
valid->type_count = 8;
|
||
|
valid->type_funcs = otv_gsub_validate_funcs;
|
||
|
valid->glyph_count = glyph_count;
|
||
|
|
||
|
otv_LookupList_validate( table + LookupList,
|
||
|
valid );
|
||
|
otv_FeatureList_validate( table + FeatureList, table + LookupList,
|
||
|
valid );
|
||
|
otv_ScriptList_validate( table + ScriptList, table + FeatureList,
|
||
|
valid );
|
||
|
|
||
|
FT_TRACE4(( "\n" ));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* END */
|