From b553fcb514a5e7131d34a117bf2d01e034ab7a08 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Tue, 28 Feb 2017 15:11:21 +0100 Subject: [PATCH] [sfnt] Further generalize `sfnt_get_ps_name'; report invalid data. * src/sfnt/sfdriver.c (sfnt_ps_map): New array. (sfnt_is_postscript): New function. (char_type_func): New typedef. (get_win_string, get_apple_string): Add argument to specify character checking function. Add argument whether argument checking failures should be reported. Update callers. (search_name_id): Fix return value. --- ChangeLog | 13 +++++ src/sfnt/sfdriver.c | 126 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 117 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c8101535..7076a6e2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2017-02-23 Werner Lemberg + + [sfnt] Further generalize `sfnt_get_ps_name'; report invalid data. + + * src/sfnt/sfdriver.c (sfnt_ps_map): New array. + (sfnt_is_postscript): New function. + (char_type_func): New typedef. + (get_win_string, get_apple_string): Add argument to specify + character checking function. + Add argument whether argument checking failures should be reported. + Update callers. + (search_name_id): Fix return value. + 2017-02-23 Werner Lemberg [sfnt] Split off another bit of `sfnt_get_ps_name'. diff --git a/src/sfnt/sfdriver.c b/src/sfnt/sfdriver.c index 5c70de989..274ef805d 100644 --- a/src/sfnt/sfdriver.c +++ b/src/sfnt/sfdriver.c @@ -220,6 +220,39 @@ * */ + /* an array representing allowed ASCII characters in a PS string */ + static const unsigned char sfnt_ps_map[16] = + { + /* 4 0 C 8 */ + 0x00, 0x00, /* 0x00: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0x00, 0x00, /* 0x10: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0xDE, 0x7C, /* 0x20: 1 1 0 1 1 1 1 0 0 1 1 1 1 1 0 0 */ + 0xFF, 0xAF, /* 0x30: 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 */ + 0xFF, 0xFF, /* 0x40: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0xD7, /* 0x50: 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 */ + 0xFF, 0xFF, /* 0x60: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0x57 /* 0x70: 1 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 */ + }; + + + static int + sfnt_is_postscript( int c ) + { + unsigned int cc; + + + if ( c < 0 || c >= 0x80 ) + return 0; + + cc = (unsigned int)c; + + return sfnt_ps_map[cc >> 3] & ( 1 << ( cc & 0x07 ) ); + } + + + typedef int (*char_type_func)( int c ); + + /* handling of PID/EID 3/0 and 3/1 is the same */ #define IS_WIN( n ) ( (n)->platformID == 3 && \ ( (n)->encodingID == 1 || (n)->encodingID == 0 ) && \ @@ -230,9 +263,11 @@ (n)->languageID == 0 ) static const char* - get_win_string( FT_Memory memory, - FT_Stream stream, - TT_Name entry ) + get_win_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) { FT_Error error = FT_Err_Ok; @@ -263,8 +298,22 @@ for ( len = entry->stringLength / 2; len > 0; len--, p += 2 ) { - if ( p[0] == 0 && p[1] >= 32 ) - *r++ = p[1]; + if ( p[0] == 0 ) + { + if ( char_type( p[1] ) ) + *r++ = p[1]; + else + { + if ( report_invalid_characters ) + { + FT_TRACE0(( "get_win_string:" + " Character `%c' (0x%X) invalid in PS name string\n", + p[1], p[1] )); + /* it's not the job of FreeType to correct PS names... */ + *r++ = p[1]; + } + } + } } *r = '\0'; @@ -275,13 +324,18 @@ static const char* - get_apple_string( FT_Memory memory, - FT_Stream stream, - TT_Name entry ) + get_apple_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) { FT_Error error = FT_Err_Ok; const char* result; + FT_String* r; + FT_Char* p; + FT_UInt len; FT_UNUSED( error ); @@ -289,8 +343,8 @@ if ( FT_ALLOC( result, entry->stringLength + 1 ) ) return NULL; - if ( FT_STREAM_SEEK( entry->stringOffset ) || - FT_STREAM_READ( result, entry->stringLength ) ) + if ( FT_STREAM_SEEK( entry->stringOffset ) || + FT_FRAME_ENTER( entry->stringLength ) ) { FT_FREE( result ); entry->stringOffset = 0; @@ -300,7 +354,28 @@ return NULL; } - ((char*)result)[entry->stringLength] = '\0'; + r = (FT_String*)result; + p = (FT_Char*)stream->cursor; + + for ( len = entry->stringLength; len > 0; len--, p++ ) + { + if ( char_type( *p ) ) + *r++ = *p; + else + { + if ( report_invalid_characters ) + { + FT_TRACE0(( "get_apple_string:" + " Character `%c' (0x%X) invalid in PS name string\n", + *p, *p )); + /* it's not the job of FreeType to correct PS names... */ + *r++ = *p; + } + } + } + *r = '\0'; + + FT_FRAME_EXIT(); return result; } @@ -333,14 +408,14 @@ } } - return *win || *apple; + return ( *win >= 0 ) || ( *apple >= 0 ); } static const char* sfnt_get_ps_name( TT_Face face ) { - FT_Int found_win, found_apple; + FT_Int found, win, apple; const char* result = NULL; @@ -349,17 +424,24 @@ /* scan the name table to see whether we have a Postscript name here, */ /* either in Macintosh or Windows platform encodings */ - search_name_id( face, 6, &found_win, &found_apple ); + found = search_name_id( face, 6, &win, &apple ); - /* prefer Windows entries over Apple */ - if ( found_win != -1 ) - result = get_win_string( face->root.memory, - face->name_table.stream, - face->name_table.names + found_win ); - else if ( found_apple != -1 ) - result = get_apple_string( face->root.memory, + if ( found ) + { + /* prefer Windows entries over Apple */ + if ( win != -1 ) + result = get_win_string( face->root.memory, face->name_table.stream, - face->name_table.names + found_apple ); + face->name_table.names + win, + sfnt_is_postscript, + 1 ); + else + result = get_apple_string( face->root.memory, + face->name_table.stream, + face->name_table.names + apple, + sfnt_is_postscript, + 1 ); + } face->postscript_name = result;