diff --git a/ChangeLog b/ChangeLog index fe34f6477..02539f6b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2016-05-16 Werner Lemberg + + [cid] Fix scanning for `StartData' and `/sfnts' (#47892). + + * src/cid/cidparse.c (STARTDATA, STARTDATA_LEN, SFNTS, SFNTS_LEN): + New macros. + (cid_parser_new): Fix and document algorithm. + 2016-05-16 suzuki toshiya [truetype] Improve the recursive reference detector. diff --git a/src/cid/cidparse.c b/src/cid/cidparse.c index f1c39f6d0..73aca2ac6 100644 --- a/src/cid/cidparse.c +++ b/src/cid/cidparse.c @@ -47,6 +47,12 @@ /*************************************************************************/ +#define STARTDATA "StartData" +#define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 ) +#define SFNTS "/sfnts" +#define SFNTS_LEN ( sizeof ( SFNTS ) - 1 ) + + FT_LOCAL_DEF( FT_Error ) cid_parser_new( CID_Parser* parser, FT_Stream stream, @@ -85,9 +91,29 @@ /* now, read the rest of the file until we find */ /* `StartData' or `/sfnts' */ { - FT_Byte buffer[256 + 10]; - FT_ULong read_len = 256 + 10; - FT_Byte* p = buffer; + /* + * The algorithm is as follows (omitting the case with less than 256 + * bytes to fill for simplicity). + * + * 1. Fill the buffer with 256 + STARTDATA_LEN bytes. + * + * 2. Search for the STARTDATA and SFNTS strings at positions + * buffer[0], buffer[1], ..., + * buffer[255 + STARTDATA_LEN - SFNTS_LEN]. + * + * 3. Move the last STARTDATA_LEN bytes to buffer[0]. + * + * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN. + * + * 5. Repeat with step 2. + * + */ + FT_Byte buffer[256 + STARTDATA_LEN + 1]; + + /* values for the first loop */ + FT_ULong read_len = 256 + STARTDATA_LEN; + FT_ULong read_offset = 0; + FT_Byte* p = buffer; for ( offset = FT_STREAM_POS(); ; offset += 256 ) @@ -96,40 +122,48 @@ stream_len = stream->size - FT_STREAM_POS(); - if ( stream_len == 0 ) + + read_len = FT_MIN( read_len, stream_len ); + if ( FT_STREAM_READ( p, read_len ) ) + goto Exit; + + /* ensure that we do not compare with data beyond the buffer */ + p[read_len] = '\0'; + + limit = p + read_len - SFNTS_LEN; + + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && + ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) + { + /* save offset of binary data after `StartData' */ + offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN; + goto Found; + } + else if ( p[1] == 's' && + ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) + { + offset += (FT_ULong)( p - buffer ) + SFNTS_LEN; + goto Found; + } + } + + if ( read_offset + read_len < STARTDATA_LEN ) { FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } - read_len = FT_MIN( read_len, stream_len ); - if ( FT_STREAM_READ( p, read_len ) ) - goto Exit; + FT_MEM_MOVE( buffer, + buffer + read_offset + read_len - STARTDATA_LEN, + STARTDATA_LEN ); - if ( read_len < 256 ) - p[read_len] = '\0'; - - limit = p + read_len - 10; - - for ( p = buffer; p < limit; p++ ) - { - if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 ) - { - /* save offset of binary data after `StartData' */ - offset += (FT_ULong)( p - buffer + 10 ); - goto Found; - } - else if ( p[1] == 's' && ft_strncmp( (char*)p, "/sfnts", 6 ) == 0 ) - { - offset += (FT_ULong)( p - buffer + 7 ); - goto Found; - } - } - - FT_MEM_MOVE( buffer, p, 10 ); - read_len = 256; - p = buffer + 10; + /* values for the next loop */ + read_len = 256; + read_offset = STARTDATA_LEN; + p = buffer + read_offset; } } @@ -165,7 +199,7 @@ limit = parser->root.limit; cur = parser->root.cursor; - while ( cur < limit ) + while ( cur < limit - SFNTS_LEN ) { if ( parser->root.error ) { @@ -173,7 +207,9 @@ goto Exit; } - if ( cur[0] == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 ) + if ( cur[0] == 'S' && + cur < limit - STARTDATA_LEN && + ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) { if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) { @@ -191,7 +227,8 @@ goto Exit; } - else if ( cur[1] == 's' && ft_strncmp( (char*)cur, "/sfnts", 6 ) == 0 ) + else if ( cur[1] == 's' && + ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 ) { FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); error = FT_THROW( Unknown_File_Format ); @@ -216,6 +253,12 @@ } +#undef STARTDATA +#undef STARTDATA_LEN +#undef SFNTS +#undef SFNTS_LEN + + FT_LOCAL_DEF( void ) cid_parser_done( CID_Parser* parser ) {