static void gxv_lcar_LookupValue_validate( FT_UShort glyph, GXV_LookupValueDesc value, GXV_Validator valid ) { FT_Bytes p = valid->root->base + value.u; FT_Bytes limit = valid->root->limit; FT_UShort count; FT_Short partial; FT_UShort i; GXV_NAME_ENTER( "element in lookupTable" ); GXV_LIMIT_CHECK( 2 ); count = FT_NEXT_USHORT( p ); GXV_LIMIT_CHECK( 2 * count ); for ( i = 0; i < count; i++ ) { partial = FT_NEXT_SHORT( p ); gxv_lcar_partial_validate( partial, glyph, valid ); } GXV_EXIT; }
static void gxv_mort_subtable_type1_substTable_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_UShort num_gids = (FT_UShort)( ((GXV_mort_subtable_type1_StateOptRec *) (valid->statetable.optdata))->substitutionTable_length / 2 ); FT_UShort i; GXV_NAME_ENTER( "validating contents of substitutionTable" ); for ( i = 0; i < num_gids ; i ++ ) { FT_UShort dst_gid; GXV_LIMIT_CHECK( 2 ); dst_gid = FT_NEXT_USHORT( p ); if ( dst_gid >= 0xFFFFU ) continue; if ( dst_gid < valid->min_gid || valid->max_gid < dst_gid ) { GXV_TRACE(( "substTable include a strange gid[%d]=%d >" " out of define range (%d..%d)\n", i, dst_gid, valid->min_gid, valid->max_gid )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); } } GXV_EXIT; }
gxv_mort_featurearray_validate( FT_Bytes table, FT_Bytes limit, FT_ULong nFeatureFlags, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong i; GXV_mort_featureRec f = GXV_MORT_FEATURE_OFF; GXV_NAME_ENTER( "mort feature list" ); for ( i = 0; i < nFeatureFlags; i++ ) { GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 ); f.featureType = FT_NEXT_USHORT( p ); f.featureSetting = FT_NEXT_USHORT( p ); f.enableFlags = FT_NEXT_ULONG( p ); f.disableFlags = FT_NEXT_ULONG( p ); gxv_mort_feature_validate( &f, valid ); } if ( !IS_GXV_MORT_FEATURE_OFF( f ) ) FT_INVALID_DATA; valid->subtable_length = p - table; GXV_EXIT; }
static void gxv_just_justClassTable_validate ( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_UShort length; FT_UShort coverage; FT_ULong subFeatureFlags; GXV_NAME_ENTER( "just justClassTable" ); GXV_LIMIT_CHECK( 2 + 2 + 4 ); length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); subFeatureFlags = FT_NEXT_ULONG( p ); GXV_TRACE(( " justClassTable: coverage = 0x%04x (%s)", coverage, ( 0x4000 & coverage ) == 0 ? "ascending" : "descending" )); valid->statetable.optdata = NULL; valid->statetable.optdata_load_func = NULL; valid->statetable.subtable_setup_func = NULL; valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; valid->statetable.entry_validate_func = gxv_just_classTable_entry_validate; gxv_StateTable_validate( p, table + length, valid ); /* subtable_length is set by gxv_LookupTable_validate() */ GXV_EXIT; }
static void gxv_kern_subtable_fmt0_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; FT_UShort nPairs; FT_UShort unitSize; GXV_NAME_ENTER( "kern subtable format 0" ); unitSize = 2 + 2 + 2; nPairs = 0; /* nPairs, searchRange, entrySelector, rangeShift */ GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, gxvalid ); p += 2 + 2 + 2 + 2; gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, gxvalid ); GXV_EXIT; }
static void gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, FT_Bytes limit, GXV_kern_ClassSpec spec, GXV_Validator gxvalid ) { const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); FT_Bytes p = table; FT_UShort firstGlyph; FT_UShort nGlyphs; GXV_NAME_ENTER( "kern format 2 classTable" ); GXV_LIMIT_CHECK( 2 + 2 ); firstGlyph = FT_NEXT_USHORT( p ); nGlyphs = FT_NEXT_USHORT( p ); GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", tag, firstGlyph, nGlyphs )); gxv_glyphid_validate( firstGlyph, gxvalid ); gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), gxvalid ); gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), gxvalid ); gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); GXV_EXIT; }
gxv_mort_subtable_type2_validate(FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid) { FT_Bytes p = table; GXV_mort_subtable_type2_StateOptRec lig_rec; GXV_NAME_ENTER("mort chain subtable type2 (Ligature Substitution)"); GXV_LIMIT_CHECK(GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE); gxvalid->statetable.optdata = &lig_rec; gxvalid->statetable.optdata_load_func = gxv_mort_subtable_type2_opttable_load; gxvalid->statetable.subtable_setup_func = gxv_mort_subtable_type2_subtable_setup; gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; gxvalid->statetable.entry_validate_func = gxv_mort_subtable_type2_entry_validate; gxv_StateTable_validate(p, limit, gxvalid); p += gxvalid->subtable_length; gxv_mort_subtable_type2_ligatureTable_validate(table, gxvalid); gxvalid->subtable_length = (FT_ULong)(p - table); GXV_EXIT; }
static void gxv_kern_subtable_fmt1_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; GXV_kern_fmt1_StateOptRec vt_rec; GXV_NAME_ENTER( "kern subtable format 1" ); gxvalid->statetable.optdata = &vt_rec; gxvalid->statetable.optdata_load_func = gxv_kern_subtable_fmt1_valueTable_load; gxvalid->statetable.subtable_setup_func = gxv_kern_subtable_fmt1_subtable_setup; gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; gxvalid->statetable.entry_validate_func = gxv_kern_subtable_fmt1_entry_validate; gxv_StateTable_validate( p, limit, gxvalid ); GXV_EXIT; }
static void gxv_feat_setting_validate( FT_Bytes table, FT_Bytes limit, FT_Bool exclusive, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_UShort setting; GXV_NAME_ENTER( "setting" ); GXV_LIMIT_CHECK( 2 ); setting = FT_NEXT_USHORT( p ); /* If we have exclusive setting, the setting should be odd. */ if ( exclusive && ( setting & 1 ) == 0 ) FT_INVALID_DATA; gxv_feat_name_index_validate( p, limit, gxvalid ); GXV_FEAT_DATA( setting ) = setting; GXV_EXIT; }
static void gxv_mort_chain_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong defaultFlags; FT_ULong chainLength; FT_UShort nFeatureFlags; FT_UShort nSubtables; GXV_NAME_ENTER( "mort chain header" ); GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); defaultFlags = FT_NEXT_ULONG( p ); chainLength = FT_NEXT_ULONG( p ); nFeatureFlags = FT_NEXT_USHORT( p ); nSubtables = FT_NEXT_USHORT( p ); gxv_mort_featurearray_validate( p, table + chainLength, nFeatureFlags, valid ); p += valid->subtable_length; gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid ); valid->subtable_length = chainLength; GXV_EXIT; }
static void gxv_mort_subtable_type2_ligatureTable_validate(FT_Bytes table, GXV_Validator gxvalid) { GXV_mort_subtable_type2_StateOptRecData optdata = (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; FT_Bytes p = table + optdata->ligatureTable; FT_Bytes limit = table + optdata->ligatureTable + optdata->ligatureTable_length; GXV_NAME_ENTER("mort chain subtable type2 - substitutionTable"); if (0 != optdata->ligatureTable) { /* Apple does not give specification of ligatureTable format */ while (p < limit) { FT_UShort lig_gid; GXV_LIMIT_CHECK(2); lig_gid = FT_NEXT_USHORT(p); if (gxvalid->face->num_glyphs < lig_gid) GXV_SET_ERR_IF_PARANOID(FT_INVALID_GLYPH_ID); } } GXV_EXIT; }
gxv_morx_subtable_type1_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; GXV_morx_subtable_type1_StateOptRec st_rec; GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" ); GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE ); st_rec.substitutionTable_num_lookupTables = 0; valid->xstatetable.optdata = &st_rec; valid->xstatetable.optdata_load_func = gxv_morx_subtable_type1_substitutionTable_load; valid->xstatetable.subtable_setup_func = gxv_morx_subtable_type1_subtable_setup; valid->xstatetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_ULONG; valid->xstatetable.entry_validate_func = gxv_morx_subtable_type1_entry_validate; gxv_XStateTable_validate( p, limit, valid ); gxv_morx_subtable_type1_substitutionTable_validate( table + st_rec.substitutionTable, table + st_rec.substitutionTable + st_rec.substitutionTable_length, valid ); GXV_EXIT; }
static void gxv_just_widthDeltaClusters_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table ; FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); FT_UInt i; GXV_NAME_ENTER( "just justDeltaClusters" ); if ( limit <= wdc_end ) FT_INVALID_OFFSET; for ( i = 0; p <= wdc_end; i++ ) { gxv_just_wdc_entry_validate( p, limit, valid ); p += valid->subtable_length; } valid->subtable_length = p - table; GXV_EXIT; }
gxv_mort_subtable_type5_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; GXV_mort_subtable_type5_StateOptRec et_rec; GXV_mort_subtable_type5_StateOptRecData et = &et_rec; GXV_NAME_ENTER( "mort chain subtable type5 (Glyph Insertion)" ); GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE ); gxvalid->statetable.optdata = et; gxvalid->statetable.optdata_load_func = NULL; gxvalid->statetable.subtable_setup_func = gxv_mort_subtable_type5_subtable_setup; gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_ULONG; gxvalid->statetable.entry_validate_func = gxv_mort_subtable_type5_entry_validate; gxv_StateTable_validate( p, limit, gxvalid ); GXV_EXIT; }
static void gxv_morx_chain_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong defaultFlags; FT_ULong chainLength; FT_ULong nFeatureFlags; FT_ULong nSubtables; GXV_NAME_ENTER( "morx chain header" ); GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); defaultFlags = FT_NEXT_ULONG( p ); chainLength = FT_NEXT_ULONG( p ); nFeatureFlags = FT_NEXT_ULONG( p ); nSubtables = FT_NEXT_ULONG( p ); /* feature-array of morx is same with that of mort */ gxv_mort_featurearray_validate( p, limit, nFeatureFlags, valid ); p += valid->subtable_length; if ( nSubtables >= 0x10000L ) FT_INVALID_DATA; gxv_morx_subtables_validate( p, table + chainLength, (FT_UShort)nSubtables, valid ); valid->subtable_length = chainLength; GXV_EXIT; }
static void gxv_mort_chain_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; #ifdef GXV_LOAD_UNUSED_VARS FT_ULong defaultFlags; #endif FT_ULong chainLength; FT_UShort nFeatureFlags; FT_UShort nSubtables; GXV_NAME_ENTER( "mort chain header" ); GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); #ifdef GXV_LOAD_UNUSED_VARS defaultFlags = FT_NEXT_ULONG( p ); #else p += 4; #endif chainLength = FT_NEXT_ULONG( p ); nFeatureFlags = FT_NEXT_USHORT( p ); nSubtables = FT_NEXT_USHORT( p ); gxv_mort_featurearray_validate( p, table + chainLength, nFeatureFlags, valid ); p += valid->subtable_length; gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid ); valid->subtable_length = chainLength; /* TODO: validate defaultFlags */ GXV_EXIT; }
static void gxv_feat_registry_validate( FT_UShort feature, FT_UShort nSettings, FT_Bool exclusive, GXV_Validator valid ) { GXV_NAME_ENTER( "feature in registry" ); GXV_TRACE(( " (feature = %u)\n", feature )); if ( feature >= gxv_feat_registry_length ) { GXV_TRACE(( "feature number %d is out of range %d\n", feature, gxv_feat_registry_length )); if ( valid->root->level == FT_VALIDATE_PARANOID ) FT_INVALID_DATA; goto Exit; } if ( gxv_feat_registry[feature].existence == 0 ) { GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n", feature )); if ( valid->root->level == FT_VALIDATE_PARANOID ) FT_INVALID_DATA; goto Exit; } if ( gxv_feat_registry[feature].apple_reserved ) { /* Don't use here. Apple is reserved. */ GXV_TRACE(( "feature number %d is reserved by Apple\n", feature )); if ( valid->root->level >= FT_VALIDATE_TIGHT ) FT_INVALID_DATA; } if ( nSettings != gxv_feat_registry[feature].nSettings ) { GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n", feature, nSettings, gxv_feat_registry[feature].nSettings )); if ( valid->root->level >= FT_VALIDATE_TIGHT ) FT_INVALID_DATA; } if ( exclusive != gxv_feat_registry[feature].exclusive ) { GXV_TRACE(( "exclusive flag %d differs from predefined value\n", exclusive )); if ( valid->root->level >= FT_VALIDATE_TIGHT ) FT_INVALID_DATA; } Exit: GXV_EXIT; }
static void gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, FT_Bytes limit, FT_UShort nPairs, GXV_Validator valid ) { FT_Bytes p = table; FT_UShort i; FT_UShort last_gid_left = 0; FT_UShort last_gid_right = 0; FT_UNUSED( limit ); GXV_NAME_ENTER( "kern format 0 pairs" ); for ( i = 0; i < nPairs; i++ ) { FT_UShort gid_left; FT_UShort gid_right; FT_Short kernValue; /* left */ gid_left = FT_NEXT_USHORT( p ); gxv_glyphid_validate( gid_left, valid ); /* right */ gid_right = FT_NEXT_USHORT( p ); gxv_glyphid_validate( gid_right, valid ); /* Pairs of left and right GIDs must be unique and sorted. */ GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right )); if ( gid_left == last_gid_left ) { if ( last_gid_right < gid_right ) last_gid_right = gid_right; else FT_INVALID_DATA; } else if ( last_gid_left < gid_left ) { last_gid_left = gid_left; last_gid_right = gid_right; } else FT_INVALID_DATA; /* skip the kern value */ kernValue = FT_NEXT_SHORT( p ); } GXV_EXIT; }
static void gxv_trak_trackData_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_UShort nTracks; FT_UShort nSizes; FT_ULong sizeTableOffset; GXV_ODTECT( 4, odtect ); GXV_ODTECT_INIT( odtect ); GXV_NAME_ENTER( "trackData" ); /* read the header of trackData */ GXV_LIMIT_CHECK( 2 + 2 + 4 ); nTracks = FT_NEXT_USHORT( p ); nSizes = FT_NEXT_USHORT( p ); sizeTableOffset = FT_NEXT_ULONG( p ); gxv_odtect_add_range( table, (FT_ULong)( p - table ), "trackData header", odtect ); /* validate trackTable */ gxv_trak_trackTable_validate( p, limit, nTracks, gxvalid ); gxv_odtect_add_range( p, gxvalid->subtable_length, "trackTable", odtect ); /* sizeTable is array of FT_Fixed, don't check contents */ p = gxvalid->root->base + sizeTableOffset; GXV_LIMIT_CHECK( nSizes * 4 ); gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect ); /* validate trackValueOffet */ p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_min ); if ( limit - p < nTracks * nSizes * 2 ) GXV_TRACE(( "too short trackValue array\n" )); p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_max ); GXV_LIMIT_CHECK( nSizes * 2 ); gxv_odtect_add_range( gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_min ), GXV_TRAK_DATA( trackValueOffset_max ) - GXV_TRAK_DATA( trackValueOffset_min ) + nSizes * 2, "trackValue array", odtect ); gxv_odtect_validate( odtect, gxvalid ); GXV_EXIT; }
static void gxv_kern_subtable_fmt2_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { GXV_ODTECT( 3, odtect ); GXV_kern_subtable_fmt2_DataRec fmt2_rec = { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; FT_UShort leftOffsetTable; FT_UShort rightOffsetTable; GXV_NAME_ENTER( "kern subtable format 2" ); GXV_ODTECT_INIT( odtect ); fmt2_rec.odtect = odtect; GXV_KERN_DATA( subtable_data ) = &fmt2_rec; GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); leftOffsetTable = FT_NEXT_USHORT( p ); rightOffsetTable = FT_NEXT_USHORT( p ); GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); GXV_LIMIT_CHECK( leftOffsetTable ); GXV_LIMIT_CHECK( rightOffsetTable ); GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, GXV_KERN_CLS_L, gxvalid ); gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, GXV_KERN_CLS_R, gxvalid ); if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) < GXV_KERN_FMT2_DATA( array ) ) FT_INVALID_OFFSET; gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) - GXV_KERN_FMT2_DATA( array ), "array", odtect ); gxv_odtect_validate( odtect, gxvalid ); GXV_EXIT; }
gxv_morx_subtable_type4_validate(FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid) { GXV_NAME_ENTER("morx chain subtable type4 " "(Non-Contextual Glyph Substitution)"); gxv_mort_subtable_type4_validate(table, limit, gxvalid); GXV_EXIT; }
static void gxv_mort_subtable_type2_subtable_setup(FT_UShort table_size, FT_UShort classTable, FT_UShort stateArray, FT_UShort entryTable, FT_UShort *classTable_length_p, FT_UShort *stateArray_length_p, FT_UShort *entryTable_length_p, GXV_Validator gxvalid) { FT_UShort o[6]; FT_UShort *l[6]; FT_UShort buff[7]; GXV_mort_subtable_type2_StateOptRecData optdata = (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; GXV_NAME_ENTER("subtable boundaries setup"); o[0] = classTable; o[1] = stateArray; o[2] = entryTable; o[3] = optdata->ligActionTable; o[4] = optdata->componentTable; o[5] = optdata->ligatureTable; l[0] = classTable_length_p; l[1] = stateArray_length_p; l[2] = entryTable_length_p; l[3] = &(optdata->ligActionTable_length); l[4] = &(optdata->componentTable_length); l[5] = &(optdata->ligatureTable_length); gxv_set_length_by_ushort_offset(o, l, buff, 6, table_size, gxvalid); GXV_TRACE(("classTable: offset=0x%04x length=0x%04x\n", classTable, *classTable_length_p)); GXV_TRACE(("stateArray: offset=0x%04x length=0x%04x\n", stateArray, *stateArray_length_p)); GXV_TRACE(("entryTable: offset=0x%04x length=0x%04x\n", entryTable, *entryTable_length_p)); GXV_TRACE(("ligActionTable: offset=0x%04x length=0x%04x\n", optdata->ligActionTable, optdata->ligActionTable_length)); GXV_TRACE(("componentTable: offset=0x%04x length=0x%04x\n", optdata->componentTable, optdata->componentTable_length)); GXV_TRACE(("ligatureTable: offset=0x%04x length=0x%04x\n", optdata->ligatureTable, optdata->ligatureTable_length)); GXV_EXIT; }
static void gxv_lcar_partial_validate( FT_UShort partial, FT_UShort glyph, GXV_Validator valid ) { GXV_NAME_ENTER( "partial" ); if ( GXV_LCAR_DATA( format ) != 1 ) goto Exit; gxv_ctlPoint_validate( glyph, partial, valid ); Exit: GXV_EXIT; }
static void gxv_trak_trackTable_validate( FT_Bytes table, FT_Bytes limit, FT_UShort nTracks, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_Fixed track, t; FT_UShort nameIndex; FT_UShort offset; FT_UShort i, j; GXV_NAME_ENTER( "trackTable" ); GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU; GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000; GXV_LIMIT_CHECK( nTracks * ( 4 + 2 + 2 ) ); for ( i = 0; i < nTracks; i ++ ) { p = table + i * ( 4 + 2 + 2 ); track = FT_NEXT_LONG( p ); nameIndex = FT_NEXT_USHORT( p ); offset = FT_NEXT_USHORT( p ); if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) ) GXV_TRAK_DATA( trackValueOffset_min ) = offset; if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) ) GXV_TRAK_DATA( trackValueOffset_max ) = offset; gxv_sfntName_validate( nameIndex, 256, 32767, gxvalid ); for ( j = i; j < nTracks; j ++ ) { p = table + j * ( 4 + 2 + 2 ); t = FT_NEXT_LONG( p ); if ( t == track ) GXV_TRACE(( "duplicated entries found for track value 0x%x\n", track )); } } gxvalid->subtable_length = p - table; GXV_EXIT; }
static void gxv_bsln_parts_fmt0_validate( FT_Bytes tables, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = tables; GXV_NAME_ENTER( "parts format 0" ); /* deltas */ GXV_LIMIT_CHECK( 2 * GXV_BSLN_VALUE_COUNT ); valid->table_data = NULL; /* No ctlPoints here. */ GXV_EXIT; }
gxv_mort_subtable_type4_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; GXV_NAME_ENTER( "mort chain subtable type4 " "(Non-Contextual Glyph Substitution)" ); gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; gxvalid->lookupval_func = gxv_mort_subtable_type4_lookupval_validate; gxvalid->lookupfmt4_trans = gxv_mort_subtable_type4_lookupfmt4_transit; gxv_LookupTable_validate( p, limit, gxvalid ); GXV_EXIT; }
static void gxv_morx_chain_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; #ifdef GXV_LOAD_UNUSED_VARS FT_ULong defaultFlags; #endif FT_ULong chainLength; FT_ULong nFeatureFlags; FT_ULong nSubtables; GXV_NAME_ENTER( "morx chain header" ); GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); #ifdef GXV_LOAD_UNUSED_VARS defaultFlags = FT_NEXT_ULONG( p ); #else p += 4; #endif chainLength = FT_NEXT_ULONG( p ); nFeatureFlags = FT_NEXT_ULONG( p ); nSubtables = FT_NEXT_ULONG( p ); /* feature-array of morx is same with that of mort */ gxv_mort_featurearray_validate( p, limit, nFeatureFlags, valid ); p += valid->subtable_length; if ( nSubtables >= 0x10000L ) FT_INVALID_DATA; gxv_morx_subtables_validate( p, table + chainLength, (FT_UShort)nSubtables, valid ); valid->subtable_length = chainLength; /* TODO: defaultFlags should be compared with the flags in tables */ GXV_EXIT; }
static void gxv_bsln_parts_fmt2_validate( FT_Bytes tables, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = tables; FT_UShort stdGlyph; FT_UShort ctlPoint; FT_Int i; FT_UShort defaultBaseline = GXV_BSLN_DATA( defaultBaseline ); GXV_NAME_ENTER( "parts format 2" ); GXV_LIMIT_CHECK( 2 + ( 2 * GXV_BSLN_VALUE_COUNT ) ); /* stdGlyph */ stdGlyph = FT_NEXT_USHORT( p ); GXV_TRACE(( " (stdGlyph = %u)\n", stdGlyph )); gxv_glyphid_validate( stdGlyph, valid ); /* Record the position of ctlPoints */ GXV_BSLN_DATA( ctlPoints_p ) = p; /* ctlPoints */ for ( i = 0; i < GXV_BSLN_VALUE_COUNT; i++ ) { ctlPoint = FT_NEXT_USHORT( p ); if ( ctlPoint == GXV_BSLN_VALUE_EMPTY ) { if ( i == defaultBaseline ) FT_INVALID_DATA; } else gxv_ctlPoint_validate( stdGlyph, (FT_Short)ctlPoint, valid ); } GXV_EXIT; }
static void gxv_just_postcompTable_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; GXV_NAME_ENTER( "just postcompTable" ); gxv_just_pcLookupTable_validate( p, limit, valid ); p += valid->subtable_length; gxv_just_pcActionRecord_validate( p, limit, valid ); p += valid->subtable_length; valid->subtable_length = p - table; GXV_EXIT; }
static void gxv_just_justClassTable_validate ( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_UShort length; FT_UShort coverage; FT_ULong subFeatureFlags; GXV_NAME_ENTER( "just justClassTable" ); GXV_LIMIT_CHECK( 2 + 2 + 4 ); length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); subFeatureFlags = FT_NEXT_ULONG( p ); GXV_TRACE(( " justClassTable: coverage = 0x%04x (%s) ", coverage )); if ( ( coverage & 0x4000 ) == 0 ) GXV_TRACE(( "ascending\n" )); else GXV_TRACE(( "descending\n" )); if ( subFeatureFlags ) GXV_TRACE(( " justClassTable: nonzero value (0x%08x)" " in unused subFeatureFlags\n", subFeatureFlags )); gxvalid->statetable.optdata = NULL; gxvalid->statetable.optdata_load_func = NULL; gxvalid->statetable.subtable_setup_func = NULL; gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; gxvalid->statetable.entry_validate_func = gxv_just_classTable_entry_validate; gxv_StateTable_validate( p, table + length, gxvalid ); /* subtable_length is set by gxv_LookupTable_validate() */ GXV_EXIT; }