gxv_trak_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { FT_Bytes p = table; FT_Bytes limit = 0; GXV_ValidatorRec validrec; GXV_Validator valid = &validrec; GXV_trak_DataRec trakrec; GXV_trak_Data trak = &trakrec; FT_ULong version; FT_UShort format; FT_UShort horizOffset; FT_UShort vertOffset; FT_UShort reserved; GXV_ODTECT( 3, odtect ); GXV_ODTECT_INIT( odtect ); valid->root = ftvalid; valid->table_data = trak; valid->face = face; limit = valid->root->limit; FT_TRACE3(( "validating `trak' table\n" )); GXV_INIT; GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 ); version = FT_NEXT_ULONG( p ); format = FT_NEXT_USHORT( p ); horizOffset = FT_NEXT_USHORT( p ); vertOffset = FT_NEXT_USHORT( p ); reserved = FT_NEXT_USHORT( p ); GXV_TRACE(( " (version = 0x%08x)\n", version )); GXV_TRACE(( " (format = 0x%04x)\n", format )); GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset )); GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset )); GXV_TRACE(( " (reserved = 0x%04x)\n", reserved )); /* Version 1.0 (always:1996) */ if ( version != 0x00010000UL ) FT_INVALID_FORMAT; /* format 0 (always:1996) */ if ( format != 0x0000 ) FT_INVALID_FORMAT; GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset ); GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset ); /* Reserved Fixed Value (always) */ if ( reserved != 0x0000 ) FT_INVALID_DATA; /* validate trackData */ if ( 0 < horizOffset ) { gxv_trak_trackData_validate( table + horizOffset, limit, valid ); gxv_odtect_add_range( table + horizOffset, valid->subtable_length, "horizJustData", odtect ); } if ( 0 < vertOffset ) { gxv_trak_trackData_validate( table + vertOffset, limit, valid ); gxv_odtect_add_range( table + vertOffset, valid->subtable_length, "vertJustData", odtect ); } gxv_odtect_validate( odtect, valid ); FT_TRACE4(( "\n" )); }
static void gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, FT_Bytes limit, FT_UShort nPairs, GXV_Validator gxvalid ) { 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; #ifdef GXV_LOAD_UNUSED_VARS FT_Short kernValue; #endif /* left */ gid_left = FT_NEXT_USHORT( p ); gxv_glyphid_validate( gid_left, gxvalid ); /* right */ gid_right = FT_NEXT_USHORT( p ); gxv_glyphid_validate( gid_right, gxvalid ); /* 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 */ #ifdef GXV_LOAD_UNUSED_VARS kernValue = FT_NEXT_SHORT( p ); #else p += 2; #endif } GXV_EXIT; }
tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_len; FT_Long num_shorts, num_longs, num_shorts_checked; TT_LongMetrics* longs; TT_ShortMetrics** shorts; FT_Byte* p; if ( vertical ) { void* lm = &face->vertical.long_metrics; void** sm = &face->vertical.short_metrics; error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->vertical.number_Of_VMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->vertical.number_Of_VMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } else { void* lm = &face->horizontal.long_metrics; void** sm = &face->horizontal.short_metrics; error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->horizontal.number_Of_HMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->horizontal.number_Of_HMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } /* never trust derived values */ num_shorts = face->max_profile.numGlyphs - num_longs; num_shorts_checked = ( table_len - num_longs * 4L ) / 2; if ( num_shorts < 0 ) { FT_ERROR(( "%cmtx has more metrics than glyphs.\n" )); /* Adobe simply ignores this problem. So we shall do the same. */ #if 0 error = vertical ? SFNT_Err_Invalid_Vert_Metrics : SFNT_Err_Invalid_Horiz_Metrics; goto Exit; #else num_shorts = 0; #endif } if ( FT_QNEW_ARRAY( *longs, num_longs ) || FT_QNEW_ARRAY( *shorts, num_shorts ) ) goto Fail; if ( FT_FRAME_ENTER( table_len ) ) goto Fail; p = stream->cursor; { TT_LongMetrics cur = *longs; TT_LongMetrics limit = cur + num_longs; for ( ; cur < limit; cur++ ) { cur->advance = FT_NEXT_USHORT( p ); cur->bearing = FT_NEXT_SHORT( p ); } } /* do we have an inconsistent number of metric values? */ { TT_ShortMetrics* cur = *shorts; TT_ShortMetrics* limit = cur + FT_MIN( num_shorts, num_shorts_checked ); for ( ; cur < limit; cur++ ) *cur = FT_NEXT_SHORT( p ); /* We fill up the missing left side bearings with the */ /* last valid value. Since this will occur for buggy CJK */ /* fonts usually only, nothing serious will happen. */ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) { FT_Short val = (*shorts)[num_shorts_checked - 1]; limit = *shorts + num_shorts; for ( ; cur < limit; cur++ ) *cur = val; } } FT_FRAME_EXIT(); if ( vertical ) face->vertical.number_Of_VMetrics = (FT_UShort)num_longs; else face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs; Fail: return error; }
tt_face_find_bdf_prop( TT_Face face, const char* property_name, BDF_PropertyRec *aprop ) { TT_BDF bdf = &face->bdf; FT_Size size = FT_FACE(face)->size; FT_Error error = FT_Err_Ok; FT_Byte* p; FT_UInt count; FT_Byte* strike; FT_Offset property_len; aprop->type = BDF_PROPERTY_TYPE_NONE; if ( bdf->loaded == 0 ) { error = tt_face_load_bdf_props( face, FT_FACE( face )->stream ); if ( error ) goto Exit; } count = bdf->num_strikes; p = bdf->table + 8; strike = p + 4 * count; error = FT_ERR( Invalid_Argument ); if ( size == NULL || property_name == NULL ) goto Exit; property_len = ft_strlen( property_name ); if ( property_len == 0 ) goto Exit; for ( ; count > 0; count-- ) { FT_UInt _ppem = FT_NEXT_USHORT( p ); FT_UInt _count = FT_NEXT_USHORT( p ); if ( _ppem == size->metrics.y_ppem ) { count = _count; goto FoundStrike; } strike += 10 * _count; } goto Exit; FoundStrike: p = strike; for ( ; count > 0; count-- ) { FT_UInt type = FT_PEEK_USHORT( p + 4 ); if ( ( type & 0x10 ) != 0 ) { FT_UInt32 name_offset = FT_PEEK_ULONG( p ); FT_UInt32 value = FT_PEEK_ULONG( p + 6 ); /* be a bit paranoid for invalid entries here */ if ( name_offset < bdf->strings_size && property_len < bdf->strings_size - name_offset && ft_strncmp( property_name, (const char*)bdf->strings + name_offset, bdf->strings_size - name_offset ) == 0 ) { switch ( type & 0x0F ) { case 0x00: /* string */ case 0x01: /* atoms */ /* check that the content is really 0-terminated */ if ( value < bdf->strings_size && ft_memchr( bdf->strings + value, 0, bdf->strings_size ) ) { aprop->type = BDF_PROPERTY_TYPE_ATOM; aprop->u.atom = (const char*)bdf->strings + value; error = FT_Err_Ok; goto Exit; } break; case 0x02: aprop->type = BDF_PROPERTY_TYPE_INTEGER; aprop->u.integer = (FT_Int32)value; error = FT_Err_Ok; goto Exit; case 0x03: aprop->type = BDF_PROPERTY_TYPE_CARDINAL; aprop->u.cardinal = value; error = FT_Err_Ok; goto Exit; default: ; } } } p += 10; } Exit: return error; }
otv_Coverage_validate( FT_Bytes table, OTV_Validator otvalid, FT_Int expected_count ) { FT_Bytes p = table; FT_UInt CoverageFormat; FT_UInt total = 0; OTV_NAME_ENTER( "Coverage" ); OTV_LIMIT_CHECK( 4 ); CoverageFormat = FT_NEXT_USHORT( p ); OTV_TRACE(( " (format %d)\n", CoverageFormat )); switch ( CoverageFormat ) { case 1: /* CoverageFormat1 */ { FT_UInt GlyphCount; FT_UInt i; GlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ for ( i = 0; i < GlyphCount; ++i ) { FT_UInt gid; gid = FT_NEXT_USHORT( p ); if ( gid >= otvalid->glyph_count ) FT_INVALID_GLYPH_ID; } total = GlyphCount; } break; case 2: /* CoverageFormat2 */ { FT_UInt n, RangeCount; FT_UInt Start, End, StartCoverageIndex, last = 0; RangeCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); OTV_LIMIT_CHECK( RangeCount * 6 ); /* RangeRecord */ for ( n = 0; n < RangeCount; n++ ) { Start = FT_NEXT_USHORT( p ); End = FT_NEXT_USHORT( p ); StartCoverageIndex = FT_NEXT_USHORT( p ); if ( Start > End || StartCoverageIndex != total ) FT_INVALID_DATA; if ( End >= otvalid->glyph_count ) FT_INVALID_GLYPH_ID; if ( n > 0 && Start <= last ) FT_INVALID_DATA; total += End - Start + 1; last = End; } } break; default: FT_INVALID_FORMAT; } /* Generally, a coverage table offset has an associated count field. */ /* The number of glyphs in the table should match this field. If */ /* there is no associated count, a value of -1 tells us not to check. */ if ( expected_count != -1 && (FT_UInt)expected_count != total ) FT_INVALID_DATA; OTV_EXIT; }
gxv_feat_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { GXV_ValidatorRec validrec; GXV_Validator valid = &validrec; GXV_feat_DataRec featrec; GXV_feat_Data feat = &featrec; FT_Bytes p = table; FT_Bytes limit = 0; FT_UInt featureNameCount; FT_UInt i; FT_Int last_feature; valid->root = ftvalid; valid->table_data = feat; valid->face = face; FT_TRACE3(( "validating `feat' table\n" )); GXV_INIT; feat->reserved_size = 0; /* version + featureNameCount + none_0 + none_1 */ GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); feat->reserved_size += 4 + 2 + 2 + 4; if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ FT_INVALID_FORMAT; featureNameCount = FT_NEXT_USHORT( p ); GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); if ( !( IS_PARANOID_VALIDATION ) ) p += 6; /* skip (none) and (none) */ else { if ( FT_NEXT_USHORT( p ) != 0 ) FT_INVALID_DATA; if ( FT_NEXT_ULONG( p ) != 0 ) FT_INVALID_DATA; } feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) { gxv_feat_name_validate( p, limit, valid ); if ( (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); last_feature = GXV_FEAT_DATA( feature ); p += 2 + 2 + 4 + 2 + 2; } FT_TRACE4(( "\n" )); }
tt_face_get_kerning( TT_Face face, FT_UInt left_glyph, FT_UInt right_glyph ) { FT_Int result = 0; FT_UInt count, mask; FT_Byte* p = face->kern_table; FT_Byte* p_limit = p + face->kern_table_size; p += 4; mask = 0x0001; for ( count = face->num_kern_tables; count > 0 && p + 6 <= p_limit; count--, mask <<= 1 ) { FT_Byte* base = p; FT_Byte* next; FT_UInt version = FT_NEXT_USHORT( p ); FT_UInt length = FT_NEXT_USHORT( p ); FT_UInt coverage = FT_NEXT_USHORT( p ); FT_UInt num_pairs; FT_Int value = 0; FT_UNUSED( version ); next = base + length; if ( next > p_limit ) /* handle broken table */ next = p_limit; if ( ( face->kern_avail_bits & mask ) == 0 ) goto NextTable; if ( p + 8 > next ) goto NextTable; num_pairs = FT_NEXT_USHORT( p ); p += 6; if ( ( next - p ) < 6 * (int)num_pairs ) /* handle broken count */ num_pairs = (FT_UInt)( ( next - p ) / 6 ); switch ( coverage >> 8 ) { case 0: { FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); if ( face->kern_order_bits & mask ) /* binary search */ { FT_UInt min = 0; FT_UInt max = num_pairs; while ( min < max ) { FT_UInt mid = ( min + max ) >> 1; FT_Byte* q = p + 6 * mid; FT_ULong key; key = FT_NEXT_ULONG( q ); if ( key == key0 ) { value = FT_PEEK_SHORT( q ); goto Found; } if ( key < key0 ) min = mid + 1; else max = mid; } } else /* linear search */ { FT_UInt count2; for ( count2 = num_pairs; count2 > 0; count2-- ) { FT_ULong key = FT_NEXT_ULONG( p ); if ( key == key0 ) { value = FT_PEEK_SHORT( p ); goto Found; } p += 2; } } } break; /* * We don't support format 2 because we haven't seen a single font * using it in real life... */ default: ; }
/* * gxv_just_justData_validate() parses and validates horizData, vertData. */ static void gxv_just_justData_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { /* * following 3 offsets are measured from the start of `just' * (which table points to), not justData */ FT_UShort justClassTableOffset; FT_UShort wdcTableOffset; FT_UShort pcTableOffset; FT_Bytes p = table; GXV_ODTECT( 4, odtect ); GXV_NAME_ENTER( "just justData" ); GXV_ODTECT_INIT( odtect ); GXV_LIMIT_CHECK( 2 + 2 + 2 ); justClassTableOffset = FT_NEXT_USHORT( p ); wdcTableOffset = FT_NEXT_USHORT( p ); pcTableOffset = FT_NEXT_USHORT( p ); GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset )); GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset )); GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset )); gxv_just_justData_lookuptable_validate( p, limit, valid ); gxv_odtect_add_range( p, valid->subtable_length, "just_LookupTable", odtect ); if ( wdcTableOffset ) { gxv_just_widthDeltaClusters_validate( valid->root->base + wdcTableOffset, limit, valid ); gxv_odtect_add_range( valid->root->base + wdcTableOffset, valid->subtable_length, "just_wdcTable", odtect ); } if ( pcTableOffset ) { gxv_just_postcompTable_validate( valid->root->base + pcTableOffset, limit, valid ); gxv_odtect_add_range( valid->root->base + pcTableOffset, valid->subtable_length, "just_pcTable", odtect ); } if ( justClassTableOffset ) { gxv_just_justClassTable_validate( valid->root->base + justClassTableOffset, limit, valid ); gxv_odtect_add_range( valid->root->base + justClassTableOffset, valid->subtable_length, "just_justClassTable", odtect ); } gxv_odtect_validate( odtect, valid ); GXV_EXIT; }
gxv_just_validate( FT_Bytes table, FT_Face face, FT_Validator ftvalid ) { FT_Bytes p = table; FT_Bytes limit = 0; FT_Offset table_size; GXV_ValidatorRec validrec; GXV_Validator valid = &validrec; GXV_just_DataRec justrec; GXV_just_Data just = &justrec; FT_ULong version; FT_UShort format; FT_UShort horizOffset; FT_UShort vertOffset; GXV_ODTECT( 3, odtect ); GXV_ODTECT_INIT( odtect ); valid->root = ftvalid; valid->table_data = just; valid->face = face; FT_TRACE3(( "validating `just' table\n" )); GXV_INIT; limit = valid->root->limit; table_size = limit - table; GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); version = FT_NEXT_ULONG( p ); format = FT_NEXT_USHORT( p ); horizOffset = FT_NEXT_USHORT( p ); vertOffset = FT_NEXT_USHORT( p ); gxv_odtect_add_range( table, p - table, "just header", odtect ); /* Version 1.0 (always:2000) */ GXV_TRACE(( " (version = 0x%08x)\n", version )); if ( version != 0x00010000UL ) FT_INVALID_FORMAT; /* format 0 (always:2000) */ GXV_TRACE(( " (format = 0x%04x)\n", format )); if ( format != 0x0000 ) FT_INVALID_FORMAT; GXV_TRACE(( " (horizOffset = %d)\n", horizOffset )); GXV_TRACE(( " (vertOffset = %d)\n", vertOffset )); /* validate justData */ if ( 0 < horizOffset ) { gxv_just_justData_validate( table + horizOffset, limit, valid ); gxv_odtect_add_range( table + horizOffset, valid->subtable_length, "horizJustData", odtect ); } if ( 0 < vertOffset ) { gxv_just_justData_validate( table + vertOffset, limit, valid ); gxv_odtect_add_range( table + vertOffset, valid->subtable_length, "vertJustData", odtect ); } gxv_odtect_validate( odtect, valid ); FT_TRACE4(( "\n" )); }
static void gxv_mort_subtables_validate( FT_Bytes table, FT_Bytes limit, FT_UShort nSubtables, GXV_Validator gxvalid ) { FT_Bytes p = table; GXV_Validate_Func fmt_funcs_table[] = { gxv_mort_subtable_type0_validate, /* 0 */ gxv_mort_subtable_type1_validate, /* 1 */ gxv_mort_subtable_type2_validate, /* 2 */ NULL, /* 3 */ gxv_mort_subtable_type4_validate, /* 4 */ gxv_mort_subtable_type5_validate, /* 5 */ }; FT_UShort i; GXV_NAME_ENTER( "subtables in a chain" ); for ( i = 0; i < nSubtables; i++ ) { GXV_Validate_Func func; FT_UShort length; FT_UShort coverage; #ifdef GXV_LOAD_UNUSED_VARS FT_ULong subFeatureFlags; #endif FT_UInt type; FT_UInt rest; GXV_LIMIT_CHECK( 2 + 2 + 4 ); length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); #ifdef GXV_LOAD_UNUSED_VARS subFeatureFlags = FT_NEXT_ULONG( p ); #else p += 4; #endif GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", i + 1, nSubtables, length )); type = coverage & 0x0007; rest = length - ( 2 + 2 + 4 ); GXV_LIMIT_CHECK( rest ); gxv_mort_coverage_validate( coverage, gxvalid ); if ( type > 5 ) FT_INVALID_FORMAT; func = fmt_funcs_table[type]; if ( func == NULL ) GXV_TRACE(( "morx type %d is reserved\n", type )); func( p, p + rest, gxvalid ); p += rest; /* TODO: validate subFeatureFlags */ } gxvalid->subtable_length = p - table; GXV_EXIT; }
tt_face_load_colr( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = face->root.memory; FT_Byte* table = NULL; FT_Byte* p = NULL; Colr* colr = NULL; FT_ULong base_glyph_offset, layer_offset; FT_ULong table_size; /* `COLR' always needs `CPAL' */ if ( !face->cpal ) return FT_THROW( Invalid_File_Format ); error = face->goto_table( face, TTAG_COLR, stream, &table_size ); if ( error ) goto NoColr; if ( table_size < COLR_HEADER_SIZE ) goto InvalidTable; if ( FT_FRAME_EXTRACT( table_size, table ) ) goto NoColr; p = table; if ( FT_NEW( colr ) ) goto NoColr; colr->version = FT_NEXT_USHORT( p ); if ( colr->version != 0 ) goto InvalidTable; colr->num_base_glyphs = FT_NEXT_USHORT( p ); base_glyph_offset = FT_NEXT_ULONG( p ); if ( base_glyph_offset >= table_size ) goto InvalidTable; if ( colr->num_base_glyphs * BASE_GLYPH_SIZE > table_size - base_glyph_offset ) goto InvalidTable; layer_offset = FT_NEXT_ULONG( p ); colr->num_layers = FT_NEXT_USHORT( p ); if ( layer_offset >= table_size ) goto InvalidTable; if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) goto InvalidTable; colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); colr->layers = (FT_Byte*)( table + layer_offset ); colr->table = table; colr->table_size = table_size; face->colr = colr; return FT_Err_Ok; InvalidTable: error = FT_THROW( Invalid_Table ); NoColr: FT_FRAME_RELEASE( table ); FT_FREE( colr ); return error; }
otv_BASE_validate( FT_Bytes table, FT_Validator ftvalid ) { OTV_ValidatorRec otvalidrec; OTV_Validator otvalid = &otvalidrec; FT_Bytes p = table; FT_UInt table_size; FT_UShort version; OTV_OPTIONAL_TABLE( HorizAxis ); OTV_OPTIONAL_TABLE( VertAxis ); OTV_OPTIONAL_TABLE32( itemVarStore ); otvalid->root = ftvalid; FT_TRACE3(( "validating BASE table\n" )); OTV_INIT; OTV_LIMIT_CHECK( 4 ); if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ FT_INVALID_FORMAT; version = FT_NEXT_USHORT( p ); /* minorVersion */ table_size = 8; switch ( version ) { case 0: OTV_LIMIT_CHECK( 4 ); break; case 1: OTV_LIMIT_CHECK( 8 ); table_size += 4; break; default: FT_INVALID_FORMAT; } OTV_OPTIONAL_OFFSET( HorizAxis ); OTV_SIZE_CHECK( HorizAxis ); if ( HorizAxis ) otv_Axis_validate( table + HorizAxis, otvalid ); OTV_OPTIONAL_OFFSET( VertAxis ); OTV_SIZE_CHECK( VertAxis ); if ( VertAxis ) otv_Axis_validate( table + VertAxis, otvalid ); if ( version > 0 ) { OTV_OPTIONAL_OFFSET32( itemVarStore ); OTV_SIZE_CHECK32( itemVarStore ); if ( itemVarStore ) OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ } FT_TRACE4(( "\n" )); }
static FT_UInt otv_Feature_get_count( FT_Bytes table ) { return FT_NEXT_USHORT( table ); }
static FT_UInt otv_LookupList_get_count( FT_Bytes table ) { return FT_NEXT_USHORT( table ); }
static void gxv_kern_subtable_fmt3_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; FT_UShort glyphCount; FT_Byte kernValueCount; FT_Byte leftClassCount; FT_Byte rightClassCount; FT_Byte flags; GXV_NAME_ENTER( "kern subtable format 3" ); GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); glyphCount = FT_NEXT_USHORT( p ); kernValueCount = FT_NEXT_BYTE( p ); leftClassCount = FT_NEXT_BYTE( p ); rightClassCount = FT_NEXT_BYTE( p ); flags = FT_NEXT_BYTE( p ); if ( valid->face->num_glyphs != glyphCount ) { GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", valid->face->num_glyphs, glyphCount )); if ( valid->root->level >= FT_VALIDATE_PARANOID ) FT_INVALID_GLYPH_ID; } /* * just skip kernValue[kernValueCount] */ GXV_LIMIT_CHECK( 2 * kernValueCount ); p += 2 * kernValueCount; /* * check leftClass[gid] < leftClassCount */ { FT_Byte min, max; GXV_LIMIT_CHECK( glyphCount ); gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); p += valid->subtable_length; if ( leftClassCount < max ) FT_INVALID_DATA; } /* * check rightClass[gid] < rightClassCount */ { FT_Byte min, max; GXV_LIMIT_CHECK( glyphCount ); gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid ); p += valid->subtable_length; if ( rightClassCount < max ) FT_INVALID_DATA; } /* * check kernIndex[i, j] < kernValueCount */ { FT_UShort i, j; for ( i = 0; i < leftClassCount; i++ ) { for ( j = 0; j < rightClassCount; j++ ) { GXV_LIMIT_CHECK( 1 ); if ( kernValueCount < FT_NEXT_BYTE( p ) ) FT_INVALID_OFFSET; } } } valid->subtable_length = p - table; GXV_EXIT; }
otv_GDEF_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 table_size; FT_UShort version; FT_Bool need_MarkAttachClassDef = 1; OTV_OPTIONAL_TABLE( GlyphClassDef ); OTV_OPTIONAL_TABLE( AttachListOffset ); OTV_OPTIONAL_TABLE( LigCaretListOffset ); OTV_OPTIONAL_TABLE( MarkAttachClassDef ); OTV_OPTIONAL_TABLE( MarkGlyphSetsDef ); OTV_OPTIONAL_TABLE32( itemVarStore ); otvalid->root = ftvalid; FT_TRACE3(( "validating GDEF table\n" )); OTV_INIT; OTV_LIMIT_CHECK( 4 ); if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ FT_INVALID_FORMAT; version = FT_NEXT_USHORT( p ); /* minorVersion */ table_size = 10; switch ( version ) { case 0: /* MarkAttachClassDef has been added to the OpenType */ /* specification without increasing GDEF's version, */ /* so we use this ugly hack to find out whether the */ /* table is needed actually. */ need_MarkAttachClassDef = FT_BOOL( otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); if ( need_MarkAttachClassDef ) { OTV_LIMIT_CHECK( 8 ); table_size += 2; } else OTV_LIMIT_CHECK( 6 ); /* OpenType < 1.2 */ break; case 2: OTV_LIMIT_CHECK( 10 ); table_size += 4; break; case 3: OTV_LIMIT_CHECK( 14 ); table_size += 8; break; default: FT_INVALID_FORMAT; } otvalid->glyph_count = glyph_count; OTV_OPTIONAL_OFFSET( GlyphClassDef ); OTV_SIZE_CHECK( GlyphClassDef ); if ( GlyphClassDef ) otv_ClassDef_validate( table + GlyphClassDef, otvalid ); OTV_OPTIONAL_OFFSET( AttachListOffset ); OTV_SIZE_CHECK( AttachListOffset ); if ( AttachListOffset ) { OTV_NEST2( AttachList, AttachPoint ); OTV_RUN( table + AttachListOffset, otvalid ); } OTV_OPTIONAL_OFFSET( LigCaretListOffset ); OTV_SIZE_CHECK( LigCaretListOffset ); if ( LigCaretListOffset ) { OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); OTV_RUN( table + LigCaretListOffset, otvalid ); } if ( need_MarkAttachClassDef ) { OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); OTV_SIZE_CHECK( MarkAttachClassDef ); if ( MarkAttachClassDef ) otv_ClassDef_validate( table + MarkAttachClassDef, otvalid ); } if ( version > 0 ) { OTV_OPTIONAL_OFFSET( MarkGlyphSetsDef ); OTV_SIZE_CHECK( MarkGlyphSetsDef ); if ( MarkGlyphSetsDef ) otv_MarkGlyphSets_validate( table + MarkGlyphSetsDef, otvalid ); } if ( version > 2 ) { OTV_OPTIONAL_OFFSET32( itemVarStore ); OTV_SIZE_CHECK32( itemVarStore ); if ( itemVarStore ) OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ } FT_TRACE4(( "\n" )); }
static void gxv_feat_name_validate( FT_Bytes table, FT_Bytes limit, GXV_Validator valid ) { FT_Bytes p = table; FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); FT_UShort feature; FT_UShort nSettings; FT_ULong settingTable; FT_UShort featureFlags; FT_Bool exclusive; FT_Int last_setting; FT_UInt i; GXV_NAME_ENTER( "name" ); /* feature + nSettings + settingTable + featureFlags */ GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); feature = FT_NEXT_USHORT( p ); GXV_FEAT_DATA( feature ) = feature; nSettings = FT_NEXT_USHORT( p ); settingTable = FT_NEXT_ULONG ( p ); featureFlags = FT_NEXT_USHORT( p ); if ( settingTable < reserved_size ) FT_INVALID_OFFSET; if ( ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); if ( exclusive ) { FT_Byte dynamic_default; if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) dynamic_default = (FT_Byte)( featureFlags & GXV_FEAT_MASK_DEFAULT_SETTING ); else dynamic_default = 0; /* If exclusive, check whether default setting is in the range. */ if ( !( dynamic_default < nSettings ) ) FT_INVALID_FORMAT; } gxv_feat_registry_validate( feature, nSettings, exclusive, valid ); gxv_feat_name_index_validate( p, limit, valid ); p = valid->root->base + settingTable; for ( last_setting = -1, i = 0; i < nSettings; i++ ) { gxv_feat_setting_validate( p, limit, exclusive, valid ); if ( (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); last_setting = (FT_Int)GXV_FEAT_DATA( setting ); /* setting + nameIndex */ p += ( 2 + 2 ); } GXV_EXIT; }
pfr_face_get_kerning( PFR_Face face, FT_UInt glyph1, FT_UInt glyph2, FT_Vector* kerning ) { FT_Error error; PFR_PhyFont phy_font = &face->phy_font; PFR_KernItem item = phy_font->kern_items; FT_UInt32 idx = PFR_KERN_INDEX( glyph1, glyph2 ); kerning->x = 0; kerning->y = 0; /* find the kerning item containing our pair */ while ( item ) { if ( item->pair1 <= idx && idx <= item->pair2 ) goto Found_Item; item = item->next; } /* not found */ goto Exit; Found_Item: { /* perform simply binary search within the item */ FT_UInt min, mid, max; FT_Stream stream = face->root.stream; FT_Byte* p; if ( FT_STREAM_SEEK( item->offset ) || FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) goto Exit; min = 0; max = item->pair_count; while ( min < max ) { FT_UInt char1, char2, charcode; mid = ( min + max ) >> 1; p = stream->cursor + mid*item->pair_size; if ( item->flags & PFR_KERN_2BYTE_CHAR ) { char1 = FT_NEXT_USHORT( p ); char2 = FT_NEXT_USHORT( p ); } else { char1 = FT_NEXT_USHORT( p ); char2 = FT_NEXT_USHORT( p ); } charcode = PFR_KERN_INDEX( char1, char2 ); if ( idx == charcode ) { if ( item->flags & PFR_KERN_2BYTE_ADJ ) kerning->x = item->base_adj + FT_NEXT_SHORT( p ); else kerning->x = item->base_adj + FT_NEXT_CHAR( p ); break; } if ( idx > charcode ) min = mid + 1; else max = mid; } FT_FRAME_EXIT(); } Exit: return 0; }
FT_Stream_ReadFields( FT_Stream stream, const FT_Frame_Field* fields, void* structure ) { FT_Error error; FT_Bool frame_accessed = 0; FT_Byte* cursor; if ( !fields || !stream ) return FT_Err_Invalid_Argument; cursor = stream->cursor; error = FT_Err_Ok; do { FT_ULong value; FT_Int sign_shift; FT_Byte* p; switch ( fields->value ) { case ft_frame_start: /* access a new frame */ error = FT_Stream_EnterFrame( stream, fields->offset ); if ( error ) goto Exit; frame_accessed = 1; cursor = stream->cursor; fields++; continue; /* loop! */ case ft_frame_bytes: /* read a byte sequence */ case ft_frame_skip: /* skip some bytes */ { FT_UInt len = fields->size; if ( cursor + len > stream->limit ) { error = FT_Err_Invalid_Stream_Operation; goto Exit; } if ( fields->value == ft_frame_bytes ) { p = (FT_Byte*)structure + fields->offset; FT_MEM_COPY( p, cursor, len ); } cursor += len; fields++; continue; } case ft_frame_byte: case ft_frame_schar: /* read a single byte */ value = FT_NEXT_BYTE(cursor); sign_shift = 24; break; case ft_frame_short_be: case ft_frame_ushort_be: /* read a 2-byte big-endian short */ value = FT_NEXT_USHORT(cursor); sign_shift = 16; break; case ft_frame_short_le: case ft_frame_ushort_le: /* read a 2-byte little-endian short */ value = FT_NEXT_USHORT_LE(cursor); sign_shift = 16; break; case ft_frame_long_be: case ft_frame_ulong_be: /* read a 4-byte big-endian long */ value = FT_NEXT_ULONG(cursor); sign_shift = 0; break; case ft_frame_long_le: case ft_frame_ulong_le: /* read a 4-byte little-endian long */ value = FT_NEXT_ULONG_LE(cursor); sign_shift = 0; break; case ft_frame_off3_be: case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ value = FT_NEXT_UOFF3(cursor); sign_shift = 8; break; case ft_frame_off3_le: case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ value = FT_NEXT_UOFF3_LE(cursor); sign_shift = 8; break; default: /* otherwise, exit the loop */ stream->cursor = cursor; goto Exit; } /* now, compute the signed value is necessary */ if ( fields->value & FT_FRAME_OP_SIGNED ) value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); /* finally, store the value in the object */ p = (FT_Byte*)structure + fields->offset; switch ( fields->size ) { case (8 / FT_CHAR_BIT): *(FT_Byte*)p = (FT_Byte)value; break; case (16 / FT_CHAR_BIT): *(FT_UShort*)p = (FT_UShort)value; break; case (32 / FT_CHAR_BIT): *(FT_UInt32*)p = (FT_UInt32)value; break; default: /* for 64-bit systems */ *(FT_ULong*)p = (FT_ULong)value; } /* go to next field */ fields++; } while ( 1 ); Exit: /* close the frame if it was opened by this read */ if ( frame_accessed ) FT_Stream_ExitFrame( stream ); return error; }
static void otv_SingleSubst_validate( FT_Bytes table, OTV_Validator otvalid ) { FT_Bytes p = table; FT_UInt SubstFormat; OTV_NAME_ENTER( "SingleSubst" ); OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); OTV_TRACE(( " (format %d)\n", SubstFormat )); switch ( SubstFormat ) { case 1: /* SingleSubstFormat1 */ { FT_Bytes Coverage; FT_Int DeltaGlyphID; FT_Long idx; OTV_LIMIT_CHECK( 4 ); Coverage = table + FT_NEXT_USHORT( p ); DeltaGlyphID = FT_NEXT_SHORT( p ); otv_Coverage_validate( Coverage, otvalid, -1 ); idx = (FT_Long)otv_Coverage_get_first( Coverage ) + DeltaGlyphID; if ( idx < 0 ) FT_INVALID_DATA; idx = (FT_Long)otv_Coverage_get_last( Coverage ) + DeltaGlyphID; if ( (FT_UInt)idx >= otvalid->glyph_count ) FT_INVALID_DATA; } break; case 2: /* SingleSubstFormat2 */ { FT_UInt Coverage, GlyphCount; OTV_LIMIT_CHECK( 4 ); Coverage = FT_NEXT_USHORT( p ); GlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)GlyphCount ); OTV_LIMIT_CHECK( GlyphCount * 2 ); /* Substitute */ for ( ; GlyphCount > 0; GlyphCount-- ) if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) FT_INVALID_GLYPH_ID; } break; default: FT_INVALID_FORMAT; } OTV_EXIT; }
tt_face_load_kern( TT_Face face, FT_Stream stream ) { FT_Error error; FT_ULong table_size; FT_Byte* p; FT_Byte* p_limit; FT_UInt nn, num_tables; FT_UInt32 avail = 0, ordered = 0; /* the kern table is optional; exit silently if it is missing */ error = face->goto_table( face, TTAG_kern, stream, &table_size ); if ( error ) goto Exit; if ( table_size < 4 ) /* the case of a malformed table */ { FT_ERROR(( "tt_face_load_kern:" " kerning table is too small - ignored\n" )); error = FT_THROW( Table_Missing ); goto Exit; } if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) { FT_ERROR(( "tt_face_load_kern:" " could not extract kerning table\n" )); goto Exit; } face->kern_table_size = table_size; p = face->kern_table; p_limit = p + table_size; p += 2; /* skip version */ num_tables = FT_NEXT_USHORT( p ); if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ num_tables = 32; for ( nn = 0; nn < num_tables; nn++ ) { FT_UInt num_pairs, length, coverage; FT_Byte* p_next; FT_UInt32 mask = (FT_UInt32)1UL << nn; if ( p + 6 > p_limit ) break; p_next = p; p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); if ( length <= 6 + 8 ) break; p_next += length; if ( p_next > p_limit ) /* handle broken table */ p_next = p_limit; /* only use horizontal kerning tables */ if ( ( coverage & ~8U ) != 0x0001 || p + 8 > p_limit ) goto NextTable; num_pairs = FT_NEXT_USHORT( p ); p += 6; if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); avail |= mask; /* * Now check whether the pairs in this table are ordered. * We then can use binary search. */ if ( num_pairs > 0 ) { FT_ULong count; FT_ULong old_pair; old_pair = FT_NEXT_ULONG( p ); p += 2; for ( count = num_pairs - 1; count > 0; count-- ) { FT_UInt32 cur_pair; cur_pair = FT_NEXT_ULONG( p ); if ( cur_pair <= old_pair ) break; p += 2; old_pair = cur_pair; } if ( count == 0 ) ordered |= mask; } NextTable: p = p_next; } face->num_kern_tables = nn; face->kern_avail_bits = avail; face->kern_order_bits = ordered; Exit: return error; }
static void otv_ReverseChainSingleSubst_validate( FT_Bytes table, OTV_Validator otvalid ) { FT_Bytes p = table, Coverage; FT_UInt SubstFormat; FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; OTV_NAME_ENTER( "ReverseChainSingleSubst" ); OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); OTV_TRACE(( " (format %d)\n", SubstFormat )); switch ( SubstFormat ) { case 1: /* ReverseChainSingleSubstFormat1 */ OTV_LIMIT_CHECK( 4 ); Coverage = table + FT_NEXT_USHORT( p ); BacktrackGlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); otv_Coverage_validate( Coverage, otvalid, -1 ); OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); LookaheadGlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); GlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) FT_INVALID_DATA; OTV_LIMIT_CHECK( GlyphCount * 2 ); /* Substitute */ for ( ; GlyphCount > 0; GlyphCount-- ) if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) FT_INVALID_DATA; break; default: FT_INVALID_FORMAT; } OTV_EXIT; }
static FT_Error tt_face_load_bdf_props( TT_Face face, FT_Stream stream ) { TT_BDF bdf = &face->bdf; FT_ULong length; FT_Error error; FT_ZERO( bdf ); error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); if ( error || length < 8 || FT_FRAME_EXTRACT( length, bdf->table ) ) { error = FT_THROW( Invalid_Table ); goto Exit; } bdf->table_end = bdf->table + length; { FT_Byte* p = bdf->table; FT_UInt version = FT_NEXT_USHORT( p ); FT_UInt num_strikes = FT_NEXT_USHORT( p ); FT_ULong strings = FT_NEXT_ULONG ( p ); FT_UInt count; FT_Byte* strike; if ( version != 0x0001 || strings < 8 || ( strings - 8 ) / 4 < num_strikes || strings + 1 > length ) { goto BadTable; } bdf->num_strikes = num_strikes; bdf->strings = bdf->table + strings; bdf->strings_size = length - strings; count = bdf->num_strikes; p = bdf->table + 8; strike = p + count * 4; for ( ; count > 0; count-- ) { FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); /* * We don't need to check the value sets themselves, since this * is done later. */ strike += 10 * num_items; p += 4; } if ( strike > bdf->strings ) goto BadTable; } bdf->loaded = 1; Exit: return error; BadTable: FT_FRAME_RELEASE( bdf->table ); FT_ZERO( bdf ); error = FT_THROW( Invalid_Table ); goto Exit; }
otv_ClassDef_validate( FT_Bytes table, OTV_Validator otvalid ) { FT_Bytes p = table; FT_UInt ClassFormat; OTV_NAME_ENTER( "ClassDef" ); OTV_LIMIT_CHECK( 4 ); ClassFormat = FT_NEXT_USHORT( p ); OTV_TRACE(( " (format %d)\n", ClassFormat )); switch ( ClassFormat ) { case 1: /* ClassDefFormat1 */ { FT_UInt StartGlyph; FT_UInt GlyphCount; OTV_LIMIT_CHECK( 4 ); StartGlyph = FT_NEXT_USHORT( p ); GlyphCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ if ( StartGlyph + GlyphCount - 1 >= otvalid->glyph_count ) FT_INVALID_GLYPH_ID; } break; case 2: /* ClassDefFormat2 */ { FT_UInt n, ClassRangeCount; FT_UInt Start, End, last = 0; ClassRangeCount = FT_NEXT_USHORT( p ); OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); OTV_LIMIT_CHECK( ClassRangeCount * 6 ); /* ClassRangeRecord */ for ( n = 0; n < ClassRangeCount; n++ ) { Start = FT_NEXT_USHORT( p ); End = FT_NEXT_USHORT( p ); p += 2; /* skip Class */ if ( Start > End || ( n > 0 && Start <= last ) ) FT_INVALID_DATA; if ( End >= otvalid->glyph_count ) FT_INVALID_GLYPH_ID; last = End; } } break; default: FT_INVALID_FORMAT; } /* no need to check glyph indices used as input to class definition */ /* tables since even invalid glyph indices return a meaningful result */ OTV_EXIT; }