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.
diff --git a/ChangeLog b/ChangeLog
index e0e822f..7bf3f72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-08-04 Werner Lemberg <wl@gnu.org>
+
+ 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 <wl@gnu.org>
* src/cff/cffgload.c (cff_decoder_parse_charstrings): No longer
diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c
index 6b7c342..126cbef 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;
}