Index: third_party/freetype/src/sfnt/ttload.c |
diff --git a/third_party/freetype/src/sfnt/ttload.c b/third_party/freetype/src/sfnt/ttload.c |
index 8338150abd4adcbaa7259258e7b68905de11fd59..c1bd7f0c82eb8686e5eb31a0bbb2b579954e2f60 100644 |
--- a/third_party/freetype/src/sfnt/ttload.c |
+++ b/third_party/freetype/src/sfnt/ttload.c |
@@ -5,7 +5,7 @@ |
/* Load the basic TrueType tables, i.e., tables that can be either in */ |
/* TTF or OTF fonts (body). */ |
/* */ |
-/* Copyright 1996-2010, 2012-2014 by */ |
+/* Copyright 1996-2015 by */ |
/* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
/* */ |
/* This file is part of the FreeType project, and may only be used, */ |
@@ -151,7 +151,8 @@ |
/* Here, we */ |
/* */ |
- /* - check that `num_tables' is valid (and adjust it if necessary) */ |
+ /* - check that `num_tables' is valid (and adjust it if necessary); */ |
+ /* also return the number of valid table entries */ |
/* */ |
/* - look for a `head' table, check its size, and parse it to check */ |
/* whether its `magic' field is correctly set */ |
@@ -167,7 +168,8 @@ |
/* */ |
static FT_Error |
check_table_dir( SFNT_Header sfnt, |
- FT_Stream stream ) |
+ FT_Stream stream, |
+ FT_UShort* valid ) |
{ |
FT_Error error; |
FT_UShort nn, valid_entries = 0; |
@@ -208,13 +210,27 @@ |
/* we ignore invalid tables */ |
- /* table.Offset + table.Length > stream->size ? */ |
- if ( table.Length > stream->size || |
- table.Offset > stream->size - table.Length ) |
+ if ( table.Offset > stream->size ) |
{ |
FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); |
continue; |
} |
+ else if ( table.Length > stream->size - table.Offset ) |
+ { |
+ /* Some tables have such a simple structure that clipping its */ |
+ /* contents is harmless. This also makes FreeType less sensitive */ |
+ /* to invalid table lengths (which programs like Acroread seem to */ |
+ /* ignore in general). */ |
+ |
+ if ( table.Tag == TTAG_hmtx || |
+ table.Tag == TTAG_vmtx ) |
+ valid_entries++; |
+ else |
+ { |
+ FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); |
+ continue; |
+ } |
+ } |
else |
valid_entries++; |
@@ -262,11 +278,11 @@ |
has_meta = 1; |
} |
- sfnt->num_tables = valid_entries; |
+ *valid = valid_entries; |
- if ( sfnt->num_tables == 0 ) |
+ if ( !valid_entries ) |
{ |
- FT_TRACE2(( "check_table_dir: no tables found\n" )); |
+ FT_TRACE2(( "check_table_dir: no valid tables found\n" )); |
error = FT_THROW( Unknown_File_Format ); |
goto Exit; |
} |
@@ -322,8 +338,7 @@ |
SFNT_HeaderRec sfnt; |
FT_Error error; |
FT_Memory memory = stream->memory; |
- TT_TableRec* entry; |
- FT_Int nn; |
+ FT_UShort nn, valid_entries; |
static const FT_Frame_Field offset_table_fields[] = |
{ |
@@ -364,59 +379,114 @@ |
if ( sfnt.format_tag != TTAG_OTTO ) |
{ |
/* check first */ |
- error = check_table_dir( &sfnt, stream ); |
+ error = check_table_dir( &sfnt, stream, &valid_entries ); |
if ( error ) |
{ |
FT_TRACE2(( "tt_face_load_font_dir:" |
" invalid table directory for TrueType\n" )); |
- |
goto Exit; |
} |
} |
+ else |
+ valid_entries = sfnt.num_tables; |
- face->num_tables = sfnt.num_tables; |
+ face->num_tables = valid_entries; |
face->format_tag = sfnt.format_tag; |
if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) |
goto Exit; |
- if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || |
- FT_FRAME_ENTER( face->num_tables * 16L ) ) |
+ if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || |
+ FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) |
goto Exit; |
- entry = face->dir_tables; |
- |
FT_TRACE2(( "\n" |
" tag offset length checksum\n" |
" ----------------------------------\n" )); |
+ valid_entries = 0; |
for ( nn = 0; nn < sfnt.num_tables; nn++ ) |
{ |
- entry->Tag = FT_GET_TAG4(); |
- entry->CheckSum = FT_GET_ULONG(); |
- entry->Offset = FT_GET_ULONG(); |
- entry->Length = FT_GET_ULONG(); |
+ TT_TableRec entry; |
+ FT_UShort i; |
+ FT_Bool duplicate; |
- /* ignore invalid tables */ |
- /* entry->Offset + entry->Length > stream->size ? */ |
- if ( entry->Length > stream->size || |
- entry->Offset > stream->size - entry->Length ) |
+ entry.Tag = FT_GET_TAG4(); |
+ entry.CheckSum = FT_GET_ULONG(); |
+ entry.Offset = FT_GET_ULONG(); |
+ entry.Length = FT_GET_ULONG(); |
+ |
+ /* ignore invalid tables that can't be sanitized */ |
+ |
+ if ( entry.Offset > stream->size ) |
continue; |
+ else if ( entry.Length > stream->size - entry.Offset ) |
+ { |
+ if ( entry.Tag == TTAG_hmtx || |
+ entry.Tag == TTAG_vmtx ) |
+ { |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ FT_ULong old_length = entry.Length; |
+#endif |
+ |
+ |
+ /* make metrics table length a multiple of 4 */ |
+ entry.Length = ( stream->size - entry.Offset ) & ~3U; |
+ |
+ FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" |
+ " (sanitized; original length %08lx)", |
+ (FT_Char)( entry.Tag >> 24 ), |
+ (FT_Char)( entry.Tag >> 16 ), |
+ (FT_Char)( entry.Tag >> 8 ), |
+ (FT_Char)( entry.Tag ), |
+ entry.Offset, |
+ entry.Length, |
+ entry.CheckSum, |
+ old_length )); |
+ } |
+ else |
+ continue; |
+ } |
+#ifdef FT_DEBUG_LEVEL_TRACE |
else |
+ FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", |
+ (FT_Char)( entry.Tag >> 24 ), |
+ (FT_Char)( entry.Tag >> 16 ), |
+ (FT_Char)( entry.Tag >> 8 ), |
+ (FT_Char)( entry.Tag ), |
+ entry.Offset, |
+ entry.Length, |
+ entry.CheckSum )); |
+#endif |
+ |
+ /* ignore duplicate tables – the first one wins */ |
+ duplicate = 0; |
+ for ( i = 0; i < valid_entries; i++ ) |
{ |
- FT_TRACE2(( " %c%c%c%c %08lx %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->CheckSum )); |
- entry++; |
+ if ( face->dir_tables[i].Tag == entry.Tag ) |
+ { |
+ duplicate = 1; |
+ break; |
+ } |
+ } |
+ if ( duplicate ) |
+ { |
+ FT_TRACE2(( " (duplicate, ignored)\n" )); |
+ continue; |
+ } |
+ else |
+ { |
+ FT_TRACE2(( "\n" )); |
+ |
+ /* we finally have a valid entry */ |
+ face->dir_tables[valid_entries++] = entry; |
} |
} |
+ /* final adjustment to number of tables */ |
+ face->num_tables = valid_entries; |
+ |
FT_FRAME_EXIT(); |
FT_TRACE2(( "table directory loaded\n\n" )); |