| 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" ));
|
|
|