From bd4b8976a36fd49dc2e04516aa76687c784c4c3a Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sun, 20 Dec 2015 19:36:04 +0100 Subject: [PATCH] [type1, psaux] Handle large values of num_subrs correctly (#46692). We now use a hash to map from subr indices to array elements holding the subroutines, if necessary. * include/freetype/internal/t1types.h: Include FT_INTERNAL_HASH_H. (T1_FontRec): Add `subrs_hash' field. * include/freetype/internal/psaux.h: Include FT_INTERNAL_HASH_H. (T1_DecoderRec): Add `subrs_hash' field. * src/type1/t1load.h (T1_LoaderRec): Add `subrs_hash' field. * src/type1/t1driver.c: Include FT_INTERNAL_HASH_H. (t1_ps_get_font_value) [PS_DICT_SUBR]: Look up hash if necessary. * src/type1/t1load.c: Include FT_INTERNAL_HASH_H. (parse_subrs): Use hash for subr indices that exceed the allocated number of subr slots. (t1_init_loader): Remove unnecessary code. (t1_done_loader, T1_Open_Face): Updated. * src/type1/t1gload.c (T1_Compute_Max_Advance, T1_Get_Advances, T1_Load_Glyph): Updated. * src/type1/t1objs.c (T1_Face_Done): Updated. * src/psaux/t1decode.c: Include FT_INTERNAL_HASH_H. (t1_decoder_parse_charstrings) [op_callsubr]: Look up hash if necessary. * src/cid/cidgload.c (cid_load_glyph): Updated. --- ChangeLog | 35 ++++++++++++++++ include/freetype/internal/psaux.h | 2 + include/freetype/internal/t1types.h | 2 + src/cid/cidgload.c | 7 ++-- src/psaux/t1decode.c | 14 +++++++ src/type1/t1driver.c | 34 ++++++++++++--- src/type1/t1gload.c | 9 ++-- src/type1/t1load.c | 65 ++++++++++++++++++++++------- src/type1/t1load.h | 1 + src/type1/t1objs.c | 3 ++ 10 files changed, 147 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7e62e2e70..fa3273543 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2015-12-20 Werner Lemberg + + [type1, psaux] Handle large values of num_subrs correctly (#46692). + + We now use a hash to map from subr indices to array elements holding + the subroutines, if necessary. + + * include/freetype/internal/t1types.h: Include FT_INTERNAL_HASH_H. + (T1_FontRec): Add `subrs_hash' field. + + * include/freetype/internal/psaux.h: Include FT_INTERNAL_HASH_H. + (T1_DecoderRec): Add `subrs_hash' field. + + * src/type1/t1load.h (T1_LoaderRec): Add `subrs_hash' field. + + * src/type1/t1driver.c: Include FT_INTERNAL_HASH_H. + (t1_ps_get_font_value) [PS_DICT_SUBR]: Look up hash if necessary. + + * src/type1/t1load.c: Include FT_INTERNAL_HASH_H. + (parse_subrs): Use hash for subr indices that exceed the allocated + number of subr slots. + (t1_init_loader): Remove unnecessary code. + (t1_done_loader, T1_Open_Face): Updated. + + * src/type1/t1gload.c (T1_Compute_Max_Advance, T1_Get_Advances, + T1_Load_Glyph): Updated. + + * src/type1/t1objs.c (T1_Face_Done): Updated. + + * src/psaux/t1decode.c: Include FT_INTERNAL_HASH_H. + (t1_decoder_parse_charstrings) [op_callsubr]: Look up hash if + necessary. + + * src/cid/cidgload.c (cid_load_glyph): Updated. + 2015-12-20 Werner Lemberg [base] Thinko: Remove free function pointer. diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h index 1c5f784f5..63aac8869 100644 --- a/include/freetype/internal/psaux.h +++ b/include/freetype/internal/psaux.h @@ -24,6 +24,7 @@ #include #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_TYPE1_TYPES_H +#include FT_INTERNAL_HASH_H #include FT_SERVICE_POSTSCRIPT_CMAPS_H @@ -678,6 +679,7 @@ FT_BEGIN_HEADER FT_Int num_subrs; FT_Byte** subrs; FT_UInt* subrs_len; /* array of subrs length (optional) */ + FT_Hash subrs_hash; /* used if `num_subrs' was massaged */ FT_Matrix font_matrix; FT_Vector font_offset; diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h index 029acc400..a35a4fdea 100644 --- a/include/freetype/internal/t1types.h +++ b/include/freetype/internal/t1types.h @@ -25,6 +25,7 @@ #include FT_TYPE1_TABLES_H #include FT_INTERNAL_POSTSCRIPT_HINTS_H #include FT_INTERNAL_SERVICE_H +#include FT_INTERNAL_HASH_H #include FT_SERVICE_POSTSCRIPT_CMAPS_H @@ -107,6 +108,7 @@ FT_BEGIN_HEADER FT_Int num_subrs; FT_Byte** subrs; FT_UInt* subrs_len; + FT_Hash subrs_hash; FT_Int num_glyphs; FT_String** glyph_names; /* array of glyph names */ diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c index d402f8e16..99962dbca 100644 --- a/src/cid/cidgload.c +++ b/src/cid/cidgload.c @@ -142,9 +142,10 @@ /* Set up subrs */ - decoder->num_subrs = cid_subrs->num_subrs; - decoder->subrs = cid_subrs->code; - decoder->subrs_len = 0; + decoder->num_subrs = cid_subrs->num_subrs; + decoder->subrs = cid_subrs->code; + decoder->subrs_len = 0; + decoder->subrs_hash = NULL; /* Set up font matrix */ dict = cid->font_dicts + fd_select; diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c index 5811fcb49..9e2d2771d 100644 --- a/src/psaux/t1decode.c +++ b/src/psaux/t1decode.c @@ -20,6 +20,7 @@ #include FT_INTERNAL_CALC_H #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include FT_INTERNAL_HASH_H #include FT_OUTLINE_H #include "t1decode.h" @@ -1348,6 +1349,19 @@ FT_TRACE4(( " callsubr" )); idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + if ( idx < 0 || idx >= decoder->num_subrs ) { FT_ERROR(( "t1_decoder_parse_charstrings:" diff --git a/src/type1/t1driver.c b/src/type1/t1driver.c index 716dd55e4..e1e2852f8 100644 --- a/src/type1/t1driver.c +++ b/src/type1/t1driver.c @@ -29,6 +29,7 @@ #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_HASH_H #include FT_SERVICE_MULTIPLE_MASTERS_H #include FT_SERVICE_GLYPH_DICT_H @@ -329,13 +330,36 @@ break; case PS_DICT_SUBR: - if ( idx < (FT_UInt)type1->num_subrs ) { - retval = type1->subrs_len[idx] + 1; - if ( value && value_len >= retval ) + FT_Bool ok = 0; + + + if ( type1->subrs_hash ) { - ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 ); - ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + /* convert subr index to array index */ + size_t* val = ft_hash_num_lookup( idx, type1->subrs_hash ); + + + if ( val ) + { + idx = *val; + ok = 1; + } + } + else + { + if ( idx < (FT_UInt)type1->num_subrs ) + ok = 1; + } + + if ( ok ) + { + retval = type1->subrs_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } } } break; diff --git a/src/type1/t1gload.c b/src/type1/t1gload.c index 85ada2ea6..81ea22678 100644 --- a/src/type1/t1gload.c +++ b/src/type1/t1gload.c @@ -183,6 +183,7 @@ decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; decoder.buildchar = face->buildchar; decoder.len_buildchar = face->len_buildchar; @@ -245,9 +246,10 @@ decoder.builder.metrics_only = 1; decoder.builder.load_points = 0; - decoder.num_subrs = type1->num_subrs; - decoder.subrs = type1->subrs; - decoder.subrs_len = type1->subrs_len; + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; decoder.buildchar = face->buildchar; decoder.len_buildchar = face->len_buildchar; @@ -346,6 +348,7 @@ decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; decoder.buildchar = face->buildchar; decoder.len_buildchar = face->len_buildchar; diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 4ce1e35ae..3fb3cd28b 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -66,6 +66,7 @@ #include FT_MULTIPLE_MASTERS_H #include FT_INTERNAL_TYPE1_TYPES_H #include FT_INTERNAL_CALC_H +#include FT_INTERNAL_HASH_H #include "t1load.h" #include "t1errors.h" @@ -1404,6 +1405,8 @@ FT_Memory memory = parser->root.memory; FT_Error error; FT_Int num_subrs; + FT_Int count; + FT_Hash hash = NULL; PSAux_Service psaux = (PSAux_Service)face->psaux; @@ -1432,11 +1435,36 @@ /* we certainly need more than 8 bytes per subroutine */ if ( num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 ) { + /* + * There are two possibilities. Either the font contains an invalid + * value for `num_subrs', or we have a subsetted font where the + * subroutine indices are not adjusted, e.g. + * + * /Subrs 812 array + * dup 0 { ... } NP + * dup 51 { ... } NP + * dup 681 { ... } NP + * ND + * + * In both cases, we use a number hash that maps from subr indices to + * actual array elements. + */ + FT_TRACE0(( "parse_subrs: adjusting number of subroutines" " (from %d to %d)\n", num_subrs, ( parser->root.limit - parser->root.cursor ) >> 3 )); num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3; + + if ( !hash ) + { + if ( FT_NEW( hash ) ) + goto Fail; + + error = ft_hash_init( hash, 1, memory ); + if ( error ) + goto Fail; + } } /* position the parser right before the `dup' of the first subr */ @@ -1458,7 +1486,7 @@ /* */ /* `index' + binary data */ /* */ - for (;;) + for ( count = 0; ; count++ ) { FT_Long idx; FT_ULong size; @@ -1494,6 +1522,14 @@ T1_Skip_Spaces ( parser ); } + /* if we use a hash, the subrs index is the key, and a running */ + /* counter specified for `T1_Add_Table' acts as the value */ + if ( hash ) + { + ft_hash_num_insert( idx, count, hash, memory ); + idx = count; + } + /* with synthetic fonts it is possible we get here twice */ if ( loader->num_subrs ) continue; @@ -1534,7 +1570,10 @@ } if ( !loader->num_subrs ) - loader->num_subrs = num_subrs; + { + loader->num_subrs = num_subrs; + loader->subrs_hash = hash; + } return; @@ -2105,17 +2144,6 @@ FT_UNUSED( face ); FT_MEM_ZERO( loader, sizeof ( *loader ) ); - loader->num_glyphs = 0; - loader->num_chars = 0; - - /* initialize the tables -- simply set their `init' field to 0 */ - loader->encoding_table.init = 0; - loader->charstrings.init = 0; - loader->glyph_names.init = 0; - loader->subrs.init = 0; - loader->swap_table.init = 0; - loader->fontdata = 0; - loader->keywords_encountered = 0; } @@ -2123,6 +2151,7 @@ t1_done_loader( T1_Loader loader ) { T1_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; /* finalize tables */ @@ -2132,6 +2161,10 @@ T1_Release_Table( &loader->swap_table ); T1_Release_Table( &loader->subrs ); + /* finalize hash */ + ft_hash_free( loader->subrs_hash, memory ); + FT_FREE( loader->subrs_hash ); + /* finalize parser */ T1_Finalize_Parser( parser ); } @@ -2248,11 +2281,15 @@ if ( loader.subrs.init ) { - loader.subrs.init = 0; type1->num_subrs = loader.num_subrs; type1->subrs_block = loader.subrs.block; type1->subrs = loader.subrs.elements; type1->subrs_len = loader.subrs.lengths; + type1->subrs_hash = loader.subrs_hash; + + /* prevent `t1_done_loader' from freeing the propagated data */ + loader.subrs.init = 0; + loader.subrs_hash = NULL; } if ( !IS_INCREMENTAL ) diff --git a/src/type1/t1load.h b/src/type1/t1load.h index de422e7ec..58b1eeee7 100644 --- a/src/type1/t1load.h +++ b/src/type1/t1load.h @@ -46,6 +46,7 @@ FT_BEGIN_HEADER FT_Int num_subrs; PS_TableRec subrs; + FT_Hash subrs_hash; FT_Bool fontdata; FT_UInt keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */ diff --git a/src/type1/t1objs.c b/src/type1/t1objs.c index d921063ea..7c9225644 100644 --- a/src/type1/t1objs.c +++ b/src/type1/t1objs.c @@ -247,6 +247,9 @@ FT_FREE( type1->subrs ); FT_FREE( type1->subrs_len ); + ft_hash_free( type1->subrs_hash, memory ); + FT_FREE( type1->subrs_hash ); + FT_FREE( type1->subrs_block ); FT_FREE( type1->charstrings_block ); FT_FREE( type1->glyph_names_block );