From fc7177d2e154150feed52d3fe82316953825dfa2 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Tue, 7 Oct 2003 05:49:41 +0000 Subject: [PATCH] Heavy modification of the PS parser to handle comments and strings correctly. This doesn't slow down the loading of PS fonts significantly since charstrings aren't affected. * include/freetype/config/ftstdlib.h (ft_xdigit): Renamed to... (ft_isxdigit): This. Updated all callers. (ft_isdigit): New alias to `isdigit'. * include/freetype/internal/psaux.h (PS_Parser_FuncsRec): Renamed `skip_alpha' to `skip_PS_token'. Add parameter to `to_bytes' and change some argument types. * src/psaux/psauxmod.c (ps_parser_funcs): Updated. * src/psaux/psobjs.c (ft_char_table): New array to map character codes (ASCII and EBCDIC) of digits to numbers. (OP): New auxiliary macro holding either `>=' or `<' depending on the character encoding. (skip_comment): New function. (skip_spaces): Use it. (skip_alpha): Removed. (skip_literal_string, skip_string): New functions. (ps_parser_skip_PS_token): New function. This is a better replacement of... (ps_parser_skip_alpha): Removed. (ps_parser_to_token, ps+parser_to_token_array): Updated. (T1Radix): Rewritten, using `ft_char_table'. (t1_toint): Renamed to... (ps_toint): This. Update all callers. Use `ft_char_table'. (ps_tobytes): Add parameter to handle delimiters and change some argument types. Use `ft_char_table'. (t1_tofixed): Renamed to... (ps_tofixed): This. Update all callers. Use `ft_char_table'. (t1_tocoordarray): Renamed and updated to... (ps_tocoordarray): This. Update all callers. (t1_tofixedarray): Renamed and updated to... (ps_tofixedarray): This. Update all callers. (t1_tobool): Renamed to... (ps_tobool): This. Update all callers. (ps_parser_load_field): Updated. (ps_parser_load_field_table): Use `T1_MAX_TABLE_ELEMENTS' everywhere. (ps_parser_to_int, ps_parser_to_fixed, ps_parser_to_coord_array, ps_parser_to_fixed_array): Skip spaces. Updated. (ps_parser_to_bytes): Add parameter to handle delimiters and change some argument types. Updated. * src/psaux/psobjs.h: Updated. * src/cid/cidload.c (cid_parse_dict): Updated. * src/cid/cidparse.c (cid_parser_new): Check whether the `StartData' token was really found. * src/cid/cidparse.h (cid_parser_skip_alpha): Updated and renamed to... (cid_parser_skip_PS_token): This. * src/type1/t1parse.h (T1_ParserRec): Use `FT_Bool' for boolean fields. (T1_Skip_Alpha): Replaced with... (T1_Skip_PS_Token): This new macro. * src/type1/t1parse.c (hexa_value): Removed. (T1_Get_Private_Dict): Use `ft_isxdigit' and `psaux->ps_parser_funcs_to_bytes' for handling ASCII hexadecimal encoding. After decrypting, replace the four random bytes at the beginning with whitespace. * src/type1/t1load.c (t1_allocate_blend): Use proper error values. (parser_blend_design_positions, parse_blend_design_map, parse_weight_vector): Updated. (is_space): Handle `\f' also. (is_name_char): Removed. (read_binary_data): Updated. (parse_encoding): Use `ft_isdigit'. Updated. (parse_subrs): Updated. (TABLE_EXTEND): New macro. (parse_charstrings): Updated. Provide a workaround for buggy fonts which have more entries in the /CharStrings dictionary then expected; the function now adds some slots and skips entries which still exceed the new limit. (parse_dict): Updated. Terminate on the token `closefile'. * src/type42/t42parse.c (T1_Skip_Alpha): Replaced with... (T1_Skip_PS_Token): This new macro. Updated all callers. (t42_parse_encoding): Use `ft_isdigit'. * src/base/ftmm.c (ft_face_get_mm_service): Return FT_Err_OK if success. --- ChangeLog | 94 ++++ include/freetype/config/ftstdlib.h | 11 +- include/freetype/ftoutln.h | 39 +- include/freetype/internal/psaux.h | 8 +- src/base/ftmm.c | 3 + src/base/ftpfr.c | 1 + src/cid/cidload.c | 63 ++- src/cid/cidparse.c | 47 +- src/cid/cidparse.h | 8 +- src/psaux/psauxmod.c | 2 +- src/psaux/psobjs.c | 736 ++++++++++++++++++++--------- src/psaux/psobjs.h | 7 +- src/type1/t1load.c | 537 +++++++++++---------- src/type1/t1parse.c | 91 ++-- src/type1/t1parse.h | 12 +- src/type42/t42parse.c | 12 +- 16 files changed, 1027 insertions(+), 644 deletions(-) diff --git a/ChangeLog b/ChangeLog index 97c71b75f..6983ffe5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,97 @@ +2003-10-06 Werner Lemberg + + Heavy modification of the PS parser to handle comments and strings + correctly. This doesn't slow down the loading of PS fonts + significantly since charstrings aren't affected. + + * include/freetype/config/ftstdlib.h (ft_xdigit): Renamed to... + (ft_isxdigit): This. Updated all callers. + (ft_isdigit): New alias to `isdigit'. + + * include/freetype/internal/psaux.h (PS_Parser_FuncsRec): Renamed + `skip_alpha' to `skip_PS_token'. + Add parameter to `to_bytes' and change some argument types. + + * src/psaux/psauxmod.c (ps_parser_funcs): Updated. + * src/psaux/psobjs.c (ft_char_table): New array to map character + codes (ASCII and EBCDIC) of digits to numbers. + (OP): New auxiliary macro holding either `>=' or `<' depending on + the character encoding. + (skip_comment): New function. + (skip_spaces): Use it. + (skip_alpha): Removed. + (skip_literal_string, skip_string): New functions. + (ps_parser_skip_PS_token): New function. This is a better + replacement of... + (ps_parser_skip_alpha): Removed. + (ps_parser_to_token, ps+parser_to_token_array): Updated. + (T1Radix): Rewritten, using `ft_char_table'. + (t1_toint): Renamed to... + (ps_toint): This. Update all callers. + Use `ft_char_table'. + (ps_tobytes): Add parameter to handle delimiters and change some + argument types. + Use `ft_char_table'. + (t1_tofixed): Renamed to... + (ps_tofixed): This. Update all callers. + Use `ft_char_table'. + (t1_tocoordarray): Renamed and updated to... + (ps_tocoordarray): This. Update all callers. + (t1_tofixedarray): Renamed and updated to... + (ps_tofixedarray): This. Update all callers. + (t1_tobool): Renamed to... + (ps_tobool): This. Update all callers. + (ps_parser_load_field): Updated. + (ps_parser_load_field_table): Use `T1_MAX_TABLE_ELEMENTS' + everywhere. + (ps_parser_to_int, ps_parser_to_fixed, ps_parser_to_coord_array, + ps_parser_to_fixed_array): Skip spaces. Updated. + (ps_parser_to_bytes): Add parameter to handle delimiters and change + some argument types. Updated. + * src/psaux/psobjs.h: Updated. + + * src/cid/cidload.c (cid_parse_dict): Updated. + * src/cid/cidparse.c (cid_parser_new): Check whether the `StartData' + token was really found. + * src/cid/cidparse.h (cid_parser_skip_alpha): Updated and renamed + to... + (cid_parser_skip_PS_token): This. + + * src/type1/t1parse.h (T1_ParserRec): Use `FT_Bool' for boolean + fields. + (T1_Skip_Alpha): Replaced with... + (T1_Skip_PS_Token): This new macro. + * src/type1/t1parse.c (hexa_value): Removed. + (T1_Get_Private_Dict): Use `ft_isxdigit' and + `psaux->ps_parser_funcs_to_bytes' for handling ASCII hexadecimal + encoding. + After decrypting, replace the four random bytes at the beginning + with whitespace. + * src/type1/t1load.c (t1_allocate_blend): Use proper error values. + (parser_blend_design_positions, parse_blend_design_map, + parse_weight_vector): Updated. + (is_space): Handle `\f' also. + (is_name_char): Removed. + (read_binary_data): Updated. + (parse_encoding): Use `ft_isdigit'. + Updated. + (parse_subrs): Updated. + (TABLE_EXTEND): New macro. + (parse_charstrings): Updated. + Provide a workaround for buggy fonts which have more entries in the + /CharStrings dictionary then expected; the function now adds some + slots and skips entries which still exceed the new limit. + (parse_dict): Updated. + Terminate on the token `closefile'. + + * src/type42/t42parse.c (T1_Skip_Alpha): Replaced with... + (T1_Skip_PS_Token): This new macro. Updated all callers. + (t42_parse_encoding): Use `ft_isdigit'. + + + * src/base/ftmm.c (ft_face_get_mm_service): Return FT_Err_OK if + success. + 2003-10-05 Werner Lemberg * include/freetype/ftmodule.h: Renamed to... diff --git a/include/freetype/config/ftstdlib.h b/include/freetype/config/ftstdlib.h index 7868fd402..f160ad27f 100644 --- a/include/freetype/config/ftstdlib.h +++ b/include/freetype/config/ftstdlib.h @@ -5,7 +5,7 @@ /* ANSI-specific library and header configuration file (specification */ /* only). */ /* */ -/* Copyright 2002 by */ +/* Copyright 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -73,10 +73,11 @@ #include -#define ft_isalnum isalnum -#define ft_isupper isupper -#define ft_islower islower -#define ft_xdigit isxdigit +#define ft_isalnum isalnum +#define ft_isupper isupper +#define ft_islower islower +#define ft_isdigit isdigit +#define ft_isxdigit isxdigit #include diff --git a/include/freetype/ftoutln.h b/include/freetype/ftoutln.h index daebae835..8c6a689df 100644 --- a/include/freetype/ftoutln.h +++ b/include/freetype/ftoutln.h @@ -5,7 +5,7 @@ /* Support for the FT_Outline type used to store glyph shapes of */ /* most scalable font formats (specification). */ /* */ -/* Copyright 1996-2001, 2002 by */ +/* Copyright 1996-2001, 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -391,32 +391,33 @@ FT_BEGIN_HEADER /************************************************************************** * - * @enum: FT_Orientation + * @enum: + * FT_Orientation * * @description: - * a list of values used to describe an outline's contour orientation + * A list of values used to describe an outline's contour orientation. * - * The TrueType and Postscript specifications used different conventions - * to determine wether outline contours should be filled or unfilled. + * The TrueType and Postscript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. * * @values: * FT_ORIENTATION_TRUETYPE :: - * according to the TrueType specification, clockwise contours must - * be filled, and counter-clockwise ones must be unfilled + * According to the TrueType specification, clockwise contours must + * be filled, and counter-clockwise ones must be unfilled. * * FT_ORIENTATION_POSTSCRIPT :: - * according to the Postscript specification, counter-clockwise contours - * must be filled, and clockwise ones must be unfilled + * According to the Postscript specification, counter-clockwise contours + * must be filled, and clockwise ones must be unfilled. * * FT_ORIENTATION_FILL_RIGHT :: - * this is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to * remember that in TrueType, everything that is to the right of * the drawing direction of a contour must be filled. * * FT_ORIENTATION_FILL_LEFT :: - * this is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to * remember that in Postscript, everything that is to the left of - * the drawing direction of a contour must be filled + * the drawing direction of a contour must be filled. */ typedef enum { @@ -430,22 +431,24 @@ FT_BEGIN_HEADER /************************************************************************** * - * @function: FT_Outline_Get_Orientation + * @function: + * FT_Outline_Get_Orientation * * @description: - * this function analyzes a glyph outline and tries to compute its - * fill orientation (see @FT_Orientation). This is done by computing + * This function analyzes a glyph outline and tries to compute its + * fill orientation (see @FT_Orientation). This is done by computing * the direction of each global horizontal and/or vertical extrema * within the outline. * - * note that this will return @FT_ORIENTATION_TRUETYPE for empty + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty * outlines. * * @input: - * outline :: handle to source outline + * outline :: + * A handle to the source outline. * * @return: - * orientation + * The orientation. * */ FT_EXPORT( FT_Orientation ) diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h index 48bda925a..bc36da7af 100644 --- a/include/freetype/internal/psaux.h +++ b/include/freetype/internal/psaux.h @@ -330,18 +330,20 @@ FT_BEGIN_HEADER void (*skip_spaces)( PS_Parser parser ); void - (*skip_alpha)( PS_Parser parser ); + (*skip_PS_token)( PS_Parser parser ); FT_Long (*to_int)( PS_Parser parser ); FT_Fixed (*to_fixed)( PS_Parser parser, FT_Int power_ten ); + FT_Error (*to_bytes)( PS_Parser parser, FT_Byte* bytes, - FT_Int max_bytes, - FT_Int* pnum_bytes ); + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); FT_Int (*to_coord_array)( PS_Parser parser, diff --git a/src/base/ftmm.c b/src/base/ftmm.c index 039a85094..0bb281309 100644 --- a/src/base/ftmm.c +++ b/src/base/ftmm.c @@ -51,6 +51,9 @@ FT_FACE_LOOKUP_SERVICE( face, *aservice, MULTI_MASTERS ); + + if ( aservice ) + error = FT_Err_Ok; } return error; diff --git a/src/base/ftpfr.c b/src/base/ftpfr.c index b1cd77372..80a657c66 100644 --- a/src/base/ftpfr.c +++ b/src/base/ftpfr.c @@ -26,6 +26,7 @@ { FT_Service_PfrMetrics service; + FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS ); return service; diff --git a/src/cid/cidload.c b/src/cid/cidload.c index 32c4a0d8d..db302b279 100644 --- a/src/cid/cidload.c +++ b/src/cid/cidload.c @@ -39,7 +39,7 @@ /* read a single offset */ FT_LOCAL_DEF( FT_Long ) - cid_get_offset( FT_Byte** start, + cid_get_offset( FT_Byte* *start, FT_Byte offsize ) { FT_Long result; @@ -164,9 +164,9 @@ temp_scale = ABS( temp[3] ); - /* Set Units per EM based on FontMatrix values. We set the value to */ + /* Set units per EM based on FontMatrix values. We set the value to */ /* `1000/temp_scale', because temp_scale was already multiplied by */ - /* 1000 (in t1_tofixed(), from psobjs.c). */ + /* 1000 (in `t1_tofixed', from psobjs.c). */ root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L, FT_DivFix( temp_scale, 1000 ) ) ); @@ -258,38 +258,57 @@ parser->root.cursor = base; parser->root.limit = base + size; - parser->root.error = 0; + parser->root.error = CID_Err_Ok; { FT_Byte* cur = base; FT_Byte* limit = cur + size; - for ( ; cur < limit; cur++ ) + for (;;) { + FT_Byte* newlimit; + + + parser->root.cursor = cur; + cid_parser_skip_spaces( parser ); + + if ( parser->root.cursor >= limit ) + newlimit = limit - 1 - 17; + else + newlimit = parser->root.cursor - 17; + /* look for `%ADOBeginFontDict' */ - if ( *cur == '%' && cur + 20 < limit && - ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + for ( ; cur < newlimit; cur++ ) { - cur += 17; - - /* if /FDArray was found, then cid->num_dicts is > 0, and */ - /* we can start increasing parser->num_dict */ - if ( face->cid.num_dicts > 0 ) - parser->num_dict++; + if ( *cur == '%' && + ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + parser->num_dict++; + } } + + cur = parser->root.cursor; + /* no error can occur in cid_parser_skip_spaces */ + if ( cur >= limit ) + break; + + cid_parser_skip_PS_token( parser ); + if ( parser->root.cursor >= limit || parser->root.error ) + break; + /* look for immediates */ - else if ( *cur == '/' && cur + 2 < limit ) + if ( *cur == '/' && cur + 2 < limit ) { FT_PtrDist len; cur++; - - parser->root.cursor = cur; - cid_parser_skip_alpha( parser ); - len = parser->root.cursor - cur; + if ( len > 0 && len < 22 ) { /* now compare the immediate name to the keyword table */ @@ -303,10 +322,7 @@ name = (FT_Byte*)keyword->ident; if ( !name ) - { - cid_parser_skip_alpha( parser ); break; - } if ( cur[0] == name[0] && len == ft_strlen( (const char*)name ) ) @@ -321,14 +337,11 @@ if ( n >= len ) { /* we found it - run the parsing callback */ - cid_parser_skip_spaces( parser ); parser->root.error = cid_load_keyword( face, loader, keyword ); if ( parser->root.error ) return parser->root.error; - - cur = parser->root.cursor; break; } } @@ -336,6 +349,8 @@ } } } + + cur = parser->root.cursor; } } return parser->root.error; diff --git a/src/cid/cidparse.c b/src/cid/cidparse.c index 397a66ff8..57037298a 100644 --- a/src/cid/cidparse.c +++ b/src/cid/cidparse.c @@ -4,7 +4,7 @@ /* */ /* CID-keyed Type1 parser (body). */ /* */ -/* Copyright 1996-2001, 2002 by */ +/* Copyright 1996-2001, 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -58,6 +58,7 @@ FT_ULong base_offset, offset, ps_len; FT_Byte buffer[256 + 10]; FT_Int buff_len; + FT_Byte *cur, *limit; FT_MEM_ZERO( parser, sizeof ( *parser ) ); @@ -67,7 +68,7 @@ base_offset = FT_STREAM_POS(); - /* first of all, check the font format in the header */ + /* first of all, check the font format in the header */ if ( FT_FRAME_ENTER( 31 ) ) goto Exit; @@ -82,15 +83,17 @@ if ( error ) goto Exit; - /* now, read the rest of the file, until we find a `StartData' */ + Again: + /* now, read the rest of the file until we find a `StartData' */ buff_len = 256; for (;;) { - FT_Byte *p, *limit = buffer + 256; + FT_Byte* p; FT_ULong top_position; /* fill input buffer */ + limit = buffer + 256; buff_len -= 256; if ( buff_len > 0 ) FT_MEM_MOVE( buffer, limit, buff_len ); @@ -101,7 +104,7 @@ goto Exit; top_position = FT_STREAM_POS() - buff_len; - buff_len = 256 + 10; + buff_len = 256 + 10; /* look for `StartData' */ for ( p = buffer; p < limit; p++ ) @@ -116,12 +119,12 @@ } Found: - /* we have found the start of the binary data. We will now */ - /* rewind and extract the frame of corresponding to the Postscript */ - /* section */ + /* we have found the start of the binary data. We will now */ + /* rewind and extract the frame corresponding to the PostScript */ + /* section */ ps_len = offset - base_offset; - if ( FT_STREAM_SEEK( base_offset ) || + if ( FT_STREAM_SEEK( base_offset ) || FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) goto Exit; @@ -132,6 +135,32 @@ parser->root.limit = parser->root.cursor + ps_len; parser->num_dict = -1; + /* finally we check whether `StartData' was real -- it could be */ + /* in a comment or string */ + + limit = parser->root.limit; + cur = parser->root.cursor; + + while ( cur < limit ) + { + if ( *cur == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 ) + { + limit = parser->root.limit; + cur = parser->root.cursor; + goto Exit; + } + + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + cur = parser->root.cursor; + } + + /* we haven't found the correct `StartData'; go back and continue */ + /* searching */ + FT_FRAME_RELEASE( parser->postscript ); + if ( !FT_STREAM_SEEK( offset ) ) + goto Again; + Exit: return error; } diff --git a/src/cid/cidparse.h b/src/cid/cidparse.h index 1b3e0b967..61148034d 100644 --- a/src/cid/cidparse.h +++ b/src/cid/cidparse.h @@ -4,7 +4,7 @@ /* */ /* CID-keyed Type1 parser (specification). */ /* */ -/* Copyright 1996-2001, 2002 by */ +/* Copyright 1996-2001, 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -87,8 +87,10 @@ FT_BEGIN_HEADER /* */ /*************************************************************************/ -#define cid_parser_skip_spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) -#define cid_parser_skip_alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root ) +#define cid_parser_skip_spaces( p ) \ + (p)->root.funcs.skip_spaces( &(p)->root ) +#define cid_parser_skip_PS_token( p ) \ + (p)->root.funcs.skip_PS_token( &(p)->root ) #define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root ) #define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) diff --git a/src/psaux/psauxmod.c b/src/psaux/psauxmod.c index d6024178b..756ec1c56 100644 --- a/src/psaux/psauxmod.c +++ b/src/psaux/psauxmod.c @@ -39,7 +39,7 @@ ps_parser_init, ps_parser_done, ps_parser_skip_spaces, - ps_parser_skip_alpha, + ps_parser_skip_PS_token, ps_parser_to_int, ps_parser_to_fixed, ps_parser_to_bytes, diff --git a/src/psaux/psobjs.c b/src/psaux/psobjs.c index 992800f6a..adc9772c6 100644 --- a/src/psaux/psobjs.c +++ b/src/psaux/psobjs.c @@ -267,31 +267,76 @@ /*************************************************************************/ /* In the PostScript Language Reference Manual (PLRM) the following */ - /* characters are called `white-space characters'. */ + /* characters are called `whitespace characters'. */ #define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' ) #define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' || (c) == '\f' ) #define IS_T1_NULLSPACE( c ) ( (c) == '\0' ) - /* According to the PLRM all white-space characters are equivalent, */ - /* except in comments and strings. */ + /* According to the PLRM all whitespace characters are equivalent, */ + /* except in comments and strings. */ #define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || \ IS_T1_LINESPACE( c ) || \ IS_T1_NULLSPACE( c ) ) + /* The following array is used by various functions to quickly convert */ + /* digits (both decimal and non-decimal) into numbers. */ + +#if 'A' == 65 + /* ASCII */ + + char ft_char_table[128] = + { + /* 0x00 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + }; + + /* no character >= 0x80 can represent a valid number */ +#define OP >= + +#endif /* 'A' == 65 */ + +#if 'A' == 193 + /* EBCDIC */ + + char ft_char_table[128] = + { + /* 0x80 */ + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + } + + /* no character < 0x80 can represent a valid number */ +#define OP < + +#endif /* 'A' == 193 */ + + + /* first character must be already part of the comment */ + static void - skip_spaces( FT_Byte** acur, - FT_Byte* limit ) + skip_comment( FT_Byte* *acur, + FT_Byte* limit ) { - FT_Byte* cur = *acur; + FT_Byte* cur = *acur; while ( cur < limit ) { - FT_Byte c = *cur; - - - if ( !IS_T1_SPACE( c ) ) + if ( IS_T1_LINESPACE( *cur ) ) break; cur++; } @@ -301,19 +346,54 @@ static void - skip_alpha( FT_Byte** acur, - FT_Byte* limit ) + skip_spaces( FT_Byte* *acur, + FT_Byte* limit ) { FT_Byte* cur = *acur; while ( cur < limit ) { - FT_Byte c = *cur; + if ( !IS_T1_SPACE( *cur ) ) + { + if ( *cur == '%' ) + /* According to the PLRM, a comment is equal to a space. */ + skip_comment( &cur, limit ); + else + break; + } + cur++; + } + *acur = cur; + } - if ( IS_T1_SPACE( c ) ) - break; + + /* first character must be `(' */ + + static void + skip_literal_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Int embed = 0; + + + while ( cur < limit ) + { + if ( *cur == '\\' ) + cur++; + else if ( *cur == '(' ) + embed++; + else if ( *cur == ')' ) + { + embed--; + if ( embed == 0 ) + { + cur++; + break; + } + } cur++; } @@ -321,20 +401,145 @@ } + /* first character must be `<' */ + + static void + skip_string( PS_Parser parser ) + { + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + + cur++; + + while ( cur < limit ) + { + int d; + + + /* All whitespace characters are ignored. */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; + + if ( *cur OP 0x80 ) + break; + + d = ft_char_table[*cur & 0x7F]; + if ( d < 0 || d >= 16 ) + break; + } + + if ( cur < limit && *cur != '>' ) + parser->error = PSaux_Err_Invalid_File_Format; + else + cur++; + + parser->cursor = cur; + } + + + /***********************************************************************/ + /* */ + /* All exported parsing routines handle leading whitespace and stop at */ + /* the first character which isn't part of the just handled token. */ + /* */ + /***********************************************************************/ + + FT_LOCAL_DEF( void ) - ps_parser_skip_spaces( PS_Parser parser ) + ps_parser_skip_PS_token( PS_Parser parser ) { - skip_spaces( &parser->cursor, parser->limit ); + /* Note: PostScript allows any non-delimiting, non-whitespace */ + /* character in a name (PS Ref Manual, 3rd ed, p31). */ + /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ + + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + + skip_spaces( &cur, limit ); /* this also skips comments */ + if ( cur >= limit ) + goto Exit; + + /* self-delimiting, single-character tokens */ + if ( *cur == '[' || *cur == ']' || + *cur == '{' || *cur == '}' ) + { + cur++; + goto Exit; + } + + if ( *cur == '(' ) /* (...) */ + { + skip_literal_string( &cur, limit ); + goto Exit; + } + + if ( *cur == '<' ) /* <...> */ + { + if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ + { + cur++; + cur++; + goto Exit; + } + parser->cursor = cur; + skip_string( parser ); + return; + } + + if ( *cur == '>' ) + { + cur++; + if ( cur >= limit || *cur != '>' ) /* >> */ + { + parser->error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + cur++; + goto Exit; + } + + if ( *cur == '/' ) + cur++; + + /* anything else */ + while ( cur < limit ) + { + if ( IS_T1_SPACE( *cur ) || + *cur == '(' || + *cur == '/' || + *cur == '%' || + *cur == '[' || *cur == ']' || + *cur == '{' || *cur == '}' || + *cur == '<' || *cur == '>' ) + break; + + if ( *cur == ')' ) + { + parser->error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + cur++; + } + + Exit: + parser->cursor = cur; } FT_LOCAL_DEF( void ) - ps_parser_skip_alpha( PS_Parser parser ) + ps_parser_skip_spaces( PS_Parser parser ) { - skip_alpha( &parser->cursor, parser->limit ); + skip_spaces( &parser->cursor, parser->limit ); } + /* `token' here means either something between balanced delimiters */ + /* or the next token; the delimiters are not removed. */ + FT_LOCAL_DEF( void ) ps_parser_to_token( PS_Parser parser, T1_Token token ) @@ -349,72 +554,87 @@ token->start = 0; token->limit = 0; - /* first of all, skip space */ + /* first of all, skip leading whitespace */ ps_parser_skip_spaces( parser ); cur = parser->cursor; limit = parser->limit; - if ( cur < limit ) + if ( cur >= limit ) + return; + + switch ( *cur ) { - switch ( *cur ) + /************* check for literal string *****************/ + case '(': + token->type = T1_TOKEN_TYPE_STRING; + token->start = cur; + skip_literal_string( &cur, limit ); + if ( cur < limit ) + token->limit = cur; + break; + + /************* check for programs/array *****************/ + case '{': + token->type = T1_TOKEN_TYPE_ARRAY; + ender = '}'; + goto Lookup_Ender; + + /************* check for table/array ********************/ + case '[': + token->type = T1_TOKEN_TYPE_ARRAY; + ender = ']'; + /* fall through */ + + Lookup_Ender: + embed = 1; + starter = *cur; + token->start = cur++; + + /* we need this to catch `[ ]' */ + parser->cursor = cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + while ( cur < limit && !parser->error ) { - /************* check for strings ***********************/ - case '(': - token->type = T1_TOKEN_TYPE_STRING; - ender = ')'; - goto Lookup_Ender; - - /************* check for programs/array ****************/ - case '{': - token->type = T1_TOKEN_TYPE_ARRAY; - ender = '}'; - goto Lookup_Ender; - - /************* check for table/array ******************/ - case '[': - token->type = T1_TOKEN_TYPE_ARRAY; - ender = ']'; - - Lookup_Ender: - embed = 1; - starter = *cur++; - token->start = cur; - while ( cur < limit ) + if ( *cur == starter ) + embed++; + else if ( *cur == ender ) { - if ( *cur == starter ) - embed++; - else if ( *cur == ender ) + embed--; + if ( embed <= 0 ) { - embed--; - if ( embed <= 0 ) - { - token->limit = cur++; - break; - } + token->limit = ++cur; + break; } - cur++; } - break; - /* **************** otherwise, it's any token **********/ - default: - token->start = cur++; - token->type = T1_TOKEN_TYPE_ANY; - while ( cur < limit && !IS_T1_SPACE( *cur ) ) - cur++; - - token->limit = cur; - } - - if ( !token->limit ) - { - token->start = 0; - token->type = T1_TOKEN_TYPE_NONE; + parser->cursor = cur; + ps_parser_skip_PS_token( parser ); + /* we need this to catch `[XXX ]' */ + ps_parser_skip_spaces ( parser ); + cur = parser->cursor; } + break; + + /* ************ otherwise, it is any token **************/ + default: + token->start = cur; + token->type = T1_TOKEN_TYPE_ANY; + ps_parser_skip_PS_token( parser ); + cur = parser->cursor; + if ( !parser->error ) + token->limit = cur; + } - parser->cursor = cur; + if ( !token->limit ) + { + token->start = 0; + token->type = T1_TOKEN_TYPE_NONE; } + + parser->cursor = cur; } @@ -429,7 +649,9 @@ *pnum_tokens = -1; + /* this also handles leading whitespace */ ps_parser_to_token( parser, &master ); + if ( master.type == T1_TOKEN_TYPE_ARRAY ) { FT_Byte* old_cursor = parser->cursor; @@ -438,8 +660,9 @@ T1_Token limit = cur + max_tokens; - parser->cursor = master.start; - parser->limit = master.limit; + /* don't include outermost delimiters */ + parser->cursor = master.start + 1; + parser->limit = master.limit - 1; while ( parser->cursor < parser->limit ) { @@ -464,150 +687,161 @@ } + /* first character must be already part of the number */ + static FT_Long T1Radix( FT_Long radixBase, - FT_Byte** cur, + FT_Byte* *acur, FT_Byte* limit ) { - FT_Long result = 0; - FT_Byte radixEndChar0 = - (FT_Byte)( radixBase > 10 ? '9' + 1 : '0' + radixBase ); - FT_Byte radixEndChar1 = - (FT_Byte)( 'A' + radixBase - 10 ); - FT_Byte radixEndChar2 = - (FT_Byte)( 'a' + radixBase - 10 ); + FT_Long result = 0; + FT_Byte* cur = *acur; - while( *cur < limit ) + if ( radixBase < 2 || radixBase > 36 ) + return 0; + + while ( cur < limit ) { - if ( (*cur)[0] >= '0' && (*cur)[0] < radixEndChar0 ) - result = result * radixBase + (*cur)[0] - '0'; + int d; - else if ( radixBase > 10 && - (*cur)[0] >= 'A' && (*cur)[0] < radixEndChar1 ) - result = result * radixBase + ( (*cur)[0] - 'A' + 10 ); - else if ( radixBase > 10 && - (*cur)[0] >= 'a' && (*cur)[0] < radixEndChar2 ) - result = result * radixBase + ( (*cur)[0] - 'a' + 10 ); + if ( *cur OP 0x80 ) + break; + + d = ft_char_table[*cur & 0x7F]; + if ( d < 0 || d >= radixBase ) + break; - else - return result; + result = result * radixBase + d; - (*cur)++; + cur++; } return result; } + /* first character must be already part of the number */ + static FT_Long - t1_toint( FT_Byte** cursor, + ps_toint( FT_Byte* *acur, FT_Byte* limit ) { FT_Long result = 0; - FT_Byte* cur = *cursor; - FT_Byte c = '\0', d; + FT_Byte* cur = *acur; + FT_Byte c; - for ( ; cur < limit; cur++ ) + if ( cur >= limit ) + goto Exit; + + c = *cur; + if ( c == '-' ) + cur++; + + while ( cur < limit ) { - c = *cur; - d = (FT_Byte)( c - '0' ); - if ( d < 10 ) - break; + int d; + - if ( c == '-' ) + if ( *cur == '#' ) { cur++; + result = T1Radix( result, &cur, limit ); break; } - } - if ( cur < limit ) - { - do - { - d = (FT_Byte)( cur[0] - '0' ); - if ( d >= 10 ) - { - if ( cur[0] == '#' ) - { - cur++; - result = T1Radix( result, &cur, limit ); - } - break; - } + if ( *cur OP 0x80 ) + break; - result = result * 10 + d; - cur++; + d = ft_char_table[*cur & 0x7F]; + if ( d < 0 || d >= 10 ) + break; + result = result * 10 + d; - } while ( cur < limit ); + cur++; + }; - if ( c == '-' ) - result = -result; - } + if ( c == '-' ) + result = -result; - *cursor = cur; + Exit: + *acur = cur; return result; } - /* <...>: hexadecimal string */ + /* first character must be `<' if `delimiters' is non-zero */ + static FT_Error - ps_tobytes( FT_Byte** cursor, + ps_tobytes( FT_Byte* *acur, FT_Byte* limit, - FT_Int max_bytes, + FT_Long max_bytes, FT_Byte* bytes, - FT_Int* pnum_bytes ) + FT_Long* pnum_bytes, + FT_Bool delimiters ) { FT_Error error = PSaux_Err_Ok; - FT_Byte* cur = *cursor; - FT_Int n = 0; - FT_Byte b; + FT_Byte* cur = *acur; + FT_Long n; - skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; - if ( *cur != '<' ) + if ( delimiters ) { - error = PSaux_Err_Invalid_File_Format; - goto Exit; + if ( *cur != '<' ) + { + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + cur++; } - cur++; + max_bytes = max_bytes * 2; - for ( ; cur < limit; n++ ) + for ( n = 0; cur < limit; n++, cur++ ) { - FT_Byte* cur2 = cur; + int d; - if ( n + 1 > max_bytes * 2 ) + if ( n >= max_bytes ) + /* buffer is full */ goto Exit; - /* All white-space charcters are ignored. */ + /* All whitespace characters are ignored. */ skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; - b = (FT_Byte) T1Radix( 16, &cur, cur + 1 ); + if ( *cur OP 0x80 ) + break; - if ( cur == cur2 ) + d = ft_char_table[*cur & 0x7F]; + if ( d < 0 || d >= 16 ) break; /* == != <0f> */ - bytes[n / 2] = (FT_Byte)( ( n % 2 ) ? bytes[n / 2] + b - : b * 16 ); + bytes[n / 2] = (FT_Byte)( ( n % 2 ) ? bytes[n / 2] + d + : d * 16 ); } - skip_spaces( &cur, limit ); - - if ( *cur != '>' ) + if ( delimiters ) { - error = PSaux_Err_Invalid_File_Format; - goto Exit; + if ( cur < limit && *cur != '>' ) + { + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + + cur++; } - *cursor = ++cur; + *acur = cur; Exit: *pnum_bytes = ( n + 1 ) / 2; @@ -616,22 +850,23 @@ } + /* first character must be already part of the number */ + static FT_Long - t1_tofixed( FT_Byte** cursor, + ps_tofixed( FT_Byte* *acur, FT_Byte* limit, FT_Long power_ten ) { - FT_Byte* cur = *cursor; + FT_Byte* cur = *acur; FT_Long num, divider, result; FT_Int sign = 0; - FT_Byte d; if ( cur >= limit ) return 0; /* first of all, check the sign */ - if ( *cur == '-' ) + if ( *cur == '-' && cur + 1 < limit ) { sign = 1; cur++; @@ -639,7 +874,7 @@ /* then, read the integer part, if any */ if ( *cur != '.' ) - result = t1_toint( &cur, limit ) << 16; + result = ps_toint( &cur, limit ) << 16; else result = 0; @@ -656,8 +891,14 @@ for (;;) { - d = (FT_Byte)( *cur - '0' ); - if ( d >= 10 ) + int d; + + + if ( *cur OP 0x80 ) + break; + + d = ft_char_table[*cur & 0x7F]; + if ( d < 0 || d >= 10 ) break; if ( divider < 10000000L ) @@ -676,7 +917,7 @@ if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) ) { cur++; - power_ten += t1_toint( &cur, limit ); + power_ten += ps_toint( &cur, limit ); } Exit: @@ -701,18 +942,20 @@ if ( sign ) result = -result; - *cursor = cur; + *acur = cur; return result; } + /* first character must be a delimiter or a part of a number */ + static FT_Int - t1_tocoordarray( FT_Byte** cursor, + ps_tocoordarray( FT_Byte* *acur, FT_Byte* limit, FT_Int max_coords, FT_Short* coords ) { - FT_Byte* cur = *cursor; + FT_Byte* cur = *acur; FT_Int count = 0; FT_Byte c, ender; @@ -720,8 +963,8 @@ if ( cur >= limit ) goto Exit; - /* check for the beginning of an array; if not, only one number will */ - /* be read */ + /* check for the beginning of an array; otherwise, only one number */ + /* will be read */ c = *cur; ender = 0; @@ -735,24 +978,23 @@ cur++; /* now, read the coordinates */ - for ( ; cur < limit; ) + while ( cur < limit ) { /* skip whitespace in front of data */ - for (;;) - { - c = *cur; - if ( c != ' ' && c != '\t' ) - break; + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; - cur++; - if ( cur >= limit ) - goto Exit; - } + if ( count >= max_coords ) + break; - if ( count >= max_coords || c == ender ) + if ( c == ender ) + { + cur++; break; + } - coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 ); + coords[count] = (FT_Short)( ps_tofixed( &cur, limit, 0 ) >> 16 ); count++; if ( !ender ) @@ -760,27 +1002,30 @@ } Exit: - *cursor = cur; + *acur = cur; return count; } + /* first character must be a delimiter or a part of a number */ + static FT_Int - t1_tofixedarray( FT_Byte** cursor, + ps_tofixedarray( FT_Byte* *acur, FT_Byte* limit, FT_Int max_values, FT_Fixed* values, FT_Int power_ten ) { - FT_Byte* cur = *cursor; + FT_Byte* cur = *acur; FT_Int count = 0; FT_Byte c, ender; - if ( cur >= limit ) goto Exit; + if ( cur >= limit ) + goto Exit; - /* check for the beginning of an array. If not, only one number will */ - /* be read */ + /* Check for the beginning of an array. Otherwise, only one number */ + /* will be read. */ c = *cur; ender = 0; @@ -794,24 +1039,23 @@ cur++; /* now, read the values */ - for ( ; cur < limit; ) + while ( cur < limit ) { /* skip whitespace in front of data */ - for (;;) - { - c = *cur; - if ( c != ' ' && c != '\t' ) - break; + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; - cur++; - if ( cur >= limit ) - goto Exit; - } + if ( count >= max_values ) + break; - if ( count >= max_values || c == ender ) + if ( c == ender ) + { + cur++; break; + } - values[count] = t1_tofixed( &cur, limit, power_ten ); + values[count] = ps_tofixed( &cur, limit, power_ten ); count++; if ( !ender ) @@ -819,7 +1063,7 @@ } Exit: - *cursor = cur; + *acur = cur; return count; } @@ -827,7 +1071,7 @@ #if 0 static FT_String* - t1_tostring( FT_Byte** cursor, + ps_tostring( FT_Byte** cursor, FT_Byte* limit, FT_Memory memory ) { @@ -887,40 +1131,41 @@ static int - t1_tobool( FT_Byte** cursor, + ps_tobool( FT_Byte* *acur, FT_Byte* limit ) { - FT_Byte* cur = *cursor; + FT_Byte* cur = *acur; FT_Bool result = 0; /* return 1 if we find `true', 0 otherwise */ if ( cur + 3 < limit && - cur[0] == 't' && - cur[1] == 'r' && - cur[2] == 'u' && - cur[3] == 'e' ) + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) { result = 1; cur += 5; } else if ( cur + 4 < limit && - cur[0] == 'f' && - cur[1] == 'a' && - cur[2] == 'l' && - cur[3] == 's' && - cur[4] == 'e' ) + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) { result = 0; cur += 6; } - *cursor = cur; + *acur = cur; return result; } - /* Load a simple field (i.e. non-table) into the current list of objects */ + /* load a simple field (i.e. non-table) into the current list of objects */ + FT_LOCAL_DEF( FT_Error ) ps_parser_load_field( PS_Parser parser, const T1_Field field, @@ -936,6 +1181,7 @@ FT_Error error; + /* this also skips leading whitespace */ ps_parser_to_token( parser, &token ); if ( !token.type ) goto Fail; @@ -945,7 +1191,7 @@ cur = token.start; limit = token.limit; - /* we must detect arrays */ + /* we must detect arrays in /FontBBox */ if ( field->type == T1_FIELD_TYPE_BBOX ) { T1_TokenRec token2; @@ -953,8 +1199,9 @@ FT_Byte* old_limit = parser->limit; - parser->cursor = token.start; - parser->limit = token.limit; + /* don't include delimiters */ + parser->cursor = token.start + 1; + parser->limit = token.limit - 1; ps_parser_to_token( parser, &token2 ); parser->cursor = old_cur; @@ -966,12 +1213,16 @@ else if ( token.type == T1_TOKEN_TYPE_ARRAY ) { FieldArray: - /* if this is an array, and we have no blend, an error occurs */ + /* if this is an array and we have no blend, an error occurs */ if ( max_objects == 0 ) goto Fail; count = max_objects; - idx = 1; + idx = 1; + + /* don't include delimiters */ + cur++; + limit--; } for ( ; count > 0; count--, idx++ ) @@ -981,23 +1232,25 @@ FT_String* string; + skip_spaces( &cur, limit ); + switch ( field->type ) { case T1_FIELD_TYPE_BOOL: - val = t1_tobool( &cur, limit ); + val = ps_tobool( &cur, limit ); goto Store_Integer; case T1_FIELD_TYPE_FIXED: - val = t1_tofixed( &cur, limit, 0 ); + val = ps_tofixed( &cur, limit, 0 ); goto Store_Integer; case T1_FIELD_TYPE_FIXED_1000: - val = t1_tofixed( &cur, limit, 3 ); + val = ps_tofixed( &cur, limit, 3 ); goto Store_Integer; case T1_FIELD_TYPE_INTEGER: - val = t1_toint( &cur, limit ); - goto Store_Integer; + val = ps_toint( &cur, limit ); + /* fall through */ Store_Integer: switch ( field->size ) @@ -1026,15 +1279,25 @@ FT_UInt len = (FT_UInt)( limit - cur ); - /* with synthetic fonts, it's possible to find a field twice */ + if ( cur >= limit ) + break; + + /* with synthetic fonts, it is possible to find a field twice */ if ( *(FT_String**)q ) break; if ( field->type == T1_FIELD_TYPE_KEY ) { + /* don't include leading `/' */ len--; cur++; } + else + { + /* don't include delimiting parentheses */ + cur++; + len -= 2; + } if ( FT_ALLOC( string, len + 1 ) ) goto Exit; @@ -1052,10 +1315,7 @@ FT_BBox* bbox = (FT_BBox*)q; - /* we need the '[' and ']' delimiters */ - token.start--; - token.limit++; - (void)t1_tofixedarray( &token.start, token.limit, 4, temp, 0 ); + (void)ps_tofixedarray( &token.start, token.limit, 4, temp, 0 ); bbox->xMin = FT_RoundFix( temp[0] ); bbox->yMin = FT_RoundFix( temp[1] ); @@ -1070,7 +1330,7 @@ } } -#if 0 /* obsolete - keep for reference */ +#if 0 /* obsolete -- keep for reference */ if ( pflags ) *pflags |= 1L << field->flag_bit; #else @@ -1113,7 +1373,8 @@ fieldrec.type = T1_FIELD_TYPE_FIXED; #endif - ps_parser_to_token_array( parser, elements, 32, &num_elements ); + ps_parser_to_token_array( parser, elements, + T1_MAX_TABLE_ELEMENTS, &num_elements ); if ( num_elements < 0 ) goto Fail; @@ -1159,21 +1420,25 @@ FT_LOCAL_DEF( FT_Long ) ps_parser_to_int( PS_Parser parser ) { - return t1_toint( &parser->cursor, parser->limit ); + ps_parser_skip_spaces( parser ); + return ps_toint( &parser->cursor, parser->limit ); } FT_LOCAL_DEF( FT_Error ) ps_parser_to_bytes( PS_Parser parser, FT_Byte* bytes, - FT_Int max_bytes, - FT_Int* pnum_bytes ) + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ) { + ps_parser_skip_spaces( parser ); return ps_tobytes( &parser->cursor, parser->limit, max_bytes, bytes, - pnum_bytes ); + pnum_bytes, + delimiters ); } @@ -1181,7 +1446,8 @@ ps_parser_to_fixed( PS_Parser parser, FT_Int power_ten ) { - return t1_tofixed( &parser->cursor, parser->limit, power_ten ); + ps_parser_skip_spaces( parser ); + return ps_tofixed( &parser->cursor, parser->limit, power_ten ); } @@ -1190,7 +1456,8 @@ FT_Int max_coords, FT_Short* coords ) { - return t1_tocoordarray( &parser->cursor, parser->limit, + ps_parser_skip_spaces( parser ); + return ps_tocoordarray( &parser->cursor, parser->limit, max_coords, coords ); } @@ -1201,7 +1468,8 @@ FT_Fixed* values, FT_Int power_ten ) { - return t1_tofixedarray( &parser->cursor, parser->limit, + ps_parser_skip_spaces( parser ); + return ps_tofixedarray( &parser->cursor, parser->limit, max_values, values, power_ten ); } @@ -1211,14 +1479,14 @@ FT_LOCAL_DEF( FT_String* ) T1_ToString( PS_Parser parser ) { - return t1_tostring( &parser->cursor, parser->limit, parser->memory ); + return ps_tostring( &parser->cursor, parser->limit, parser->memory ); } FT_LOCAL_DEF( FT_Bool ) T1_ToBool( PS_Parser parser ) { - return t1_tobool( &parser->cursor, parser->limit ); + return ps_tobool( &parser->cursor, parser->limit ); } #endif /* 0 */ @@ -1230,7 +1498,7 @@ FT_Byte* limit, FT_Memory memory ) { - parser->error = 0; + parser->error = PSaux_Err_Ok; parser->base = base; parser->limit = limit; parser->cursor = base; diff --git a/src/psaux/psobjs.h b/src/psaux/psobjs.h index 528efc3d5..c2cbf2c79 100644 --- a/src/psaux/psobjs.h +++ b/src/psaux/psobjs.h @@ -78,7 +78,7 @@ FT_BEGIN_HEADER ps_parser_skip_spaces( PS_Parser parser ); FT_LOCAL( void ) - ps_parser_skip_alpha( PS_Parser parser ); + ps_parser_skip_PS_token( PS_Parser parser ); FT_LOCAL( void ) ps_parser_to_token( PS_Parser parser, @@ -111,8 +111,9 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) ps_parser_to_bytes( PS_Parser parser, FT_Byte* bytes, - FT_Int max_bytes, - FT_Int* pnum_bytes ); + FT_Long max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); FT_LOCAL( FT_Fixed ) diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 6bc7b9285..0440e2189 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -41,11 +41,10 @@ /* */ /* All other common cases are handled very simply. The matching rules */ /* are defined in the file `t1tokens.h' through the use of several */ - /* macros calls PARSE_XXX. */ - /* */ - /* This file is included twice here; the first time to generate parsing */ - /* callback functions, the second to generate a table of keywords (with */ - /* pointers to the associated callback). */ + /* macros calls PARSE_XXX. This file is included twice here; the first */ + /* time to generate parsing callback functions, the second time to */ + /* generate a table of keywords (with pointers to the associated */ + /* callback functions). */ /* */ /* The function `parse_dict' simply scans *linearly* a given dictionary */ /* (either the top-level or private one) and calls the appropriate */ @@ -71,7 +70,6 @@ #include "t1errors.h" - /*************************************************************************/ /* */ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ @@ -100,7 +98,7 @@ { PS_Blend blend; FT_Memory memory = face->root.memory; - FT_Error error = 0; + FT_Error error = T1_Err_Ok; blend = face->blend; @@ -174,7 +172,7 @@ return error; Fail: - error = -1; + error = T1_Err_Invalid_File_Format; goto Exit; } @@ -205,8 +203,10 @@ axis->minimum = map->design_points[0]; axis->maximum = map->design_points[map->num_points - 1]; } - error = 0; + + error = T1_Err_Ok; } + return error; } @@ -253,6 +253,7 @@ error = T1_Err_Ok; } + return error; } @@ -289,7 +290,7 @@ FT_Fixed p_design = designs[p]; - /* exact match ? */ + /* exact match? */ if ( design == p_design ) { the_blend = blends[p]; @@ -305,7 +306,7 @@ before = p; } - /* now, interpolate if needed */ + /* now interpolate if necessary */ if ( before < 0 ) the_blend = blends[0]; @@ -386,9 +387,9 @@ parse_blend_axis_types( T1_Face face, T1_Loader loader ) { - T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ]; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; FT_Int n, num_axis; - FT_Error error = 0; + FT_Error error = T1_Err_Ok; PS_Blend blend; FT_Memory memory; @@ -448,16 +449,16 @@ parse_blend_design_positions( T1_Face face, T1_Loader loader ) { - T1_TokenRec design_tokens[ T1_MAX_MM_DESIGNS ]; + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; FT_Int num_designs; FT_Int num_axis; T1_Parser parser = &loader->parser; - FT_Error error = 0; + FT_Error error = T1_Err_Ok; PS_Blend blend; - /* get the array of design tokens - compute number of designs */ + /* get the array of design tokens -- compute number of designs */ T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs ); if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS ) { @@ -479,15 +480,15 @@ for ( n = 0; n < (FT_UInt)num_designs; n++ ) { - T1_TokenRec axis_tokens[ T1_MAX_MM_DESIGNS ]; + T1_TokenRec axis_tokens[T1_MAX_MM_DESIGNS]; T1_Token token; FT_Int axis, n_axis; /* read axis/coordinates tokens */ token = design_tokens + n; - parser->root.cursor = token->start - 1; - parser->root.limit = token->limit + 1; + parser->root.cursor = token->start; + parser->root.limit = token->limit; T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); if ( n == 0 ) @@ -505,7 +506,7 @@ goto Exit; } - /* now, read each axis token into the design position */ + /* now read each axis token into the design position */ for ( axis = 0; axis < n_axis; axis++ ) { T1_Token token2 = axis_tokens + axis; @@ -530,7 +531,7 @@ parse_blend_design_map( T1_Face face, T1_Loader loader ) { - FT_Error error = 0; + FT_Error error = T1_Err_Ok; T1_Parser parser = &loader->parser; PS_Blend blend; T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; @@ -548,6 +549,7 @@ error = T1_Err_Invalid_File_Format; goto Exit; } + old_cursor = parser->root.cursor; old_limit = parser->root.limit; @@ -556,29 +558,22 @@ goto Exit; blend = face->blend; - /* now, read each axis design map */ + /* now read each axis design map */ for ( n = 0; n < num_axis; n++ ) { PS_DesignMap map = blend->design_map + n; - T1_Token token; + T1_Token axis_token; + T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; FT_Int p, num_points; - token = axis_tokens + n; - parser->root.cursor = token->start; - parser->root.limit = token->limit; - - /* count the number of map points */ - { - FT_Byte* ptr = token->start; - FT_Byte* limit = token->limit; + axis_token = axis_tokens + n; + parser->root.cursor = axis_token->start; + parser->root.limit = axis_token->limit; + T1_ToTokenArray( parser, point_tokens, + T1_MAX_MM_MAP_POINTS, &num_points ); - num_points = 0; - for ( ; ptr < limit; ptr++ ) - if ( ptr[0] == '[' ) - num_points++; - } if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) { FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); @@ -594,6 +589,15 @@ for ( p = 0; p < num_points; p++ ) { + T1_Token point_token; + + + point_token = point_tokens + p; + + /* don't include delimiting brackets */ + parser->root.cursor = point_token->start + 1; + parser->root.limit = point_token->limit - 1; + map->design_points[p] = T1_ToInt( parser ); map->blend_points [p] = T1_ToFixed( parser, 0 ); } @@ -611,7 +615,7 @@ parse_weight_vector( T1_Face face, T1_Loader loader ) { - FT_Error error = 0; + FT_Error error = T1_Err_Ok; T1_Parser parser = &loader->parser; PS_Blend blend = face->blend; T1_TokenRec master; @@ -638,8 +642,9 @@ old_cursor = parser->root.cursor; old_limit = parser->root.limit; - parser->root.cursor = master.start; - parser->root.limit = master.limit; + /* don't include the delimiting brackets */ + parser->root.cursor = master.start + 1; + parser->root.limit = master.limit - 1; for ( n = 0; n < blend->num_designs; n++ ) { @@ -675,6 +680,8 @@ #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -683,15 +690,6 @@ /*************************************************************************/ /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* First of all, define the token field static variables. This is a set */ - /* of T1_FieldRec variables used later. */ - /* */ - /*************************************************************************/ - - static FT_Error t1_load_keyword( T1_Face face, T1_Loader loader, @@ -774,32 +772,12 @@ static int is_space( FT_Byte c ) { - return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); + return ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' || c == '\f' || + c == '\0' ); } - static int - is_name_char( FT_Byte c ) - { - /* Note: PostScript allows any non-delimiting, non-whitespace */ - /* in a name (PS Ref Manual, 3rd Ed, p31) */ - /* PostScript delimiters include (,),<,>,[,],{,},/ and % */ - - return ( c != '(' && - c != ')' && - c != '<' && - c != '>' && - c != '[' && - c != ']' && - c != '{' && - c != '}' && - c != '/' && - c != '%' && - ! is_space( c ) - ); - } - - static int read_binary_data( T1_Parser parser, FT_Long* size, @@ -815,14 +793,14 @@ /* */ T1_Skip_Spaces( parser ); + cur = parser->root.cursor; - if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 ) + if ( cur < limit && ft_isdigit( *cur ) ) { *size = T1_ToInt( parser ); - T1_Skip_Spaces( parser ); - T1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */ + T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ /* there is only one whitespace char after the */ /* `RD' or `-|' token */ @@ -838,9 +816,8 @@ } - /* we will now define the routines used to handle */ - /* the `/Encoding', `/Subrs', and `/CharStrings' */ - /* dictionaries */ + /* We now define the routines to handle the `/Encoding', `/Subrs', */ + /* and `/CharStrings' dictionaries. */ static void parse_font_matrix( T1_Face face, @@ -855,7 +832,7 @@ if ( matrix->xx || matrix->yx ) - /* with synthetic fonts, it's possible we get here twice */ + /* with synthetic fonts it is possible we get here twice */ return; (void)T1_ToFixedArray( parser, 6, temp, 3 ); @@ -895,28 +872,25 @@ parse_encoding( T1_Face face, T1_Loader loader ) { - T1_Parser parser = &loader->parser; - FT_Byte* cur = parser->root.cursor; - FT_Byte* limit = parser->root.limit; + T1_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)face->psaux; - /* skip whitespace */ - while ( is_space( *cur ) ) + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) { - cur++; - if ( cur >= limit ) - { - FT_ERROR(( "parse_encoding: out of bounds!\n" )); - parser->root.error = T1_Err_Invalid_File_Format; - return; - } + FT_ERROR(( "parse_encoding: out of bounds!\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return; } /* if we have a number, then the encoding is an array, */ /* and we must load it now */ - if ( (FT_Byte)( *cur - '0' ) < 10 ) + if ( ft_isdigit( *cur ) ) { T1_Encoding encode = &face->type1.encoding; FT_Int count, n; @@ -926,18 +900,19 @@ if ( encode->char_index ) - /* with synthetic fonts, it's possible we get here twice */ + /* with synthetic fonts it is possible we get here twice */ return; - /* read the number of entries in the encoding, should be 256 */ + /* read the number of entries in the encoding; should be 256 */ count = (FT_Int)T1_ToInt( parser ); - if ( parser->root.error ) + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) return; /* we use a T1_Table to store our charnames */ loader->num_chars = encode->num_chars = count; - if ( FT_NEW_ARRAY( encode->char_index, count ) || - FT_NEW_ARRAY( encode->char_name, count ) || + if ( FT_NEW_ARRAY( encode->char_index, count ) || + FT_NEW_ARRAY( encode->char_name, count ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, count, memory ) ) ) { @@ -954,86 +929,74 @@ T1_Add_Table( char_table, n, notdef, 8 ); } - /* Now, we will need to read a record of the form */ + /* Now we need to read a record of the form */ /* ... charcode /charname ... for each entry in our table */ /* */ /* We simply look for a number followed by an immediate */ /* name. Note that this ignores correctly the sequence */ - /* that is often seen in type1 fonts: */ + /* that is often seen in Type 1 fonts: */ /* */ /* 0 1 255 { 1 index exch /.notdef put } for dup */ /* */ /* used to clean the encoding array before anything else. */ - /* */ - /* We stop when we encounter a `def'. */ - cur = parser->root.cursor; - limit = parser->root.limit; - n = 0; + n = 0; - for ( ; cur < limit; ) + while ( parser->root.cursor < limit ) { - FT_Byte c; - - - c = *cur; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; /* we stop when we encounter a `def' */ - if ( c == 'd' && cur + 3 < limit ) + if ( *cur == 'd' && cur + 3 < limit ) { - if ( cur[1] == 'e' && - cur[2] == 'f' && - is_space( cur[-1] ) && - is_space( cur[3] ) ) + if ( cur[1] == 'e' && + cur[2] == 'f' && + is_space( cur[3] ) ) { FT_TRACE6(( "encoding end\n" )); + cur += 3; break; } } /* otherwise, we must find a number before anything else */ - if ( (FT_Byte)( c - '0' ) < 10 ) + if ( ft_isdigit( *cur ) ) { FT_Int charcode; - parser->root.cursor = cur; charcode = (FT_Int)T1_ToInt( parser ); - cur = parser->root.cursor; - - /* skip whitespace */ - while ( cur < limit && is_space( *cur ) ) - cur++; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; - if ( cur < limit && *cur == '/' ) + if ( *cur == '/' && cur + 2 < limit ) { - /* bingo, we have an immediate name -- it must be a */ - /* character name */ - FT_Byte* cur2 = cur + 1; FT_PtrDist len; - while ( cur2 < limit && is_name_char( *cur2 ) ) - cur2++; + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); - len = cur2 - cur - 1; + len = parser->root.cursor - cur; parser->root.error = T1_Add_Table( char_table, charcode, - cur + 1, len + 1 ); + cur, len + 1 ); char_table->elements[charcode][len] = '\0'; if ( parser->root.error ) return; - - cur = cur2; } } else - cur++; + T1_Skip_PS_Token( parser ); } face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; parser->root.cursor = cur; } + /* Otherwise, we should have either `StandardEncoding', */ /* `ExpertEncoding', or `ISOLatin1Encoding' */ else @@ -1063,35 +1026,38 @@ parse_subrs( T1_Face face, T1_Loader loader ) { - T1_Parser parser = &loader->parser; - PS_Table table = &loader->subrs; - FT_Memory memory = parser->root.memory; - FT_Error error; - FT_Int n; + T1_Parser parser = &loader->parser; + PS_Table table = &loader->subrs; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Int n; PSAux_Service psaux = (PSAux_Service)face->psaux; if ( loader->num_subrs ) - /* with synthetic fonts, it's possible we get here twice */ + /* with synthetic fonts it is possible we get here twice */ return; - if ( parser->root.cursor + 2 > parser->root.limit && - parser->root.cursor[0] == '[' && - parser->root.cursor[1] == ']' ) + T1_Skip_Spaces( parser ); + + /* test for empty array */ + if ( parser->root.cursor < parser->root.limit && + *parser->root.cursor == '[' ) { - /* empty array */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor >= parser->root.limit || + *parser->root.cursor != ']' ) + parser->root.error = T1_Err_Invalid_File_Format; return; } loader->num_subrs = (FT_Int)T1_ToInt( parser ); - if ( parser->root.error ) - return; /* position the parser right before the `dup' of the first subr */ - T1_Skip_Spaces( parser ); - T1_Skip_Alpha( parser ); /* `array' */ - T1_Skip_Spaces( parser ); + T1_Skip_PS_Token( parser ); /* `array' */ + T1_Skip_Spaces ( parser ); /* initialize subrs array */ error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory ); @@ -1113,6 +1079,8 @@ if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) break; + T1_Skip_PS_Token( parser ); /* `dup' */ + idx = T1_ToInt( parser ); if ( !read_binary_data( parser, &size, &base ) ) @@ -1122,14 +1090,13 @@ /* (bound to `noaccess put') or by two separate tokens: */ /* `noaccess' & `put'. We position the parser right */ /* before the next `dup', if any. */ - T1_Skip_Spaces( parser ); - T1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */ - T1_Skip_Spaces( parser ); + T1_Skip_PS_Token( parser ); /* `NP' or `I' or `noaccess' */ + T1_Skip_Spaces ( parser ); if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) { - T1_Skip_Alpha( parser ); /* skip `put' */ - T1_Skip_Spaces( parser ); + T1_Skip_PS_Token( parser ); /* skip `put' */ + T1_Skip_Spaces ( parser ); } /* some fonts use a value of -1 for lenIV to indicate that */ @@ -1164,6 +1131,9 @@ } +#define TABLE_EXTEND 5 + + static void parse_charstrings( T1_Face face, T1_Loader loader ) @@ -1185,25 +1155,24 @@ if ( loader->num_glyphs ) - /* with synthetic fonts, it's possible we get here twice */ + /* with synthetic fonts it is possible we get here twice */ return; loader->num_glyphs = (FT_Int)T1_ToInt( parser ); if ( parser->root.error ) return; - /* initialize tables (leaving room for addition of .notdef, */ - /* if necessary). */ + /* initialize tables, leaving room for addition of .notdef, */ + /* if necessary, and a few other glyphs to handle buggy */ + /* fonts which have more glyphs than specified. */ - error = psaux->ps_table_funcs->init( code_table, - loader->num_glyphs + 1, - memory ); + error = psaux->ps_table_funcs->init( + code_table, loader->num_glyphs + 1 + TABLE_EXTEND, memory ); if ( error ) goto Fail; - error = psaux->ps_table_funcs->init( name_table, - loader->num_glyphs + 1, - memory ); + error = psaux->ps_table_funcs->init( + name_table, loader->num_glyphs + 1 + TABLE_EXTEND, memory ); if ( error ) goto Fail; @@ -1235,29 +1204,34 @@ break; /* we stop when we find a `def' or `end' keyword */ - if ( *cur == 'd' && - cur + 3 < limit && - cur[1] == 'e' && - cur[2] == 'f' ) - break; + if ( cur + 3 < limit && is_space( cur[3] ) ) + { + if ( cur[0] == 'd' && + cur[1] == 'e' && + cur[2] == 'f' ) + break; - if ( *cur == 'e' && - cur + 3 < limit && - cur[1] == 'n' && - cur[2] == 'd' ) - break; + if ( cur[0] == 'e' && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + } if ( *cur != '/' ) - T1_Skip_Alpha( parser ); + T1_Skip_PS_Token( parser ); else { - FT_Byte* cur2 = cur + 1; FT_PtrDist len; - while ( cur2 < limit && is_name_char( *cur2 ) ) - cur2++; - len = cur2 - cur - 1; + T1_Skip_PS_Token( parser ); + if ( cur >= limit ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + len = parser->root.cursor - cur; error = T1_Add_Table( name_table, n, cur + 1, len + 1 ); if ( error ) @@ -1274,11 +1248,11 @@ notdef_found = 1; } - parser->root.cursor = cur2; if ( !read_binary_data( parser, &size, &base ) ) return; - if ( face->type1.private_dict.lenIV >= 0 ) + if ( face->type1.private_dict.lenIV >= 0 && + n < loader->num_glyphs + TABLE_EXTEND ) { FT_Byte* temp; @@ -1299,8 +1273,6 @@ goto Fail; n++; - if ( n >= loader->num_glyphs ) - break; } } @@ -1311,11 +1283,11 @@ (const char*)name_table->elements[0] ) && notdef_found ) { - /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ - /* name and code entries to swap_table. Then place notdef_index name */ - /* and code entries into swap_table. Then swap name and code */ - /* entries at indices notdef_index and 0 using values stored in */ - /* swap_table. */ + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ /* Index 0 name */ error = T1_Add_Table( swap_table, 0, @@ -1426,6 +1398,14 @@ } + /*************************************************************************/ + /* */ + /* Define the token field static variables. This is a set of */ + /* T1_FieldRec variables. */ + /* */ + /*************************************************************************/ + + static const T1_FieldRec t1_keywords[] = { @@ -1462,120 +1442,134 @@ FT_Byte* keyword_flags ) { T1_Parser parser = &loader->parser; + FT_Byte* limit; parser->root.cursor = base; parser->root.limit = base + size; - parser->root.error = 0; + parser->root.error = T1_Err_Ok; + + limit = parser->root.limit; + while ( parser->root.cursor < limit ) { - FT_Byte* cur = base; - FT_Byte* limit = cur + size; + FT_Byte* cur; - for ( ; cur < limit; cur++ ) + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + + /* look for `FontDirectory', which causes problems for some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) { - /* look for `FontDirectory', which causes problems on some fonts */ - if ( *cur == 'F' && cur + 25 < limit && - ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) - { - FT_Byte* cur2; + FT_Byte* cur2; - /* skip the `FontDirectory' keyword */ - cur += 13; - cur2 = cur; + /* skip the `FontDirectory' keyword */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = cur2 = parser->root.cursor; - /* lookup the `known' keyword */ - while ( cur < limit && *cur != 'k' && - ft_strncmp( (char*)cur, "known", 5 ) ) - cur++; + /* look up the `known' keyword */ + while ( cur < limit ) + { + if ( *cur == 'k' && cur + 5 < limit && + ft_strncmp( (char*)cur, "known", 5 ) ) + break; - if ( cur < limit ) - { - T1_TokenRec token; + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + if ( cur < limit ) + { + T1_TokenRec token; - /* skip the `known' keyword and the token following it */ - cur += 5; - loader->parser.root.cursor = cur; - T1_ToToken( &loader->parser, &token ); - /* if the last token was an array, skip it! */ - if ( token.type == T1_TOKEN_TYPE_ARRAY ) - cur2 = parser->root.cursor; - } - cur = cur2; + /* skip the `known' keyword and the token following it */ + T1_Skip_PS_Token( parser ); + T1_ToToken( parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; } - /* look for immediates */ - else if ( *cur == '/' && cur + 2 < limit ) - { - FT_Byte* cur2; - FT_PtrDist len; + parser->root.cursor = cur2; + } + + /* look for `closefile' which ends the eexec section */ + else if ( *cur == 'c' && cur + 9 < limit && + ft_strncmp( (char*)cur, "closefile", 9 ) == 0 ) + break; + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + + cur++; - cur++; - cur2 = cur; - while ( cur2 < limit && is_name_char( *cur2 ) ) - cur2++; + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); - len = cur2 - cur; - if ( len > 0 && len < 22 ) + len = parser->root.cursor - cur; + + if ( len > 0 && len < 22 ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)t1_keywords; + FT_Byte* keyword_flag = keyword_flags; + + + for (;;) { - { - /* now, compare the immediate name to the keyword table */ - T1_Field keyword = (T1_Field)t1_keywords; - FT_Byte* keyword_flag = keyword_flags; + FT_Byte* name; - for (;;) - { - FT_Byte* name; + name = (FT_Byte*)keyword->ident; + if ( !name ) + { + T1_Skip_PS_Token( parser ); + break; + } + + if ( cur[0] == name[0] && + len == ft_strlen( (const char*)name ) ) + { + FT_PtrDist n; - name = (FT_Byte*)keyword->ident; - if ( !name ) + for ( n = 1; n < len; n++ ) + if ( cur[n] != name[n] ) break; - if ( cur[0] == name[0] && - len == ft_strlen( (const char*)name ) ) + if ( n >= len ) + { + /* We found it -- run the parsing callback! */ + /* We only record the first instance of any */ + /* field to deal adequately with synthetic fonts */ + if ( keyword_flag[0] == 0 ) { - FT_PtrDist n; - - - for ( n = 1; n < len; n++ ) - if ( cur[n] != name[n] ) - break; - - if ( n >= len ) - { - /* we found it -- run the parsing callback! */ - parser->root.cursor = cur2; - T1_Skip_Spaces( parser ); - - /* we only record the first instance of any */ - /* field to deal adequately with synthetic fonts */ - if ( keyword_flag[0] == 0 ) - { - parser->root.error = t1_load_keyword( face, - loader, - keyword ); - if ( parser->root.error ) - return parser->root.error; - } - keyword_flag[0] = 1; - - cur = parser->root.cursor; - break; - } + parser->root.error = t1_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; } - keyword++; - keyword_flag++; + keyword_flag[0] = 1; + break; } } + keyword++; + keyword_flag++; } } } + else + T1_Skip_PS_Token( parser ); } return parser->root.error; } @@ -1742,16 +1736,21 @@ if ( ft_strcmp( (const char*)".notdef", (const char*)glyph_name ) != 0 ) { - if ( charcode < min_char ) min_char = charcode; - if ( charcode > max_char ) max_char = charcode; + if ( charcode < min_char ) + min_char = charcode; + if ( charcode > max_char ) + max_char = charcode; } break; } } } - /* Yes, this happens: Certain PDF-embedded fonts have only a ".notdef" - * glyph defined! + + /* + * Yes, this happens: Certain PDF-embedded fonts have only a + * `.notdef' glyph defined! */ + if ( min_char > max_char ) { min_char = 0; diff --git a/src/type1/t1parse.c b/src/type1/t1parse.c index d785aec59..5a380632e 100644 --- a/src/type1/t1parse.c +++ b/src/type1/t1parse.c @@ -104,7 +104,7 @@ FT_Long size; - psaux->ps_parser_funcs->init( &parser->root,0, 0, memory ); + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); parser->stream = stream; parser->base_len = 0; @@ -219,36 +219,13 @@ } - /* return the value of an hexadecimal digit */ - static int - hexa_value( char c ) - { - unsigned int d; - - - d = (unsigned int)( c - '0' ); - if ( d <= 9 ) - return (int)d; - - d = (unsigned int)( c - 'a' ); - if ( d <= 5 ) - return (int)( d + 10 ); - - d = (unsigned int)( c - 'A' ); - if ( d <= 5 ) - return (int)( d + 10 ); - - return -1; - } - - FT_LOCAL_DEF( FT_Error ) T1_Get_Private_Dict( T1_Parser parser, PSAux_Service psaux ) { FT_Stream stream = parser->stream; FT_Memory memory = parser->root.memory; - FT_Error error = 0; + FT_Error error = T1_Err_Ok; FT_Long size; @@ -302,7 +279,8 @@ break; } - if ( FT_STREAM_READ( parser->private_dict + parser->private_len, size ) ) + if ( FT_STREAM_READ( parser->private_dict + parser->private_len, + size ) ) goto Fail; parser->private_len += size; @@ -310,9 +288,9 @@ } else { - /* we have already `loaded' the whole PFA font file into memory; */ + /* We have already `loaded' the whole PFA font file into memory; */ /* if this is a memory resource, allocate a new block to hold */ - /* the private dict. Otherwise, simply overwrite into the base */ + /* the private dict. Otherwise, simply overwrite into the base */ /* dictionary block in the heap. */ /* first of all, look at the `eexec' keyword */ @@ -330,7 +308,7 @@ if ( cur[1] == 'e' && cur[2] == 'x' && cur[3] == 'e' && cur[4] == 'c' ) { - cur += 6; /* we skip the newling after the `eexec' */ + cur += 6; /* we skip the newline after the `eexec' */ /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */ /* skip the extra \n if we find it */ @@ -379,51 +357,38 @@ /* the `eexec' keyword); if they all are hexadecimal digits, then */ /* we have a case of ASCII storage */ - if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) | - hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 ) - - /* binary encoding -- `simply' copy the private dict */ - FT_MEM_COPY( parser->private_dict, cur, size ); - - else + if ( ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && + ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) { /* ASCII hexadecimal encoding */ + FT_Long len; - FT_Byte* write; - FT_Int count; - - write = parser->private_dict; - count = 0; - - for ( ;cur < limit; cur++ ) - { - int hex1; - - - /* check for newline */ - if ( cur[0] == '\r' || cur[0] == '\n' ) - continue; - - /* exit if we have a non-hexadecimal digit that isn't a newline */ - hex1 = hexa_value( cur[0] ); - if ( hex1 < 0 || cur + 1 >= limit ) - break; - - /* otherwise, store byte */ - *write++ = (FT_Byte)( ( hex1 << 4 ) | hexa_value( cur[1] ) ); - count++; - cur++; - } + parser->root.cursor = cur; + (void)psaux->ps_parser_funcs->to_bytes( &parser->root, + parser->private_dict, + parser->private_len, + &len, + 0 ); + parser->private_len = len; /* put a safeguard */ - parser->private_len = write - parser->private_dict; - *write++ = 0; + parser->private_dict[len] = '\0'; } + else + /* binary encoding -- copy the private dict */ + FT_MEM_COPY( parser->private_dict, cur, size ); } /* we now decrypt the encoded binary private dictionary */ psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); + + /* replace the four random bytes at the beginning with whitespace */ + parser->private_dict[0] = ' '; + parser->private_dict[1] = ' '; + parser->private_dict[2] = ' '; + parser->private_dict[3] = ' '; + parser->root.base = parser->private_dict; parser->root.cursor = parser->private_dict; parser->root.limit = parser->root.cursor + parser->private_len; diff --git a/src/type1/t1parse.h b/src/type1/t1parse.h index ecc206739..6fa4ca624 100644 --- a/src/type1/t1parse.h +++ b/src/type1/t1parse.h @@ -4,7 +4,7 @@ /* */ /* Type 1 parser (specification). */ /* */ -/* Copyright 1996-2001, 2002 by */ +/* Copyright 1996-2001, 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -69,9 +69,9 @@ FT_BEGIN_HEADER FT_Byte* private_dict; FT_Long private_len; - FT_Byte in_pfb; - FT_Byte in_memory; - FT_Byte single_block; + FT_Bool in_pfb; + FT_Bool in_memory; + FT_Bool single_block; } T1_ParserRec, *T1_Parser; @@ -91,8 +91,8 @@ FT_BEGIN_HEADER } while ( 0 ) -#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) -#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root ) +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) #define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) #define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) diff --git a/src/type42/t42parse.c b/src/type42/t42parse.c index 071c6ec1b..7ce4707a4 100644 --- a/src/type42/t42parse.c +++ b/src/type42/t42parse.c @@ -111,8 +111,8 @@ (p)->funcs.release( p ); \ } while ( 0 ) -#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) -#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root ) +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) #define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) #define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) @@ -318,7 +318,7 @@ /* if we have a number, then the encoding is an array, */ /* and we must load it now */ - if ( (FT_Byte)( *cur - '0' ) < 10 ) + if ( ft_isdigit( *cur ) ) { T1_Encoding encode = &face->type1.encoding; FT_Int count, n; @@ -394,7 +394,7 @@ } /* otherwise, we must find a number before anything else */ - if ( (FT_Byte)( c - '0' ) < 10 ) + if ( ft_isdigit( c ) ) { FT_Int charcode; @@ -571,7 +571,7 @@ } default: - if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) ) + if ( !ft_isxdigit( *cur ) || !ft_isxdigit( *(cur + 1) ) ) { FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" )); error = T42_Err_Invalid_File_Format; @@ -705,7 +705,7 @@ break; if ( *cur != '/' ) - T1_Skip_Alpha( parser ); + T1_Skip_PS_Token( parser ); else { FT_Byte* cur2 = cur + 1;