* 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.
This commit is contained in:
Wu, Chia-I (吳佳一) 2005-11-20 08:24:24 +00:00
parent 6c99045972
commit 6f1eca0460
2 changed files with 124 additions and 130 deletions

View File

@ -1,3 +1,12 @@
2005-11-20 Chia-I Wu <b90201047@ntu.edu.tw>
* 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 <wl@gnu.org>
* src/sfnt/ttload.c (tt_face_load_metrics): Ignore excess number

View File

@ -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;
}