summaryrefslogtreecommitdiffstats
path: root/src/otvalid/otvgpos.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/otvalid/otvgpos.c')
-rw-r--r--src/otvalid/otvgpos.c1013
1 files changed, 1013 insertions, 0 deletions
diff --git a/src/otvalid/otvgpos.c b/src/otvalid/otvgpos.c
new file mode 100644
index 0000000..ed34705
--- /dev/null
+++ b/src/otvalid/otvgpos.c
@@ -0,0 +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 */