From 6f1eca046074c024a8c9235caa887b9cbadde5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wu=2C=20Chia-I=20=28=E5=90=B3=E4=BD=B3=E4=B8=80=29?= Date: Sun, 20 Nov 2005 08:24:24 +0000 Subject: [PATCH] * src/sfnt/ttload.c (sfnt_dir_check): Clean up and return correct error code. (sfnt_init): New function to fill in face->ttc_header. A non-TTC font is synthesized into a TTC font with one offset table. (tt_face_load_sfnt_header): Use sfnt_init. Fix an invalid access when the font is TTC and face_index is -1. --- ChangeLog | 9 ++ src/sfnt/ttload.c | 245 ++++++++++++++++++++++------------------------ 2 files changed, 124 insertions(+), 130 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b18a002f..f731573f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-11-20 Chia-I Wu + + * src/sfnt/ttload.c (sfnt_dir_check): Clean up and return correct + error code. + (sfnt_init): New function to fill in face->ttc_header. A non-TTC font + is synthesized into a TTC font with one offset table. + (tt_face_load_sfnt_header): Use sfnt_init. + Fix an invalid access when the font is TTC and face_index is -1. + 2005-11-18 Werner Lemberg * src/sfnt/ttload.c (tt_face_load_metrics): Ignore excess number diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c index 0c3d357c3..6a9a7a29f 100644 --- a/src/sfnt/ttload.c +++ b/src/sfnt/ttload.c @@ -151,13 +151,13 @@ /* Type 42 fonts, and will generally be invalid. */ /* */ static FT_Error - sfnt_dir_check( FT_Stream stream, - FT_ULong offset, - FT_UInt num_tables ) - { + sfnt_dir_check( 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' ); @@ -176,43 +176,33 @@ }; - /* if 'num_tables' is 0, read the table count from the file */ - if ( num_tables == 0 ) - { - if ( FT_STREAM_SEEK( offset ) || - FT_STREAM_SKIP( 4 ) || - FT_READ_USHORT( num_tables ) || - FT_STREAM_SKIP( 6 ) ) - goto Bad_Format; + if ( sfnt->num_tables == 0 || + offset + sfnt->num_tables * 16 > stream->size ) + return SFNT_Err_Unknown_File_Format; - if ( offset + 12 + num_tables*16 > stream->size ) - goto Bad_Format; - } - else if ( FT_STREAM_SEEK( offset + 12 ) ) - goto Bad_Format; + if ( FT_STREAM_SEEK( offset ) ) + return error; - for ( nn = 0; nn < num_tables; nn++ ) + for ( nn = 0; nn < sfnt->num_tables; nn++ ) { TT_TableRec table; if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) ) - goto Bad_Format; + return error; if ( table.Offset + table.Length > stream->size && table.Tag != glyx_tag && table.Tag != locx_tag ) - goto Bad_Format; + return SFNT_Err_Unknown_File_Format; - if ( table.Tag == TTAG_head ) + if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) { FT_UInt32 magic; - -#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS - head_retry: -#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - - has_head = 1; +#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + if ( table.Tag == TTAG_head ) +#endif + has_head = 1; /* The table length should be 0x36, but certain font tools * make it 0x38, so we will just check that it is greater. @@ -221,41 +211,98 @@ * the table must be padded to 32-bit lengths, but this doesn't * apply to the value of its "Length" field! */ - if ( table.Length < 0x36 || - FT_STREAM_SEEK( table.Offset + 12 ) || - FT_READ_ULONG( magic ) || - magic != 0x5F0F3CF5UL ) - goto Bad_Format; + if ( table.Length < 0x36 ) + return SFNT_Err_Unknown_File_Format; - if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) ) - goto Bad_Format; + if ( FT_STREAM_SEEK( table.Offset + 12 ) || + FT_READ_ULONG( magic ) ) + return error; + + if ( magic != 0x5F0F3CF5UL ) + return SFNT_Err_Unknown_File_Format; + + if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) + return error; } - -#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS - else if ( table.Tag == TTAG_bhed ) - goto head_retry; -#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - else if ( table.Tag == TTAG_SING ) has_sing = 1; else if ( table.Tag == TTAG_META ) has_meta = 1; } - /* when sing and meta are present, head is not present */ - if ( has_sing && has_meta && has_head == 0 ) - goto Exit; + if ( has_head || ( has_sing && has_meta ) ) + return SFNT_Err_Ok; + else + return SFNT_Err_Unknown_File_Format; + } - /* otherwise, treat a missing head as a failure */ - if ( has_head == 0 ) - goto Bad_Format; - Exit: + /* Fill in face->ttc_header. If the font is not a TTC, it is */ + /* synthesized into a TTC with one offset table. */ + static FT_Error + sfnt_init( FT_Stream stream, + TT_Face face ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_ULong tag, offset; + + static const FT_Frame_Field ttc_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TTC_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_LONG( version ), + FT_FRAME_LONG( count ), + FT_FRAME_END + }; + + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + + offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( tag ) ) + return error; + + face->ttc_header.tag = TTAG_ttcf; + + if ( tag == TTAG_ttcf ) + { + FT_Int n; + + + FT_TRACE3(( "sfnt_init: file is a collection\n" )); + + if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) + return error; + + /* now read the offsets of each font in the file */ + if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + return error; + + if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) + return error; + + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + } + else + { + face->ttc_header.version = 1 << 16; + face->ttc_header.count = 1; + + if ( FT_NEW( face->ttc_header.offsets) ) + return error; + + face->ttc_header.offsets[0] = offset; + } + return error; - - Bad_Format: - error = SFNT_Err_Unknown_File_Format; - goto Exit; } @@ -295,9 +342,7 @@ FT_Long face_index, SFNT_Header sfnt ) { - FT_Error error; - FT_ULong font_format_tag, format_tag, offset; - FT_Memory memory = stream->memory; + FT_Error error; static const FT_Frame_Field sfnt_header_fields[] = { @@ -312,95 +357,35 @@ FT_FRAME_END }; - static const FT_Frame_Field ttc_header_fields[] = - { -#undef FT_STRUCTURE -#define FT_STRUCTURE TTC_HeaderRec - - FT_FRAME_START( 8 ), - FT_FRAME_LONG( version ), - FT_FRAME_LONG( count ), - FT_FRAME_END - }; - FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n", face, face_index )); - face->ttc_header.tag = 0; - face->ttc_header.version = 0; - face->ttc_header.count = 0; + error = sfnt_init( stream, face ); + if ( error ) + return error; - face->num_tables = 0; + if ( face_index < 0 ) + face_index = 0; - /* First of all, read the first 4 bytes. If it is `ttcf', then the */ - /* file is a TrueType collection, otherwise it is a single-face font. */ - /* */ - offset = FT_STREAM_POS(); + if ( face_index >= face->ttc_header.count ) + return SFNT_Err_Bad_Argument; - if ( FT_READ_ULONG( font_format_tag ) ) - goto Exit; + sfnt->offset = face->ttc_header.offsets[face_index]; - format_tag = font_format_tag; + if ( FT_STREAM_SEEK( sfnt->offset ) ) + return error; - if ( font_format_tag == TTAG_ttcf ) - { - FT_Int n; - - - FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" )); - - /* It is a TrueType collection, i.e. a file containing several */ - /* font files. Read the font directory now */ - if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) - goto Exit; - - /* now read the offsets of each font in the file */ - if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) || - FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) - goto Exit; - - for ( n = 0; n < face->ttc_header.count; n++ ) - face->ttc_header.offsets[n] = FT_GET_ULONG(); - - FT_FRAME_EXIT(); - - /* check face index */ - if ( face_index >= face->ttc_header.count ) - { - error = SFNT_Err_Bad_Argument; - goto Exit; - } - - /* seek to the appropriate TrueType file, then read tag */ - offset = face->ttc_header.offsets[face_index]; - - if ( FT_STREAM_SEEK( offset ) || - FT_READ_LONG( format_tag ) ) - goto Exit; - } - - /* the format tag was read, now check the rest of the header */ - sfnt->format_tag = format_tag; - sfnt->offset = offset; - - if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) ) - goto Exit; + /* read offset table */ + if ( FT_READ_ULONG( sfnt->format_tag ) || + FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) ) + return error; /* now check the sfnt directory */ - error = sfnt_dir_check( stream, offset, sfnt->num_tables ); + error = sfnt_dir_check( sfnt, stream ); if ( error ) - { - FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" )); - error = SFNT_Err_Unknown_File_Format; - goto Exit; - } + FT_TRACE2(( "tt_face_load_sfnt_header: invalid SFNT!\n" )); - /* disallow face index values > 0 for non-TTC files */ - if ( font_format_tag != TTAG_ttcf && face_index > 0 ) - error = SFNT_Err_Bad_Argument; - - Exit: return error; }