X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Flib%2F3rdparty%2Ffreetype%2Fsrc%2Fotvalid%2Fotvgpos.c;h=ed347053d65e275b1805e0e82d3cb511480e122b;hp=16b63bbb4bafc1d9cbc10f2b46d51e19a971fd0a;hb=ab802377c7d0abc04aeb1dc7cb250bacd22e6902;hpb=854ec39df334eb0f53b326841c8377cc06c5ca89 diff --git a/reactos/lib/3rdparty/freetype/src/otvalid/otvgpos.c b/reactos/lib/3rdparty/freetype/src/otvalid/otvgpos.c index 16b63bbb4ba..ed347053d65 100644 --- a/reactos/lib/3rdparty/freetype/src/otvalid/otvgpos.c +++ b/reactos/lib/3rdparty/freetype/src/otvalid/otvgpos.c @@ -1,1013 +1,1013 @@ -/***************************************************************************/ -/* */ -/* otvgpos.c */ -/* */ -/* OpenType GPOS table validation (body). */ -/* */ -/* Copyright 2002, 2004, 2005, 2006 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" -#include "otvgpos.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_otvgpos - - - static void - otv_Anchor_validate( FT_Bytes table, - OTV_Validator valid ); - - static void - otv_MarkArray_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** UTILITY FUNCTIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define BaseArrayFunc otv_x_sxy -#define LigatureAttachFunc otv_x_sxy -#define Mark2ArrayFunc otv_x_sxy - - /* uses valid->extra1 (counter) */ - /* uses valid->extra2 (boolean to handle NULL anchor field) */ - - static void - otv_x_sxy( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count, count1, table_size; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 2 ); - - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); - - table_size = Count * valid->extra1 * 2 + 2; - - for ( ; Count > 0; Count-- ) - for ( count1 = valid->extra1; count1 > 0; count1-- ) - { - OTV_OPTIONAL_TABLE( anchor_offset ); - - - OTV_OPTIONAL_OFFSET( anchor_offset ); - - if ( valid->extra2 ) - { - OTV_SIZE_CHECK( anchor_offset ); - if ( anchor_offset ) - otv_Anchor_validate( table + anchor_offset, valid ); - } - else - otv_Anchor_validate( table + anchor_offset, valid ); - } - - OTV_EXIT; - } - - -#define MarkBasePosFormat1Func otv_u_O_O_u_O_O -#define MarkLigPosFormat1Func otv_u_O_O_u_O_O -#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O - - /* sets valid->extra1 (class count) */ - - static void - otv_u_O_O_u_O_O( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Coverage1, Coverage2, ClassCount; - FT_UInt Array1, Array2; - OTV_Validate_Func func; - - - OTV_ENTER; - - p += 2; /* skip PosFormat */ - - OTV_LIMIT_CHECK( 10 ); - Coverage1 = FT_NEXT_USHORT( p ); - Coverage2 = FT_NEXT_USHORT( p ); - ClassCount = FT_NEXT_USHORT( p ); - Array1 = FT_NEXT_USHORT( p ); - Array2 = FT_NEXT_USHORT( p ); - - otv_Coverage_validate( table + Coverage1, valid ); - otv_Coverage_validate( table + Coverage2, valid ); - - otv_MarkArray_validate( table + Array1, valid ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - valid->extra1 = ClassCount; - - func( table + Array2, valid ); - - valid->nesting_level--; - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** VALUE RECORDS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static FT_UInt - otv_value_length( FT_UInt format ) - { - FT_UInt count; - - - count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); - count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); - count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); - - return count * 2; - } - - - /* uses valid->extra3 (pointer to base table) */ - - static void - otv_ValueRecord_validate( FT_Bytes table, - FT_UInt format, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt count; - -#ifdef FT_DEBUG_LEVEL_TRACE - FT_Int loop; - FT_ULong res = 0; - - - OTV_NAME_ENTER( "ValueRecord" ); - - /* display `format' in dual representation */ - for ( loop = 7; loop >= 0; loop-- ) - { - res <<= 4; - res += ( format >> loop ) & 1; - } - - OTV_TRACE(( " (format 0b%08lx)\n", res )); -#endif - - if ( format >= 0x100 ) - FT_INVALID_DATA; - - for ( count = 4; count > 0; count-- ) - { - if ( format & 1 ) - { - /* XPlacement, YPlacement, XAdvance, YAdvance */ - OTV_LIMIT_CHECK( 2 ); - p += 2; - } - - format >>= 1; - } - - for ( count = 4; count > 0; count-- ) - { - if ( format & 1 ) - { - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( device ); - - - /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ - OTV_LIMIT_CHECK( 2 ); - OTV_OPTIONAL_OFFSET( device ); - - /* XXX: this value is usually too small, especially if the current */ - /* ValueRecord is part of an array -- getting the correct table */ - /* size is probably not worth the trouble */ - - table_size = p - valid->extra3; - - OTV_SIZE_CHECK( device ); - if ( device ) - otv_Device_validate( valid->extra3 + device, valid ); - } - format >>= 1; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** ANCHORS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_Anchor_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt AnchorFormat; - - - OTV_NAME_ENTER( "Anchor"); - - OTV_LIMIT_CHECK( 6 ); - AnchorFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", AnchorFormat )); - - p += 4; /* skip XCoordinate and YCoordinate */ - - switch ( AnchorFormat ) - { - case 1: - break; - - case 2: - OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ - break; - - case 3: - { - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( XDeviceTable ); - OTV_OPTIONAL_TABLE( YDeviceTable ); - - - OTV_LIMIT_CHECK( 4 ); - OTV_OPTIONAL_OFFSET( XDeviceTable ); - OTV_OPTIONAL_OFFSET( YDeviceTable ); - - table_size = 6 + 4; - - OTV_SIZE_CHECK( XDeviceTable ); - if ( XDeviceTable ) - otv_Device_validate( table + XDeviceTable, valid ); - - OTV_SIZE_CHECK( YDeviceTable ); - if ( YDeviceTable ) - otv_Device_validate( table + YDeviceTable, valid ); - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** MARK ARRAYS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_MarkArray_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt MarkCount; - - - OTV_NAME_ENTER( "MarkArray" ); - - OTV_LIMIT_CHECK( 2 ); - MarkCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); - - OTV_LIMIT_CHECK( MarkCount * 4 ); - - /* MarkRecord */ - for ( ; MarkCount > 0; MarkCount-- ) - { - p += 2; /* skip Class */ - /* MarkAnchor */ - otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 1 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra3 (pointer to base table) */ - - static void - otv_SinglePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "SinglePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - valid->extra3 = table; - - switch ( PosFormat ) - { - case 1: /* SinglePosFormat1 */ - { - FT_UInt Coverage, ValueFormat; - - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat = FT_NEXT_USHORT( p ); - - otv_Coverage_validate( table + Coverage, valid ); - otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ - } - break; - - case 2: /* SinglePosFormat2 */ - { - FT_UInt Coverage, ValueFormat, ValueCount, len_value; - - - OTV_LIMIT_CHECK( 6 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat = FT_NEXT_USHORT( p ); - ValueCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); - - len_value = otv_value_length( ValueFormat ); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( ValueCount * len_value ); - - /* Value */ - for ( ; ValueCount > 0; ValueCount-- ) - { - otv_ValueRecord_validate( p, ValueFormat, valid ); - p += len_value; - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 2 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_PairSet_validate( FT_Bytes table, - FT_UInt format1, - FT_UInt format2, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt value_len1, value_len2, PairValueCount; - - - OTV_NAME_ENTER( "PairSet" ); - - OTV_LIMIT_CHECK( 2 ); - PairValueCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); - - value_len1 = otv_value_length( format1 ); - value_len2 = otv_value_length( format2 ); - - OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); - - /* PairValueRecord */ - for ( ; PairValueCount > 0; PairValueCount-- ) - { - p += 2; /* skip SecondGlyph */ - - if ( format1 ) - otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ - p += value_len1; - - if ( format2 ) - otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ - p += value_len2; - } - - OTV_EXIT; - } - - - /* sets valid->extra3 (pointer to base table) */ - - static void - otv_PairPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "PairPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - valid->extra3 = table; - - switch ( PosFormat ) - { - case 1: /* PairPosFormat1 */ - { - FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; - - - OTV_LIMIT_CHECK( 8 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat1 = FT_NEXT_USHORT( p ); - ValueFormat2 = FT_NEXT_USHORT( p ); - PairSetCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( PairSetCount * 2 ); - - /* PairSetOffset */ - for ( ; PairSetCount > 0; PairSetCount-- ) - otv_PairSet_validate( table + FT_NEXT_USHORT( p ), - ValueFormat1, ValueFormat2, valid ); - } - break; - - case 2: /* PairPosFormat2 */ - { - FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; - FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; - - - OTV_LIMIT_CHECK( 14 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat1 = FT_NEXT_USHORT( p ); - ValueFormat2 = FT_NEXT_USHORT( p ); - ClassDef1 = FT_NEXT_USHORT( p ); - ClassDef2 = FT_NEXT_USHORT( p ); - ClassCount1 = FT_NEXT_USHORT( p ); - ClassCount2 = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); - OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); - - len_value1 = otv_value_length( ValueFormat1 ); - len_value2 = otv_value_length( ValueFormat2 ); - - otv_Coverage_validate( table + Coverage, valid ); - otv_ClassDef_validate( table + ClassDef1, valid ); - otv_ClassDef_validate( table + ClassDef2, valid ); - - OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * - ( len_value1 + len_value2 ) ); - - /* Class1Record */ - for ( ; ClassCount1 > 0; ClassCount1-- ) - { - /* Class2Record */ - for ( count = ClassCount2; count > 0; count-- ) - { - if ( ValueFormat1 ) - /* Value1 */ - otv_ValueRecord_validate( p, ValueFormat1, valid ); - p += len_value1; - - if ( ValueFormat2 ) - /* Value2 */ - otv_ValueRecord_validate( p, ValueFormat2, valid ); - p += len_value2; - } - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 3 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_CursivePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "CursivePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: /* CursivePosFormat1 */ - { - FT_UInt table_size; - FT_UInt Coverage, EntryExitCount; - - OTV_OPTIONAL_TABLE( EntryAnchor ); - OTV_OPTIONAL_TABLE( ExitAnchor ); - - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - EntryExitCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( EntryExitCount * 4 ); - - table_size = EntryExitCount * 4 + 4; - - /* EntryExitRecord */ - for ( ; EntryExitCount > 0; EntryExitCount-- ) - { - OTV_OPTIONAL_OFFSET( EntryAnchor ); - OTV_OPTIONAL_OFFSET( ExitAnchor ); - - OTV_SIZE_CHECK( EntryAnchor ); - if ( EntryAnchor ) - otv_Anchor_validate( table + EntryAnchor, valid ); - - OTV_SIZE_CHECK( ExitAnchor ); - if ( ExitAnchor ) - otv_Anchor_validate( table + ExitAnchor, valid ); - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 4 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (0) */ - - static void - otv_MarkBasePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkBasePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 0; - OTV_NEST2( MarkBasePosFormat1, BaseArray ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 5 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (1) */ - - static void - otv_MarkLigPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkLigPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 1; - OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 6 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (0) */ - - static void - otv_MarkMarkPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkMarkPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 0; - OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 7 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ContextPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ContextPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - 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( ContextPosFormat1, PosRuleSet, PosRule ); - 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( ContextPosFormat2, PosClassSet, PosClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ContextPosFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 8 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ChainContextPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ChainContextPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - 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( ChainContextPosFormat1, - ChainPosRuleSet, ChainPosRule ); - 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( ChainContextPosFormat2, - ChainPosClassSet, ChainPosClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ChainContextPosFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 9 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->type_funcs */ - - static void - otv_ExtensionPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ExtensionPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: /* ExtensionPosFormat1 */ - { - 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 >= 9 ) - FT_INVALID_DATA; - - validate = valid->type_funcs[ExtensionLookupType - 1]; - validate( table + ExtensionOffset, valid ); - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - static const OTV_Validate_Func otv_gpos_validate_funcs[9] = - { - otv_SinglePos_validate, - otv_PairPos_validate, - otv_CursivePos_validate, - otv_MarkBasePos_validate, - otv_MarkLigPos_validate, - otv_MarkMarkPos_validate, - otv_ContextPos_validate, - otv_ChainContextPos_validate, - otv_ExtensionPos_validate - }; - - - /* sets valid->type_count */ - /* sets valid->type_funcs */ - - FT_LOCAL_DEF( void ) - otv_GPOS_subtable_validate( FT_Bytes table, - OTV_Validator valid ) - { - valid->type_count = 9; - valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; - - otv_Lookup_validate( table, valid ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->glyph_count */ - - FT_LOCAL_DEF( void ) - otv_GPOS_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 GPOS 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 = 9; - valid->type_funcs = (OTV_Validate_Func*)otv_gpos_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 */ +/***************************************************************************/ +/* */ +/* otvgpos.c */ +/* */ +/* OpenType GPOS table validation (body). */ +/* */ +/* Copyright 2002, 2004, 2005, 2006 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" +#include "otvgpos.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_otvgpos + + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ); + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define BaseArrayFunc otv_x_sxy +#define LigatureAttachFunc otv_x_sxy +#define Mark2ArrayFunc otv_x_sxy + + /* uses valid->extra1 (counter) */ + /* uses valid->extra2 (boolean to handle NULL anchor field) */ + + static void + otv_x_sxy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count, count1, table_size; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); + + table_size = Count * valid->extra1 * 2 + 2; + + for ( ; Count > 0; Count-- ) + for ( count1 = valid->extra1; count1 > 0; count1-- ) + { + OTV_OPTIONAL_TABLE( anchor_offset ); + + + OTV_OPTIONAL_OFFSET( anchor_offset ); + + if ( valid->extra2 ) + { + OTV_SIZE_CHECK( anchor_offset ); + if ( anchor_offset ) + otv_Anchor_validate( table + anchor_offset, valid ); + } + else + otv_Anchor_validate( table + anchor_offset, valid ); + } + + OTV_EXIT; + } + + +#define MarkBasePosFormat1Func otv_u_O_O_u_O_O +#define MarkLigPosFormat1Func otv_u_O_O_u_O_O +#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O + + /* sets valid->extra1 (class count) */ + + static void + otv_u_O_O_u_O_O( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage1, Coverage2, ClassCount; + FT_UInt Array1, Array2; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip PosFormat */ + + OTV_LIMIT_CHECK( 10 ); + Coverage1 = FT_NEXT_USHORT( p ); + Coverage2 = FT_NEXT_USHORT( p ); + ClassCount = FT_NEXT_USHORT( p ); + Array1 = FT_NEXT_USHORT( p ); + Array2 = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage1, valid ); + otv_Coverage_validate( table + Coverage2, valid ); + + otv_MarkArray_validate( table + Array1, valid ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = ClassCount; + + func( table + Array2, valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALUE RECORDS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_UInt + otv_value_length( FT_UInt format ) + { + FT_UInt count; + + + count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); + count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); + count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); + + return count * 2; + } + + + /* uses valid->extra3 (pointer to base table) */ + + static void + otv_ValueRecord_validate( FT_Bytes table, + FT_UInt format, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt count; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Int loop; + FT_ULong res = 0; + + + OTV_NAME_ENTER( "ValueRecord" ); + + /* display `format' in dual representation */ + for ( loop = 7; loop >= 0; loop-- ) + { + res <<= 4; + res += ( format >> loop ) & 1; + } + + OTV_TRACE(( " (format 0b%08lx)\n", res )); +#endif + + if ( format >= 0x100 ) + FT_INVALID_DATA; + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + /* XPlacement, YPlacement, XAdvance, YAdvance */ + OTV_LIMIT_CHECK( 2 ); + p += 2; + } + + format >>= 1; + } + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( device ); + + + /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ + OTV_LIMIT_CHECK( 2 ); + OTV_OPTIONAL_OFFSET( device ); + + /* XXX: this value is usually too small, especially if the current */ + /* ValueRecord is part of an array -- getting the correct table */ + /* size is probably not worth the trouble */ + + table_size = p - valid->extra3; + + OTV_SIZE_CHECK( device ); + if ( device ) + otv_Device_validate( valid->extra3 + device, valid ); + } + format >>= 1; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ANCHORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt AnchorFormat; + + + OTV_NAME_ENTER( "Anchor"); + + OTV_LIMIT_CHECK( 6 ); + AnchorFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", AnchorFormat )); + + p += 4; /* skip XCoordinate and YCoordinate */ + + switch ( AnchorFormat ) + { + case 1: + break; + + case 2: + OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ + break; + + case 3: + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( XDeviceTable ); + OTV_OPTIONAL_TABLE( YDeviceTable ); + + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( XDeviceTable ); + OTV_OPTIONAL_OFFSET( YDeviceTable ); + + table_size = 6 + 4; + + OTV_SIZE_CHECK( XDeviceTable ); + if ( XDeviceTable ) + otv_Device_validate( table + XDeviceTable, valid ); + + OTV_SIZE_CHECK( YDeviceTable ); + if ( YDeviceTable ) + otv_Device_validate( table + YDeviceTable, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK ARRAYS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt MarkCount; + + + OTV_NAME_ENTER( "MarkArray" ); + + OTV_LIMIT_CHECK( 2 ); + MarkCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + + OTV_LIMIT_CHECK( MarkCount * 4 ); + + /* MarkRecord */ + for ( ; MarkCount > 0; MarkCount-- ) + { + p += 2; /* skip Class */ + /* MarkAnchor */ + otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_SinglePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "SinglePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* SinglePosFormat1 */ + { + FT_UInt Coverage, ValueFormat; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ + } + break; + + case 2: /* SinglePosFormat2 */ + { + FT_UInt Coverage, ValueFormat, ValueCount, len_value; + + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + ValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + + len_value = otv_value_length( ValueFormat ); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( ValueCount * len_value ); + + /* Value */ + for ( ; ValueCount > 0; ValueCount-- ) + { + otv_ValueRecord_validate( p, ValueFormat, valid ); + p += len_value; + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_PairSet_validate( FT_Bytes table, + FT_UInt format1, + FT_UInt format2, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt value_len1, value_len2, PairValueCount; + + + OTV_NAME_ENTER( "PairSet" ); + + OTV_LIMIT_CHECK( 2 ); + PairValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + + value_len1 = otv_value_length( format1 ); + value_len2 = otv_value_length( format2 ); + + OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); + + /* PairValueRecord */ + for ( ; PairValueCount > 0; PairValueCount-- ) + { + p += 2; /* skip SecondGlyph */ + + if ( format1 ) + otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ + p += value_len1; + + if ( format2 ) + otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ + p += value_len2; + } + + OTV_EXIT; + } + + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_PairPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "PairPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* PairPosFormat1 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; + + + OTV_LIMIT_CHECK( 8 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + PairSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( PairSetCount * 2 ); + + /* PairSetOffset */ + for ( ; PairSetCount > 0; PairSetCount-- ) + otv_PairSet_validate( table + FT_NEXT_USHORT( p ), + ValueFormat1, ValueFormat2, valid ); + } + break; + + case 2: /* PairPosFormat2 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; + FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; + + + OTV_LIMIT_CHECK( 14 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + ClassDef1 = FT_NEXT_USHORT( p ); + ClassDef2 = FT_NEXT_USHORT( p ); + ClassCount1 = FT_NEXT_USHORT( p ); + ClassCount2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + + len_value1 = otv_value_length( ValueFormat1 ); + len_value2 = otv_value_length( ValueFormat2 ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ClassDef_validate( table + ClassDef1, valid ); + otv_ClassDef_validate( table + ClassDef2, valid ); + + OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * + ( len_value1 + len_value2 ) ); + + /* Class1Record */ + for ( ; ClassCount1 > 0; ClassCount1-- ) + { + /* Class2Record */ + for ( count = ClassCount2; count > 0; count-- ) + { + if ( ValueFormat1 ) + /* Value1 */ + otv_ValueRecord_validate( p, ValueFormat1, valid ); + p += len_value1; + + if ( ValueFormat2 ) + /* Value2 */ + otv_ValueRecord_validate( p, ValueFormat2, valid ); + p += len_value2; + } + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_CursivePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "CursivePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* CursivePosFormat1 */ + { + FT_UInt table_size; + FT_UInt Coverage, EntryExitCount; + + OTV_OPTIONAL_TABLE( EntryAnchor ); + OTV_OPTIONAL_TABLE( ExitAnchor ); + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + EntryExitCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( EntryExitCount * 4 ); + + table_size = EntryExitCount * 4 + 4; + + /* EntryExitRecord */ + for ( ; EntryExitCount > 0; EntryExitCount-- ) + { + OTV_OPTIONAL_OFFSET( EntryAnchor ); + OTV_OPTIONAL_OFFSET( ExitAnchor ); + + OTV_SIZE_CHECK( EntryAnchor ); + if ( EntryAnchor ) + otv_Anchor_validate( table + EntryAnchor, valid ); + + OTV_SIZE_CHECK( ExitAnchor ); + if ( ExitAnchor ) + otv_Anchor_validate( table + ExitAnchor, valid ); + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkBasePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkBasePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkBasePosFormat1, BaseArray ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (1) */ + + static void + otv_MarkLigPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkLigPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 1; + OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkMarkPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkMarkPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + 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( ContextPosFormat1, PosRuleSet, PosRule ); + 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( ContextPosFormat2, PosClassSet, PosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ChainContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ChainContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + 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( ChainContextPosFormat1, + ChainPosRuleSet, ChainPosRule ); + 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( ChainContextPosFormat2, + ChainPosClassSet, ChainPosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ChainContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 9 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_funcs */ + + static void + otv_ExtensionPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ExtensionPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* ExtensionPosFormat1 */ + { + 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 >= 9 ) + FT_INVALID_DATA; + + validate = valid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gpos_validate_funcs[9] = + { + otv_SinglePos_validate, + otv_PairPos_validate, + otv_CursivePos_validate, + otv_MarkBasePos_validate, + otv_MarkLigPos_validate, + otv_MarkMarkPos_validate, + otv_ContextPos_validate, + otv_ChainContextPos_validate, + otv_ExtensionPos_validate + }; + + + /* sets valid->type_count */ + /* sets valid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ) + { + valid->type_count = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + + otv_Lookup_validate( table, valid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GPOS_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 GPOS 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 = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_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 */