From 88ad21fbe54a5bad1d169e127094e26f1f840fba Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 16 Nov 2016 14:57:52 -0800 Subject: [cff] Make cff parser stack dynamic Allocate and free parser->stack. Allow maxstack to increase the default. Do validation of maxstack at parse time; make it a CALLBACK. Defer support for > 256 FDs in cff_font_load(). --- src/cff/cf2intrp.c | 9 ++------ src/cff/cffload.c | 39 +++++++++++++++++++++++---------- src/cff/cffparse.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/cff/cffparse.h | 15 ++++++++++--- src/cff/cfftoken.h | 17 +++++++-------- 5 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c index 9b190775a..66a237111 100644 --- a/src/cff/cf2intrp.c +++ b/src/cff/cf2intrp.c @@ -562,13 +562,8 @@ */ /* allocate an operand stack */ - if ( font->isCFF2 ) - { - /* CFF2 font may increase the operand stack size */ - FT_UInt maxstack = cf2_getMaxstack( decoder ); - if ( maxstack > stackSize ) - stackSize = maxstack; - } + stackSize = font->isCFF2 ? cf2_getMaxstack( decoder ) : + CF2_OPERAND_STACK_SIZE; opStack = cf2_stack_init( memory, error, stackSize ); if ( !opStack ) { diff --git a/src/cff/cffload.c b/src/cff/cffload.c index 4c65c94e6..1a6454314 100644 --- a/src/cff/cffload.c +++ b/src/cff/cffload.c @@ -1740,9 +1740,10 @@ Exit: CFF_FontRecDict top = &subfont->font_dict; CFF_Private priv = &subfont->private_dict; FT_Stream stream = font->stream; + FT_UInt stackSize; if ( top->private_offset == 0 || top->private_size == 0 ) - goto Exit; /* no private DICT, do nothing */ + goto Exit2; /* no private DICT, do nothing */ /* store handle needed to access memory, vstore for blend */ subfont->blend.font = font; @@ -1762,12 +1763,17 @@ Exit: subfont->lenNDV = lenNDV; subfont->NDV = NDV; - cff_parser_init( &parser, - font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE, - priv, - font->library, - top->num_designs, - top->num_axes ); + stackSize = font->cff2 ? font->top_font.font_dict.maxstack : + CFF_MAX_STACK_DEPTH + 1; + + if ( cff_parser_init( &parser, + font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE, + priv, + font->library, + stackSize, + top->num_designs, + top->num_axes ) ) + goto Exit; if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) || FT_FRAME_ENTER( top->private_size ) ) goto Exit; @@ -1784,7 +1790,12 @@ Exit: priv->num_blue_values &= ~1; Exit: - cff_blend_clear( subfont ); + /* clean up */ + cff_blend_clear( subfont ); /* clear blend stack */ + cff_parser_done( &parser ); /* free parser stack */ + + Exit2: + /* no clean up (parser not inited) */ return error; } @@ -1811,12 +1822,15 @@ Exit: CFF_Private priv = &subfont->private_dict; FT_Bool cff2 = (code == CFF2_CODE_TOPDICT || code == CFF2_CODE_FONTDICT ); + FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK : CFF_MAX_STACK_DEPTH; - + /* Note: we use default stack size for CFF2 Font DICT because */ + /* Top and Font DICTs are not allowed to have blend operators */ cff_parser_init( &parser, code, &subfont->font_dict, library, + stackSize, 0, 0 ); @@ -1902,6 +1916,8 @@ Exit: } Exit: + cff_parser_done( &parser ); /* free parser stack */ + return error; } @@ -2113,7 +2129,8 @@ Exit: goto Exit; /* Font Dicts are not limited to 256 for CFF2 */ - if ( !cff2 && fd_index.count > CFF_MAX_CID_FONTS ) + /* TODO: support this for CFF2 */ + if ( fd_index.count > CFF_MAX_CID_FONTS ) { FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" )); goto Fail_CID; @@ -2134,7 +2151,7 @@ Exit: sub = font->subfonts[idx]; FT_TRACE4(( "parsing subfont %u\n", idx )); error = cff_subfont_load( sub, &fd_index, idx, - stream, base_offset, library, + stream, base_offset, library, cff2 ? CFF2_CODE_FONTDICT : CFF_CODE_TOPDICT, font ); if ( error ) diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c index 8f54cb0e6..916d5f648 100644 --- a/src/cff/cffparse.c +++ b/src/cff/cffparse.c @@ -37,22 +37,48 @@ #define FT_COMPONENT trace_cffparse - FT_LOCAL_DEF( void ) + FT_LOCAL_DEF( FT_Error ) cff_parser_init( CFF_Parser parser, FT_UInt code, void* object, FT_Library library, + FT_UInt stackSize, FT_UShort num_designs, FT_UShort num_axes ) { + FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */ + FT_Error error; /* for FT_NEW_ARRAY */ + FT_MEM_ZERO( parser, sizeof ( *parser ) ); - parser->top = parser->stack; + /*parser->top = parser->stack;*/ parser->object_code = code; parser->object = object; parser->library = library; parser->num_designs = num_designs; parser->num_axes = num_axes; + + /* allocate the stack buffer */ + if ( FT_NEW_ARRAY( parser->stack, stackSize ) ) + { + FT_FREE( parser->stack ); + goto Exit; + } + + parser->stackSize = stackSize; + parser->top = parser->stack; /* empty stack */ + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_parser_done( CFF_Parser parser ) + { + FT_Memory memory = parser->library->memory; /* for FT_FREE */ + + FT_FREE( parser->stack ); } @@ -865,6 +891,36 @@ return error; } + /* maxstack operator increases parser and operand stacks for CFF2 */ + static FT_Error + cff_parse_maxstack( CFF_Parser parser ) + { + /* maxstack operator can only be used in a Top DICT */ + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error = FT_Err_Ok; + + if ( !dict ) + { + error = FT_ERR( Invalid_File_Format ); + goto Exit; + } + + dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ ); + if ( dict->maxstack > CFF2_MAX_STACK ) + dict->maxstack = CFF2_MAX_STACK; + if ( dict->maxstack < CFF2_DEFAULT_STACK ) + dict->maxstack = CFF2_DEFAULT_STACK; + + FT_TRACE4(( " %d\n", dict->maxstack )); + error = FT_Err_Ok; + + Exit: + return error; + } + + + #define CFF_FIELD_NUM( code, name, id ) \ CFF_FIELD( code, name, id, cff_kind_num ) #define CFF_FIELD_FIXED( code, name, id ) \ @@ -1171,7 +1227,7 @@ if ( v >= 27 && v != 31 && v != 255 ) { /* it's a number; we will push its position on the stack */ - if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH ) + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) goto Stack_Overflow; *parser->top++ = p; @@ -1262,7 +1318,7 @@ FT_Bool neg; - if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH ) + if ( parser->top - parser->stack >= parser->stackSize )*/ goto Stack_Overflow; *parser->top++ = q; diff --git a/src/cff/cffparse.h b/src/cff/cffparse.h index 7c0801596..f27d6c7f7 100644 --- a/src/cff/cffparse.h +++ b/src/cff/cffparse.h @@ -28,7 +28,11 @@ FT_BEGIN_HEADER -#define CFF_MAX_STACK_DEPTH 193 +/* CFF uses constant parser stack size */ +/* CFF2 can increase from default 193 */ +#define CFF_MAX_STACK_DEPTH 96 +#define CFF2_MAX_STACK 513 +#define CFF2_DEFAULT_STACK 193 #define CFF_CODE_TOPDICT 0x1000 #define CFF_CODE_PRIVATE 0x2000 @@ -44,8 +48,9 @@ FT_BEGIN_HEADER FT_Byte* limit; FT_Byte* cursor; - FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1]; + FT_Byte** stack; FT_Byte** top; + FT_UInt stackSize; /* allocated size */ FT_UInt object_code; void* object; @@ -56,14 +61,18 @@ FT_BEGIN_HEADER } CFF_ParserRec, *CFF_Parser; - FT_LOCAL( void ) + FT_LOCAL( FT_Error ) cff_parser_init( CFF_Parser parser, FT_UInt code, void* object, FT_Library library, + FT_UInt stackSize, FT_UShort num_designs, FT_UShort num_axes ); + FT_LOCAL( void ) + cff_parser_done( CFF_Parser parser ); + FT_LOCAL( FT_Error ) cff_parser_run( CFF_Parser parser, FT_Byte* start, diff --git a/src/cff/cfftoken.h b/src/cff/cfftoken.h index f1cf3364a..ab2fcfd6b 100644 --- a/src/cff/cfftoken.h +++ b/src/cff/cfftoken.h @@ -107,12 +107,12 @@ #undef CFFCODE #define CFFCODE CFF2_CODE_TOPDICT - CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) - CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) - CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) - CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) - CFF_FIELD_NUM ( 24, vstore_offset, "vstore" ) - CFF_FIELD_NUM ( 25, maxstack, "maxstack" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) + CFF_FIELD_NUM ( 24, vstore_offset, "vstore" ) + CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" ) #undef FT_STRUCTURE #define FT_STRUCTURE CFF_FontRecDictRec @@ -120,9 +120,8 @@ #undef CFFCODE #define CFFCODE CFF2_CODE_FONTDICT - CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) - CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) - CFF_FIELD_STRING ( 0x126, cid_font_name, "FontName" ) + CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) #undef FT_STRUCTURE #define FT_STRUCTURE CFF_PrivateRec -- cgit v1.2.1