From 17e69011123a339f3fd5bdf1fafa866f8431513a Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Mon, 4 Aug 2008 05:45:41 +0000 Subject: [PATCH] Be more tolerant w.r.t. invalid entries in SFNT table directory. * src/sfnt/ttload.c (check_table_dir): Ignore invalid entries and adjust table count. Add more trace messages. (tt_face_load_font_dir): Updated. --- ChangeLog | 9 +++ src/sfnt/ttload.c | 140 +++++++++++++++++++++++++++++----------------- 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0e822fb8..7bf3f72fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-08-04 Werner Lemberg + + Be more tolerant w.r.t. invalid entries in SFNT table directory. + + * src/sfnt/ttload.c (check_table_dir): Ignore invalid entries and + adjust table count. + Add more trace messages. + (tt_face_load_font_dir): Updated. + 2008-07-30 Werner Lemberg * src/cff/cffgload.c (cff_decoder_parse_charstrings): No longer diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c index 6b7c34262..126cbefe1 100644 --- a/src/sfnt/ttload.c +++ b/src/sfnt/ttload.c @@ -124,7 +124,7 @@ *length = table->Length; if ( FT_STREAM_SEEK( table->Offset ) ) - goto Exit; + goto Exit; } else error = SFNT_Err_Table_Missing; @@ -134,27 +134,21 @@ } - /* Here, we */ - /* */ - /* - check that `num_tables' is valid */ - /* - look for a `head' table, check its size, and parse it to check */ - /* whether its `magic' field is correctly set */ - /* */ - /* When checking directory entries, ignore the tables `glyx' and `locx' */ - /* which are hacked-out versions of `glyf' and `loca' in some PostScript */ - /* Type 42 fonts, and which are generally invalid. */ - /* */ + /* Here, we */ + /* */ + /* - check that `num_tables' is valid (and adjust it if necessary) */ + /* */ + /* - look for a `head' table, check its size, and parse it to check */ + /* whether its `magic' field is correctly set */ + /* */ static FT_Error check_table_dir( SFNT_Header sfnt, FT_Stream stream ) { - FT_Error error; - FT_UInt nn; - FT_UInt has_head = 0, has_sing = 0, has_meta = 0; - FT_ULong offset = sfnt->offset + 12; - - const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); - const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); + FT_Error error; + FT_UInt nn, valid_entries = 0; + FT_UInt has_head = 0, has_sing = 0, has_meta = 0; + FT_ULong offset = sfnt->offset + 12; static const FT_Frame_Field table_dir_entry_fields[] = { @@ -170,12 +164,8 @@ }; - if ( sfnt->num_tables == 0 || - offset + sfnt->num_tables * 16 > stream->size ) - return SFNT_Err_Unknown_File_Format; - if ( FT_STREAM_SEEK( offset ) ) - return error; + goto Exit; for ( nn = 0; nn < sfnt->num_tables; nn++ ) { @@ -183,12 +173,23 @@ if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) - return error; + { + nn--; + FT_TRACE2(( "check_table_dir:" + " can read only %d table%s in font (instead of %d)\n", + nn, nn == 1 ? "" : "s", sfnt->num_tables )); + sfnt->num_tables = nn; + break; + } - if ( table.Offset + table.Length > stream->size && - table.Tag != glyx_tag && - table.Tag != locx_tag ) - return SFNT_Err_Unknown_File_Format; + /* we ignore invalid tables */ + if ( table.Offset + table.Length > stream->size ) + { + FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + continue; + } + else + valid_entries++; if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) { @@ -210,17 +211,26 @@ * */ if ( table.Length < 0x36 ) - return SFNT_Err_Unknown_File_Format; + { + FT_TRACE2(( "check_table_dir: `head' table too small\n" )); + error = SFNT_Err_Unknown_File_Format; + goto Exit; + } if ( FT_STREAM_SEEK( table.Offset + 12 ) || FT_READ_ULONG( magic ) ) - return error; + goto Exit; if ( magic != 0x5F0F3CF5UL ) - return SFNT_Err_Unknown_File_Format; + { + FT_TRACE2(( "check_table_dir:" + " no magic number found in `head' table\n")); + error = SFNT_Err_Unknown_File_Format; + goto Exit; + } if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) - return error; + goto Exit; } else if ( table.Tag == TTAG_SING ) has_sing = 1; @@ -228,11 +238,34 @@ has_meta = 1; } + sfnt->num_tables = valid_entries; + + if ( sfnt->num_tables == 0 ) + { + FT_TRACE2(( "check_table_dir: no tables found\n" )); + error = SFNT_Err_Unknown_File_Format; + goto Exit; + } + /* if `sing' and `meta' tables are present, there is no `head' table */ if ( has_head || ( has_sing && has_meta ) ) - return SFNT_Err_Ok; + { + error = SFNT_Err_Ok; + goto Exit; + } else - return SFNT_Err_Unknown_File_Format; + { + FT_TRACE2(( "check_table_dir:" )); +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); +#else + FT_TRACE2(( " neither `head' nor `sing' table found\n" )); +#endif + error = SFNT_Err_Unknown_File_Format; + } + + Exit: + return error; } @@ -266,7 +299,7 @@ FT_Error error; FT_Memory memory = stream->memory; TT_TableRec* entry; - TT_TableRec* limit; + FT_Int nn; static const FT_Frame_Field offset_table_fields[] = { @@ -290,7 +323,7 @@ if ( FT_READ_ULONG( sfnt.format_tag ) || FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) - return error; + goto Exit; /* many fonts don't have these fields set correctly */ #if 0 @@ -301,8 +334,8 @@ /* load the table directory */ - FT_TRACE2(( "-- Tables count: %12u\n", sfnt.num_tables )); - FT_TRACE2(( "-- Format version: %08lx\n", sfnt.format_tag )); + FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); + FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); /* check first */ error = check_table_dir( &sfnt, stream ); @@ -310,42 +343,49 @@ { FT_TRACE2(( "tt_face_load_font_dir: invalid table directory!\n" )); - return error; + goto Exit; } face->num_tables = sfnt.num_tables; face->format_tag = sfnt.format_tag; if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) - return error; + goto Exit; if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || FT_FRAME_ENTER( face->num_tables * 16L ) ) - return error; + goto Exit; entry = face->dir_tables; - limit = entry + face->num_tables; - for ( ; entry < limit; entry++ ) + for ( nn = 0; nn < sfnt.num_tables; nn++ ) { entry->Tag = FT_GET_TAG4(); entry->CheckSum = FT_GET_ULONG(); entry->Offset = FT_GET_LONG(); entry->Length = FT_GET_LONG(); - FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", - (FT_Char)( entry->Tag >> 24 ), - (FT_Char)( entry->Tag >> 16 ), - (FT_Char)( entry->Tag >> 8 ), - (FT_Char)( entry->Tag ), - entry->Offset, - entry->Length )); + /* ignore invalid tables */ + if ( entry->Offset + entry->Length > stream->size ) + continue; + else + { + FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", + (FT_Char)( entry->Tag >> 24 ), + (FT_Char)( entry->Tag >> 16 ), + (FT_Char)( entry->Tag >> 8 ), + (FT_Char)( entry->Tag ), + entry->Offset, + entry->Length )); + entry++; + } } FT_FRAME_EXIT(); FT_TRACE2(( "table directory loaded\n\n" )); + Exit: return error; }