static void gxv_just_actSubrecord_type0_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_Fixed lowerLimit; FT_Fixed upperLimit; FT_UShort order; FT_UShort decomposedCount; FT_UInt i; GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); lowerLimit = FT_NEXT_ULONG( p ); upperLimit = FT_NEXT_ULONG( p ); order = FT_NEXT_USHORT( p ); decomposedCount = FT_NEXT_USHORT( p ); for ( i = 0; i < decomposedCount; i++ ) { FT_UShort glyphs; GXV_LIMIT_CHECK( 2 ); glyphs = FT_NEXT_USHORT( p ); } valid->subtable_length = p - table; }
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_just_actSubrecord_type4_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_ULong variantsAxis; FT_Fixed minimumLimit; FT_Fixed noStretchValue; FT_Fixed maximumLimit; GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); variantsAxis = FT_NEXT_ULONG( p ); minimumLimit = FT_NEXT_ULONG( p ); noStretchValue = FT_NEXT_ULONG( p ); maximumLimit = FT_NEXT_ULONG( p ); gxvalid->subtable_length = p - table; if ( variantsAxis != 0x64756374L ) /* 'duct' */ GXV_TRACE(( "variantsAxis 0x%08x is non default value", variantsAxis )); if ( minimumLimit > noStretchValue ) GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n", minimumLimit, noStretchValue )); else if ( noStretchValue > maximumLimit ) GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n", noStretchValue, maximumLimit )); else if ( !IS_PARANOID_VALIDATION ) return; FT_INVALID_DATA; }
static void gxv_just_wdp_entry_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong justClass; FT_Fixed beforeGrowLimit; FT_Fixed beforeShrinkGrowLimit; FT_Fixed afterGrowLimit; FT_Fixed afterShrinkGrowLimit; FT_UShort growFlags; FT_UShort shrinkFlags; GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); justClass = FT_NEXT_ULONG( p ); beforeGrowLimit = FT_NEXT_ULONG( p ); beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); afterGrowLimit = FT_NEXT_ULONG( p ); afterShrinkGrowLimit = FT_NEXT_ULONG( p ); growFlags = FT_NEXT_USHORT( p ); shrinkFlags = FT_NEXT_USHORT( p ); /* TODO: decode flags for human readability */ valid->subtable_length = p - table; }
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; }
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_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; }
/* * TODO: length should be limit? **/ static void gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_UShort i; GXV_morx_subtable_type1_StateOptRecData optdata = (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata; /* TODO: calculate offset/length for each lookupTables */ valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; valid->lookupval_func = gxv_morx_subtable_type1_LookupValue_validate; valid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit; for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ ) { FT_ULong offset; GXV_LIMIT_CHECK( 4 ); offset = FT_NEXT_ULONG( p ); gxv_LookupTable_validate( table + offset, limit, valid ); } /* TODO: overlapping of lookupTables in substitutionTable */ }
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; }
otv_MATH_validate( FT_Bytes table, FT_UInt glyph_count, FT_Validator ftvalid ) { OTV_ValidatorRec validrec; OTV_Validator valid = &validrec; FT_Bytes p = table; FT_UInt MathConstants, MathGlyphInfo, MathVariants; valid->root = ftvalid; FT_TRACE3(( "validating MATH table\n" )); OTV_INIT; OTV_LIMIT_CHECK( 10 ); if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ FT_INVALID_FORMAT; MathConstants = FT_NEXT_USHORT( p ); MathGlyphInfo = FT_NEXT_USHORT( p ); MathVariants = FT_NEXT_USHORT( p ); valid->glyph_count = glyph_count; otv_MathConstants_validate( table + MathConstants, valid ); otv_MathGlyphInfo_validate( table + MathGlyphInfo, valid ); otv_MathVariants_validate ( table + MathVariants, valid ); FT_TRACE4(( "\n" )); }
static void gxv_just_actSubrecord_type2_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; #ifdef GXV_LOAD_UNUSED_VARS FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ #endif FT_UShort addGlyph; FT_UShort substGlyph; GXV_LIMIT_CHECK( 4 + 2 + 2 ); #ifdef GXV_LOAD_UNUSED_VARS substThreshhold = FT_NEXT_ULONG( p ); #else p += 4; #endif addGlyph = FT_NEXT_USHORT( p ); substGlyph = FT_NEXT_USHORT( p ); if ( addGlyph != 0xFFFF ) gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid ); gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid ); gxvalid->subtable_length = p - table; }
/* convert a UCS-4 name entry to ASCII */ static FT_String* tt_name_entry_ascii_from_ucs4( TT_NameEntry entry, FT_Memory memory ) { FT_String* string; FT_UInt len, code, n; FT_Byte* read = (FT_Byte*)entry->string; len = (FT_UInt)entry->stringLength / 4; if ( FT_MEM_NEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) { code = (FT_UInt)FT_NEXT_ULONG( read ); if ( code < 32 || code > 127 ) code = '?'; string[n] = (char)code; } string[len] = 0; return string; }
static void gxv_just_actSubrecord_type0_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_Fixed lowerLimit; FT_Fixed upperLimit; #ifdef GXV_LOAD_UNUSED_VARS FT_UShort order; #endif FT_UShort decomposedCount; FT_UInt i; GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); lowerLimit = FT_NEXT_ULONG( p ); upperLimit = FT_NEXT_ULONG( p ); #ifdef GXV_LOAD_UNUSED_VARS order = FT_NEXT_USHORT( p ); #else p += 2; #endif decomposedCount = FT_NEXT_USHORT( p ); if ( lowerLimit >= upperLimit ) { GXV_TRACE(( "just table includes invalid range spec:" " lowerLimit(%d) > upperLimit(%d)\n" )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); } for ( i = 0; i < decomposedCount; i++ ) { FT_UShort glyphs; GXV_LIMIT_CHECK( 2 ); glyphs = FT_NEXT_USHORT( p ); gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid ); } gxvalid->subtable_length = p - table; }
gxv_bsln_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { GXV_ValidatorRec validrec; GXV_Validator valid = &validrec; GXV_bsln_DataRec bslnrec; GXV_bsln_Data bsln = &bslnrec; FT_Bytes p = table; FT_Bytes limit = 0; FT_ULong version; FT_UShort format; FT_UShort defaultBaseline; GXV_Validate_Func fmt_funcs_table [] = { gxv_bsln_parts_fmt0_validate, gxv_bsln_parts_fmt1_validate, gxv_bsln_parts_fmt2_validate, gxv_bsln_parts_fmt3_validate, }; valid->root = ftvalid; valid->table_data = bsln; valid->face = face; FT_TRACE3(( "validating `bsln' table\n" )); GXV_INIT; GXV_LIMIT_CHECK( 4 + 2 + 2 ); version = FT_NEXT_ULONG( p ); format = FT_NEXT_USHORT( p ); defaultBaseline = FT_NEXT_USHORT( p ); /* only version 1.0 is defined (1996) */ if ( version != 0x00010000UL ) FT_INVALID_FORMAT; /* only format 1, 2, 3 are defined (1996) */ GXV_TRACE(( " (format = %d)\n", format )); if ( format > 3 ) FT_INVALID_FORMAT; if ( defaultBaseline > 31 ) FT_INVALID_FORMAT; bsln->defaultBaseline = defaultBaseline; fmt_funcs_table[format]( p, limit, valid ); FT_TRACE4(( "\n" )); }
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_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_just_actSubrecord_type4_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong variantsAxis; FT_Fixed minimumLimit; FT_Fixed noStretchValue; FT_Fixed maximumLimit; GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); variantsAxis = FT_NEXT_ULONG( p ); minimumLimit = FT_NEXT_ULONG( p ); noStretchValue = FT_NEXT_ULONG( p ); maximumLimit = FT_NEXT_ULONG( p ); valid->subtable_length = p - table; }
gxv_opbd_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { GXV_ValidatorRec gxvalidrec; GXV_Validator gxvalid = &gxvalidrec; GXV_opbd_DataRec opbdrec; GXV_opbd_Data opbd = &opbdrec; FT_Bytes p = table; FT_Bytes limit = 0; FT_ULong version; gxvalid->root = ftvalid; gxvalid->table_data = opbd; gxvalid->face = face; FT_TRACE3(( "validating `opbd' table\n" )); GXV_INIT; GXV_OPBD_DATA( valueOffset_min ) = 0xFFFFU; GXV_LIMIT_CHECK( 4 + 2 ); version = FT_NEXT_ULONG( p ); GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p ); /* only 0x00010000 is defined (1996) */ GXV_TRACE(( "(version=0x%08x)\n", version )); if ( 0x00010000UL != version ) FT_INVALID_FORMAT; /* only values 0 and 1 are defined (1996) */ GXV_TRACE(( "(format=0x%04x)\n", GXV_OPBD_DATA( format ) )); if ( 0x0001 < GXV_OPBD_DATA( format ) ) FT_INVALID_FORMAT; gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; gxvalid->lookupval_func = gxv_opbd_LookupValue_validate; gxvalid->lookupfmt4_trans = gxv_opbd_LookupFmt4_transit; gxv_LookupTable_validate( p, limit, gxvalid ); p += gxvalid->subtable_length; if ( p > table + GXV_OPBD_DATA( valueOffset_min ) ) { GXV_TRACE(( "found overlap between LookupTable and opbd_value array\n" )); FT_INVALID_OFFSET; } FT_TRACE4(( "\n" )); }
static void gxv_just_wdp_entry_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_ULong justClass; #ifdef GXV_LOAD_UNUSED_VARS FT_Fixed beforeGrowLimit; FT_Fixed beforeShrinkGrowLimit; FT_Fixed afterGrowLimit; FT_Fixed afterShrinkGrowLimit; FT_UShort growFlags; FT_UShort shrinkFlags; #endif GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); justClass = FT_NEXT_ULONG( p ); #ifndef GXV_LOAD_UNUSED_VARS p += 4 + 4 + 4 + 4 + 2 + 2; #else beforeGrowLimit = FT_NEXT_ULONG( p ); beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); afterGrowLimit = FT_NEXT_ULONG( p ); afterShrinkGrowLimit = FT_NEXT_ULONG( p ); growFlags = FT_NEXT_USHORT( p ); shrinkFlags = FT_NEXT_USHORT( p ); #endif /* According to Apple spec, only 7bits in justClass is used */ if ( ( justClass & 0xFFFFFF80UL ) != 0 ) { GXV_TRACE(( "just table includes non-zero value" " in unused justClass higher bits" " of WidthDeltaPair" )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); } gxvalid->subtable_length = p - table; }
otv_JSTF_validate( FT_Bytes table, FT_Bytes gsub, FT_Bytes gpos, FT_UInt glyph_count, FT_Validator ftvalid ) { OTV_ValidatorRec otvalidrec; OTV_Validator otvalid = &otvalidrec; FT_Bytes p = table; FT_UInt JstfScriptCount; otvalid->root = ftvalid; FT_TRACE3(( "validating JSTF table\n" )); OTV_INIT; OTV_LIMIT_CHECK( 6 ); if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ FT_INVALID_FORMAT; JstfScriptCount = FT_NEXT_USHORT( p ); FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); OTV_LIMIT_CHECK( JstfScriptCount * 6 ); if ( gsub ) otvalid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); else otvalid->extra1 = 0; if ( gpos ) otvalid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); else otvalid->extra2 = 0; otvalid->glyph_count = glyph_count; /* JstfScriptRecord */ for ( ; JstfScriptCount > 0; JstfScriptCount-- ) { p += 4; /* skip JstfScriptTag */ /* JstfScript */ otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); } FT_TRACE4(( "\n" )); }
static void gxv_morx_subtable_type2_opttable_load( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; GXV_morx_subtable_type2_StateOptRecData optdata = (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; GXV_LIMIT_CHECK( 4 + 4 + 4 ); optdata->ligActionTable = FT_NEXT_ULONG( p ); optdata->componentTable = FT_NEXT_ULONG( p ); optdata->ligatureTable = FT_NEXT_ULONG( p ); GXV_TRACE(( "offset to ligActionTable=0x%08x\n", optdata->ligActionTable )); GXV_TRACE(( "offset to componentTable=0x%08x\n", optdata->componentTable )); GXV_TRACE(( "offset to ligatureTable=0x%08x\n", optdata->ligatureTable )); }
static void gxv_mort_subtable_type2_ligActionOffset_validate( FT_Bytes table, FT_UShort ligActionOffset, GXV_Validator valid ) { /* access ligActionTable */ GXV_mort_subtable_type2_StateOptRecData optdata = (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata; FT_Bytes lat_base = table + optdata->ligActionTable; FT_Bytes p = table + ligActionOffset; FT_Bytes lat_limit = lat_base + optdata->ligActionTable; GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset ); if ( p < lat_base ) { GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n", ligActionOffset, lat_base - p )); /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ if ( valid->root->level >= FT_VALIDATE_PARANOID ) FT_INVALID_OFFSET; } else if ( lat_limit < p ) { GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n", ligActionOffset, p - lat_limit )); /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ if ( valid->root->level >= FT_VALIDATE_PARANOID ) FT_INVALID_OFFSET; } else { /* validate entry in ligActionTable */ FT_ULong lig_action; FT_UShort last; FT_UShort store; FT_ULong offset; lig_action = FT_NEXT_ULONG( p ); last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); offset = lig_action & 0x3FFFFFFFUL; } }
gxv_mort_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { GXV_ValidatorRec validrec; GXV_Validator valid = &validrec; FT_Bytes p = table; FT_Bytes limit = 0; FT_ULong version; FT_ULong nChains; FT_ULong i; valid->root = ftvalid; valid->face = face; limit = valid->root->limit; FT_TRACE3(( "validating `mort' table\n" )); GXV_INIT; GXV_LIMIT_CHECK( 4 + 4 ); version = FT_NEXT_ULONG( p ); nChains = FT_NEXT_ULONG( p ); if (version != 0x00010000UL) FT_INVALID_FORMAT; for ( i = 0; i < nChains; i++ ) { GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains )); GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); gxv_mort_chain_validate( p, limit, valid ); p += valid->subtable_length; } FT_TRACE4(( "\n" )); }
FT_Stream_GetULong( FT_Stream stream ) { FT_Byte* p; FT_Long result; FT_ASSERT( stream && stream->cursor ); result = 0; p = stream->cursor; if ( p + 3 < stream->limit ) result = FT_NEXT_ULONG( p ); stream->cursor = p; return result; }
static void gxv_just_actSubrecord_type2_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ FT_UShort addGlyph; FT_UShort substGlyph; GXV_LIMIT_CHECK( 4 + 2 + 2 ); substThreshhold = FT_NEXT_ULONG( p ); addGlyph = FT_NEXT_USHORT( p ); substGlyph = FT_NEXT_USHORT( p ); valid->subtable_length = p - table; }
FT_Stream_ReadULong( FT_Stream stream, FT_Error* error ) { FT_Byte reads[4]; FT_Byte* p = 0; FT_Long result = 0; FT_ASSERT( stream ); *error = FT_Err_Ok; if ( stream->pos + 3 < stream->size ) { if ( stream->read ) { if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) goto Fail; p = reads; } else { p = stream->base + stream->pos; } if ( p ) result = FT_NEXT_ULONG( p ); } else goto Fail; stream->pos += 4; return result; Fail: *error = FT_Err_Invalid_Stream_Operation; FT_ERROR(( "FT_Stream_ReadULong:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); return 0; }
static void otv_ExtensionSubst_validate( FT_Bytes table, OTV_Validator otvalid ) { FT_Bytes p = table; FT_UInt SubstFormat; OTV_NAME_ENTER( "ExtensionSubst" ); OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); OTV_TRACE(( " (format %d)\n", SubstFormat )); switch ( SubstFormat ) { case 1: /* ExtensionSubstFormat1 */ { FT_UInt ExtensionLookupType; FT_ULong ExtensionOffset; OTV_Validate_Func validate; OTV_LIMIT_CHECK( 6 ); ExtensionLookupType = FT_NEXT_USHORT( p ); ExtensionOffset = FT_NEXT_ULONG( p ); if ( ExtensionLookupType == 0 || ExtensionLookupType == 7 || ExtensionLookupType > 8 ) FT_INVALID_DATA; validate = otvalid->type_funcs[ExtensionLookupType - 1]; validate( table + ExtensionOffset, otvalid ); } break; default: FT_INVALID_FORMAT; } OTV_EXIT; }
static void gxv_just_wdc_entry_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_ULong count, i; GXV_LIMIT_CHECK( 4 ); count = FT_NEXT_ULONG( p ); for ( i = 0; i < count; i++ ) { GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count )); gxv_just_wdp_entry_validate( p, limit, valid ); p += valid->subtable_length; } valid->subtable_length = p - table; }
/* parse single actSubrecord */ static void gxv_just_actSubrecord_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator gxvalid ) { FT_Bytes p = table; FT_UShort actionClass; FT_UShort actionType; FT_ULong actionLength; GXV_NAME_ENTER( "just actSubrecord" ); GXV_LIMIT_CHECK( 2 + 2 + 4 ); actionClass = FT_NEXT_USHORT( p ); actionType = FT_NEXT_USHORT( p ); actionLength = FT_NEXT_ULONG( p ); /* actionClass is related with justClass using 7bit only */ if ( ( actionClass & 0xFF80 ) != 0 ) GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); if ( actionType == 0 ) gxv_just_actSubrecord_type0_validate( p, limit, gxvalid ); else if ( actionType == 1 ) gxv_just_actSubrecord_type1_validate( p, limit, gxvalid ); else if ( actionType == 2 ) gxv_just_actSubrecord_type2_validate( p, limit, gxvalid ); else if ( actionType == 3 ) ; /* Stretch glyph action: no actionData */ else if ( actionType == 4 ) gxv_just_actSubrecord_type4_validate( p, limit, gxvalid ); else if ( actionType == 5 ) gxv_just_actSubrecord_type5_validate( p, limit, gxvalid ); else FT_INVALID_DATA; gxvalid->subtable_length = actionLength; 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; }