diff options
Diffstat (limited to 'src/sfnt')
-rw-r--r-- | src/sfnt/sfdriver.c | 22 | ||||
-rw-r--r-- | src/sfnt/sfntpic.h | 12 | ||||
-rw-r--r-- | src/sfnt/sfobjs.c | 148 | ||||
-rw-r--r-- | src/sfnt/sfobjs.h | 9 | ||||
-rw-r--r-- | src/sfnt/ttcmap.c | 358 | ||||
-rw-r--r-- | src/sfnt/ttload.c | 117 | ||||
-rw-r--r-- | src/sfnt/ttsbit.c | 169 |
7 files changed, 594 insertions, 241 deletions
diff --git a/src/sfnt/sfdriver.c b/src/sfnt/sfdriver.c index 0948ad4..5dd8449 100644 --- a/src/sfnt/sfdriver.c +++ b/src/sfnt/sfdriver.c @@ -139,9 +139,9 @@ FT_DEFINE_SERVICE_SFNT_TABLEREC( sfnt_service_sfnt_table, - (FT_SFNT_TableLoadFunc)tt_face_load_any, - (FT_SFNT_TableGetFunc) get_sfnt_table, - (FT_SFNT_TableInfoFunc)sfnt_table_info ) + (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */ + (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */ + (FT_SFNT_TableInfoFunc)sfnt_table_info ) /* table_info */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES @@ -205,8 +205,8 @@ FT_DEFINE_SERVICE_GLYPHDICTREC( sfnt_service_glyph_dict, - (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, - (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index ) + (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */ + (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index ) /* name_index */ #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ @@ -330,7 +330,7 @@ FT_DEFINE_SERVICE_PSFONTNAMEREC( sfnt_service_ps_name, - (FT_PsName_GetFunc)sfnt_get_ps_name ) + (FT_PsName_GetFunc)sfnt_get_ps_name ) /* get_ps_font_name */ /* @@ -338,7 +338,7 @@ */ FT_DEFINE_SERVICE_TTCMAPSREC( tt_service_get_cmap_info, - (TT_CMap_Info_GetFunc)tt_get_cmap_info ) + (TT_CMap_Info_GetFunc)tt_get_cmap_info ) /* get_cmap_info */ #ifdef TT_CONFIG_OPTION_BDF @@ -381,8 +381,8 @@ FT_DEFINE_SERVICE_BDFRec( sfnt_service_bdf, - (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, - (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop ) + (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */ + (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop ) /* get_property */ #endif /* TT_CONFIG_OPTION_BDF */ @@ -505,7 +505,9 @@ PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), - tt_face_get_metrics + tt_face_get_metrics, + + tt_face_get_name ) diff --git a/src/sfnt/sfntpic.h b/src/sfnt/sfntpic.h index 563d634..d99be6a 100644 --- a/src/sfnt/sfntpic.h +++ b/src/sfnt/sfntpic.h @@ -20,8 +20,6 @@ #define __SFNTPIC_H__ -FT_BEGIN_HEADER - #include FT_INTERNAL_PIC_H @@ -31,7 +29,6 @@ FT_BEGIN_HEADER #define SFNT_SERVICE_GLYPH_DICT_GET sfnt_service_glyph_dict #define SFNT_SERVICE_PS_NAME_GET sfnt_service_ps_name #define TT_SERVICE_CMAP_INFO_GET tt_service_get_cmap_info -#define SFNT_SERVICES_GET sfnt_services #define TT_CMAP_CLASSES_GET tt_cmap_classes #define SFNT_SERVICE_SFNT_TABLE_GET sfnt_service_sfnt_table #define SFNT_SERVICE_BDF_GET sfnt_service_bdf @@ -56,6 +53,8 @@ FT_BEGIN_HEADER #include "ttcmap.h" +FT_BEGIN_HEADER + typedef struct sfntModulePIC_ { FT_ServiceDescRec* sfnt_services; @@ -83,8 +82,6 @@ FT_BEGIN_HEADER ( GET_PIC( library )->sfnt_service_ps_name ) #define TT_SERVICE_CMAP_INFO_GET \ ( GET_PIC( library )->tt_service_get_cmap_info ) -#define SFNT_SERVICES_GET \ - ( GET_PIC( library )->sfnt_services ) #define TT_CMAP_CLASSES_GET \ ( GET_PIC( library )->tt_cmap_classes ) #define SFNT_SERVICE_SFNT_TABLE_GET \ @@ -102,12 +99,13 @@ FT_BEGIN_HEADER FT_Error sfnt_module_class_pic_init( FT_Library library ); + +FT_END_HEADER + #endif /* FT_CONFIG_OPTION_PIC */ /* */ -FT_END_HEADER - #endif /* __SFNTPIC_H__ */ diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c index 40c27fa..de030ea 100644 --- a/src/sfnt/sfobjs.c +++ b/src/sfnt/sfobjs.c @@ -120,27 +120,9 @@ FT_Memory memory ); - /*************************************************************************/ - /* */ - /* <Function> */ - /* tt_face_get_name */ - /* */ - /* <Description> */ - /* Returns a given ENGLISH name record in ASCII. */ - /* */ - /* <Input> */ - /* face :: A handle to the source face object. */ - /* */ - /* nameid :: The name id of the name record to return. */ - /* */ - /* <InOut> */ - /* name :: The address of a string pointer. NULL if no name is */ - /* present. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - static FT_Error + /* documentation is in sfnt.h */ + + FT_LOCAL_DEF( FT_Error ) tt_face_get_name( TT_Face face, FT_UShort nameid, FT_String** name ) @@ -469,10 +451,14 @@ woff.metaOrigLength != 0 ) ) || ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || ( woff.privOffset == 0 && woff.privLength != 0 ) ) + { + FT_ERROR(( "woff_font_open: invalid WOFF header\n" )); return FT_THROW( Invalid_Table ); + } - if ( FT_ALLOC( sfnt, woff.totalSfntSize ) || - FT_NEW( sfnt_stream ) ) + /* Don't trust `totalSfntSize' before thorough checks. */ + if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) || + FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; @@ -539,6 +525,8 @@ if ( table->Tag <= old_tag ) { FT_FRAME_EXIT(); + + FT_ERROR(( "woff_font_open: table tags are not sorted\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -573,6 +561,7 @@ sfnt_offset > woff.totalSfntSize - table->OrigLength || table->CompLength > table->OrigLength ) { + FT_ERROR(( "woff_font_open: invalid table offsets\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -598,6 +587,8 @@ if ( woff.metaOffset != woff_offset || woff.metaOffset + woff.metaLength > woff.length ) { + FT_ERROR(( "woff_font_open:" + " invalid `metadata' offset or length\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -614,6 +605,7 @@ if ( woff.privOffset != woff_offset || woff.privOffset + woff.privLength > woff.length ) { + FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -625,10 +617,19 @@ if ( sfnt_offset != woff.totalSfntSize || woff_offset != woff.length ) { + FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } + /* Now use `totalSfntSize'. */ + if ( FT_REALLOC( sfnt, + 12 + woff.num_tables * 16UL, + woff.totalSfntSize ) ) + goto Exit; + + sfnt_header = sfnt + 12; + /* Write the tables. */ for ( nn = 0; nn < woff.num_tables; nn++ ) @@ -669,6 +670,7 @@ goto Exit; if ( output_len != table->OrigLength ) { + FT_ERROR(( "woff_font_open: compressed table length mismatch\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -839,13 +841,14 @@ FT_LOCAL_DEF( FT_Error ) sfnt_init_face( FT_Stream stream, TT_Face face, - FT_Int face_index, + FT_Int face_instance_index, FT_Int num_params, FT_Parameter* params ) { - FT_Error error; - FT_Library library = face->root.driver->root.library; - SFNT_Service sfnt; + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Service sfnt; + FT_Int face_index; /* for now, parameters are unused */ @@ -878,22 +881,97 @@ /* Stream may have changed in sfnt_open_font. */ stream = face->root.stream; - FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index )); + FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_instance_index )); - if ( face_index < 0 ) - face_index = 0; + face_index = FT_ABS( face_instance_index ) & 0xFFFF; if ( face_index >= face->ttc_header.count ) - return FT_THROW( Invalid_Argument ); + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + face_index = 0; + } if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) return error; - /* check that we have a valid TrueType file */ + /* check whether we have a valid TrueType file */ error = sfnt->load_font_dir( face, stream ); if ( error ) return error; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_ULong fvar_len; + + FT_ULong version; + FT_ULong offset; + + FT_UShort num_axes; + FT_UShort axis_size; + FT_UShort num_instances; + FT_UShort instance_size; + + FT_Int instance_index; + + + instance_index = FT_ABS( face_instance_index ) >> 16; + + /* test whether current face is a GX font with named instances */ + if ( face->goto_table( face, TTAG_fvar, stream, &fvar_len ) || + fvar_len < 20 || + FT_READ_ULONG( version ) || + FT_READ_USHORT( offset ) || + FT_STREAM_SKIP( 2 ) || + FT_READ_USHORT( num_axes ) || + FT_READ_USHORT( axis_size ) || + FT_READ_USHORT( num_instances ) || + FT_READ_USHORT( instance_size ) ) + { + version = 0; + offset = 0; + num_axes = 0; + axis_size = 0; + num_instances = 0; + instance_size = 0; + } + + /* check that the data is bound by the table length; */ + /* based on similar code in function `TT_Get_MM_Var' */ + if ( version != 0x00010000UL || + axis_size != 20 || + num_axes > 0x3FFE || + instance_size != 4 + 4 * num_axes || + num_instances > 0x7EFF || + offset + + axis_size * num_axes + + instance_size * num_instances > fvar_len ) + num_instances = 0; + + /* we support at most 2^15 - 1 instances */ + if ( num_instances >= ( 1U << 15 ) - 1 ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + num_instances = 0; + } + + /* instance indices in `face_instance_index' start with index 1, */ + /* thus `>' and not `>=' */ + if ( instance_index > num_instances ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + num_instances = 0; + } + + face->root.style_flags = (FT_Long)num_instances << 16; + } +#endif + face->root.num_faces = face->ttc_header.count; face->root.face_index = face_index; @@ -946,7 +1024,7 @@ FT_LOCAL_DEF( FT_Error ) sfnt_load_face( FT_Stream stream, TT_Face face, - FT_Int face_index, + FT_Int face_instance_index, FT_Int num_params, FT_Parameter* params ) { @@ -962,7 +1040,7 @@ SFNT_Service sfnt = (SFNT_Service)face->sfnt; - FT_UNUSED( face_index ); + FT_UNUSED( face_instance_index ); /* Check parameters */ @@ -1284,7 +1362,7 @@ flags |= FT_STYLE_FLAG_ITALIC; } - root->style_flags = flags; + root->style_flags |= flags; /*********************************************************************/ /* */ diff --git a/src/sfnt/sfobjs.h b/src/sfnt/sfobjs.h index 77c7d92..455f867 100644 --- a/src/sfnt/sfobjs.h +++ b/src/sfnt/sfobjs.h @@ -31,20 +31,25 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) sfnt_init_face( FT_Stream stream, TT_Face face, - FT_Int face_index, + FT_Int face_instance_index, FT_Int num_params, FT_Parameter* params ); FT_LOCAL( FT_Error ) sfnt_load_face( FT_Stream stream, TT_Face face, - FT_Int face_index, + FT_Int face_instance_index, FT_Int num_params, FT_Parameter* params ); FT_LOCAL( void ) sfnt_done_face( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ); + FT_END_HEADER diff --git a/src/sfnt/ttcmap.c b/src/sfnt/ttcmap.c index 815ee7c..2b1337f 100644 --- a/src/sfnt/ttcmap.c +++ b/src/sfnt/ttcmap.c @@ -51,6 +51,13 @@ #define TT_NEXT_ULONG FT_NEXT_ULONG + /* Too large glyph index return values are caught in `FT_Get_Char_Index' */ + /* and `FT_Get_Next_Char' (the latter calls the internal `next' function */ + /* again in this case). To mark character code return values as invalid */ + /* it is sufficient to set the corresponding glyph index return value to */ + /* zero. */ + + FT_CALLBACK_DEF( FT_Error ) tt_cmap_init( TT_CMap cmap, FT_Byte* table ) @@ -199,7 +206,7 @@ /***** FORMAT 2 *****/ /***** *****/ /***** This is used for certain CJK encodings that encode text in a *****/ - /***** mixed 8/16 bits encoding along the following lines: *****/ + /***** mixed 8/16 bits encoding along the following lines. *****/ /***** *****/ /***** * Certain byte values correspond to an 8-bit character code *****/ /***** (typically in the range 0..127 for ASCII compatibility). *****/ @@ -209,19 +216,19 @@ /***** second byte of a 2-byte character). *****/ /***** *****/ /***** The following charmap lookup and iteration functions all *****/ - /***** assume that the value "charcode" correspond to following: *****/ + /***** assume that the value `charcode' fulfills the following. *****/ /***** *****/ - /***** - For one byte characters, "charcode" is simply the *****/ + /***** - For one byte characters, `charcode' is simply the *****/ /***** character code. *****/ /***** *****/ - /***** - For two byte characters, "charcode" is the 2-byte *****/ - /***** character code in big endian format. More exactly: *****/ + /***** - For two byte characters, `charcode' is the 2-byte *****/ + /***** character code in big endian format. More precisely: *****/ /***** *****/ /***** (charcode >> 8) is the first byte value *****/ /***** (charcode & 0xFF) is the second byte value *****/ /***** *****/ - /***** Note that not all values of "charcode" are valid according *****/ - /***** to these rules, and the function moderately check the *****/ + /***** Note that not all values of `charcode' are valid according *****/ + /***** to these rules, and the function moderately checks the *****/ /***** arguments. *****/ /***** *****/ /*************************************************************************/ @@ -249,7 +256,7 @@ /* table, i.e., it is the corresponding sub-header index multiplied */ /* by 8. */ /* */ - /* Each sub-header has the following format: */ + /* Each sub-header has the following format. */ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ @@ -264,11 +271,11 @@ /* according to the specification. */ /* */ /* If a character code is contained within a given sub-header, then */ - /* mapping it to a glyph index is done as follows: */ + /* mapping it to a glyph index is done as follows. */ /* */ /* * The value of `offset' is read. This is a _byte_ distance from the */ /* location of the `offset' field itself into a slice of the */ - /* `glyph_ids' table. Let's call it `slice' (it is a USHORT[] too). */ + /* `glyph_ids' table. Let's call it `slice' (it is a USHORT[], too). */ /* */ /* * The value `slice[char.lo - first]' is read. If it is 0, there is */ /* no glyph for the charcode. Otherwise, the value of `delta' is */ @@ -326,7 +333,7 @@ FT_ASSERT( p == table + 518 ); subs = p; - glyph_ids = subs + (max_subs + 1) * 8; + glyph_ids = subs + ( max_subs + 1 ) * 8; if ( glyph_ids > valid->limit ) FT_INVALID_TOO_SHORT; @@ -436,6 +443,7 @@ } result = sub; } + Exit: return result; } @@ -475,6 +483,7 @@ result = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; } } + return result; } @@ -765,7 +774,7 @@ if ( charcode < cmap->cur_start ) charcode = cmap->cur_start; - for ( ;; ) + for (;;) { FT_Byte* values = cmap->cur_values; FT_UInt end = cmap->cur_end; @@ -973,7 +982,7 @@ /* segment if it contains only a single character. */ /* */ /* We thus omit the test here, delaying it to the */ - /* routines which actually access the cmap. */ + /* routines that actually access the cmap. */ else if ( n != num_segs - 1 || !( start == 0xFFFFU && end == 0xFFFFU ) ) { @@ -1026,12 +1035,17 @@ FT_UInt32* pcharcode, FT_Bool next ) { + TT_Face face = (TT_Face)cmap->cmap.charmap.face; + FT_Byte* limit = face->cmap_table + face->cmap_size; + + FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt i, num_segs; FT_UInt32 charcode = *pcharcode; FT_UInt gindex = 0; FT_Byte* p; + FT_Byte* q; p = cmap->data + 6; @@ -1045,65 +1059,106 @@ if ( next ) charcode++; + if ( charcode > 0xFFFFU ) + return 0; + /* linear search */ - for ( ; charcode <= 0xFFFFU; charcode++ ) - { - FT_Byte* q; + p = cmap->data + 14; /* ends table */ + q = cmap->data + 16 + num_segs2; /* starts table */ + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); - p = cmap->data + 14; /* ends table */ - q = cmap->data + 16 + num_segs2; /* starts table */ + if ( charcode < start ) + { + if ( next ) + charcode = start; + else + break; + } - for ( i = 0; i < num_segs; i++ ) + Again: + if ( charcode <= end ) { - end = TT_NEXT_USHORT( p ); - start = TT_NEXT_USHORT( q ); + FT_Byte* r; + - if ( charcode >= start && charcode <= end ) + r = q - 2 + num_segs2; + delta = TT_PEEK_SHORT( r ); + r += num_segs2; + offset = TT_PEEK_USHORT( r ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( i >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) { - p = q - 2 + num_segs2; - delta = TT_PEEK_SHORT( p ); - p += num_segs2; - offset = TT_PEEK_USHORT( p ); - - /* some fonts have an incorrect last segment; */ - /* we have to catch it */ - if ( i >= num_segs - 1 && - start == 0xFFFFU && end == 0xFFFFU ) + if ( offset && r + offset + 2 > limit ) { - TT_Face face = (TT_Face)cmap->cmap.charmap.face; - FT_Byte* limit = face->cmap_table + face->cmap_size; + delta = 1; + offset = 0; + } + } + if ( offset == 0xFFFFU ) + continue; - if ( offset && p + offset + 2 > limit ) - { - delta = 1; - offset = 0; - } - } + if ( offset ) + { + r += offset + ( charcode - start ) * 2; - if ( offset == 0xFFFFU ) + /* if r > limit, the whole segment is invalid */ + if ( next && r > limit ) continue; - if ( offset ) + gindex = TT_PEEK_USHORT( r ); + if ( gindex ) { - p += offset + ( charcode - start ) * 2; - gindex = TT_PEEK_USHORT( p ); - if ( gindex != 0 ) - gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + gindex = 0; } - else - gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + } + else + { + gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; - break; + if ( next && gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + + else + continue; + } + } + + if ( next && !gindex ) + { + if ( charcode >= 0xFFFFU ) + break; + + charcode++; + goto Again; } - } - if ( !next || gindex ) break; + } } - if ( next && gindex ) + if ( next ) *pcharcode = charcode; return gindex; @@ -1310,7 +1365,6 @@ /* if `charcode' is not in any segment, then `mid' is */ /* the segment nearest to `charcode' */ - /* */ if ( charcode > end ) { @@ -1443,7 +1497,7 @@ /* */ /* NAME OFFSET TYPE DESCRIPTION */ /* */ - /* format 0 USHORT must be 4 */ + /* format 0 USHORT must be 6 */ /* length 2 USHORT table length in bytes */ /* language 4 USHORT Mac language code */ /* */ @@ -1511,6 +1565,7 @@ p += 2 * idx; result = TT_PEEK_USHORT( p ); } + return result; } @@ -1531,7 +1586,7 @@ if ( char_code >= 0x10000UL ) - goto Exit; + return 0; if ( char_code < start ) char_code = start; @@ -1547,10 +1602,13 @@ result = char_code; break; } + + if ( char_code >= 0xFFFFU ) + return 0; + char_code++; } - Exit: *pchar_code = result; return gindex; } @@ -1602,7 +1660,7 @@ /***** *****/ /***** The purpose of this format is to easily map UTF-16 text to *****/ /***** glyph indices. Basically, the `char_code' must be in one of *****/ - /***** the following formats: *****/ + /***** the following formats. *****/ /***** *****/ /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ /***** Area (i.e. U+D800-U+DFFF). *****/ @@ -1615,7 +1673,7 @@ /***** The `is32' table embedded in the charmap indicates whether a *****/ /***** given 16-bit value is in the surrogates area or not. *****/ /***** *****/ - /***** So, for any given `char_code', we can assert the following: *****/ + /***** So, for any given `char_code', we can assert the following. *****/ /***** *****/ /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ /***** *****/ @@ -1770,7 +1828,10 @@ if ( char_code <= end ) { - result = (FT_UInt)( start_id + char_code - start ); + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + return 0; + + result = (FT_UInt)( start_id + ( char_code - start ) ); break; } } @@ -1782,8 +1843,9 @@ tt_cmap8_char_next( TT_CMap cmap, FT_UInt32 *pchar_code ) { + FT_Face face = cmap->cmap.charmap.face; FT_UInt32 result = 0; - FT_UInt32 char_code = *pchar_code + 1; + FT_UInt32 char_code; FT_UInt gindex = 0; FT_Byte* table = cmap->data; FT_Byte* p = table + 8204; @@ -1791,6 +1853,11 @@ FT_UInt32 start, end, start_id; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + p = table + 8208; for ( ; num_groups > 0; num_groups-- ) @@ -1802,18 +1869,38 @@ if ( char_code < start ) char_code = start; + Again: if ( char_code <= end ) { - gindex = (FT_UInt)( char_code - start + start_id ); - if ( gindex != 0 ) + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; + + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) { - result = char_code; - goto Exit; + if ( char_code >= 0xFFFFFFFFUL ) + break; + + char_code++; + goto Again; } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + { + gindex = 0; + continue; + } + + result = char_code; + break; } } - Exit: *pchar_code = result; return gindex; } @@ -1930,14 +2017,20 @@ FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); FT_UInt32 count = TT_NEXT_ULONG( p ); - FT_UInt32 idx = (FT_ULong)( char_code - start ); + FT_UInt32 idx; + + if ( char_code < start ) + return 0; + + idx = char_code - start; if ( idx < count ) { p += 2 * idx; result = TT_PEEK_USHORT( p ); } + return result; } @@ -1947,7 +2040,7 @@ FT_UInt32 *pchar_code ) { FT_Byte* table = cmap->data; - FT_UInt32 char_code = *pchar_code + 1; + FT_UInt32 char_code; FT_UInt gindex = 0; FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); @@ -1955,10 +2048,15 @@ FT_UInt32 idx; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + if ( char_code < start ) char_code = start; - idx = (FT_UInt32)( char_code - start ); + idx = char_code - start; p += 2 * idx; for ( ; idx < count; idx++ ) @@ -1966,6 +2064,10 @@ gindex = TT_NEXT_USHORT( p ); if ( gindex != 0 ) break; + + if ( char_code >= 0xFFFFFFFFUL ) + return 0; + char_code++; } @@ -2134,6 +2236,7 @@ static void tt_cmap12_next( TT_CMap12 cmap ) { + FT_Face face = cmap->cmap.cmap.charmap.face; FT_Byte* p; FT_ULong start, end, start_id, char_code; FT_ULong n; @@ -2155,18 +2258,38 @@ if ( char_code < start ) char_code = start; - for ( ; char_code <= end; char_code++ ) + Again: + if ( char_code <= end ) { - gindex = (FT_UInt)( start_id + char_code - start ); + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; - if ( gindex ) + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) { - cmap->cur_charcode = char_code;; - cmap->cur_gindex = gindex; - cmap->cur_group = n; + if ( char_code >= 0xFFFFFFFFUL ) + goto Fail; - return; + char_code++; + goto Again; + } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + { + gindex = 0; + continue; } + + cmap->cur_charcode = char_code; + cmap->cur_gindex = gindex; + cmap->cur_group = n; + + return; } } @@ -2196,7 +2319,12 @@ end = 0xFFFFFFFFUL; if ( next ) + { + if ( char_code >= 0xFFFFFFFFUL ) + return 0; + char_code++; + } min = 0; max = num_groups; @@ -2217,20 +2345,24 @@ else { start_id = TT_PEEK_ULONG( p ); - gindex = (FT_UInt)( start_id + char_code - start ); + /* reject invalid glyph index */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + gindex = 0; + else + gindex = (FT_UInt)( start_id + ( char_code - start ) ); break; } } if ( next ) { + FT_Face face = cmap->cmap.charmap.face; TT_CMap12 cmap12 = (TT_CMap12)cmap; /* if `char_code' is not in any group, then `mid' is */ /* the group nearest to `char_code' */ - /* */ if ( char_code > end ) { @@ -2243,6 +2375,9 @@ cmap12->cur_charcode = char_code; cmap12->cur_group = mid; + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + if ( !gindex ) { tt_cmap12_next( cmap12 ); @@ -2253,8 +2388,7 @@ else cmap12->cur_gindex = gindex; - if ( gindex ) - *pchar_code = cmap12->cur_charcode; + *pchar_code = cmap12->cur_charcode; } return gindex; @@ -2274,11 +2408,8 @@ FT_UInt32 *pchar_code ) { TT_CMap12 cmap12 = (TT_CMap12)cmap; - FT_ULong gindex; - + FT_UInt gindex; - if ( cmap12->cur_charcode >= 0xFFFFFFFFUL ) - return 0; /* no need to search */ if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) @@ -2286,11 +2417,8 @@ tt_cmap12_next( cmap12 ); if ( cmap12->valid ) { - gindex = cmap12->cur_gindex; - - /* XXX: check cur_charcode overflow is expected */ - if ( gindex ) - *pchar_code = (FT_UInt32)cmap12->cur_charcode; + gindex = cmap12->cur_gindex; + *pchar_code = (FT_UInt32)cmap12->cur_charcode; } else gindex = 0; @@ -2298,8 +2426,7 @@ else gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); - /* XXX: check gindex overflow is expected */ - return (FT_UInt32)gindex; + return gindex; } @@ -2458,6 +2585,7 @@ static void tt_cmap13_next( TT_CMap13 cmap ) { + FT_Face face = cmap->cmap.cmap.charmap.face; FT_Byte* p; FT_ULong start, end, glyph_id, char_code; FT_ULong n; @@ -2483,9 +2611,9 @@ { gindex = (FT_UInt)glyph_id; - if ( gindex ) + if ( gindex && gindex < (FT_UInt)face->num_glyphs ) { - cmap->cur_charcode = char_code;; + cmap->cur_charcode = char_code; cmap->cur_gindex = gindex; cmap->cur_group = n; @@ -2520,7 +2648,12 @@ end = 0xFFFFFFFFUL; if ( next ) + { + if ( char_code >= 0xFFFFFFFFUL ) + return 0; + char_code++; + } min = 0; max = num_groups; @@ -2548,6 +2681,7 @@ if ( next ) { + FT_Face face = cmap->cmap.charmap.face; TT_CMap13 cmap13 = (TT_CMap13)cmap; @@ -2565,6 +2699,9 @@ cmap13->cur_charcode = char_code; cmap13->cur_group = mid; + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + if ( !gindex ) { tt_cmap13_next( cmap13 ); @@ -2575,8 +2712,7 @@ else cmap13->cur_gindex = gindex; - if ( gindex ) - *pchar_code = cmap13->cur_charcode; + *pchar_code = cmap13->cur_charcode; } return gindex; @@ -2599,18 +2735,14 @@ FT_UInt gindex; - if ( cmap13->cur_charcode >= 0xFFFFFFFFUL ) - return 0; - /* no need to search */ if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) { tt_cmap13_next( cmap13 ); if ( cmap13->valid ) { - gindex = cmap13->cur_gindex; - if ( gindex ) - *pchar_code = cmap13->cur_charcode; + gindex = cmap13->cur_gindex; + *pchar_code = cmap13->cur_charcode; } else gindex = 0; @@ -2836,11 +2968,16 @@ /* through the normal Unicode cmap, no GIDs, just check order) */ if ( defOff != 0 ) { - FT_Byte* defp = table + defOff; - FT_ULong numRanges = TT_NEXT_ULONG( defp ); + FT_Byte* defp = table + defOff; + FT_ULong numRanges; FT_ULong i; - FT_ULong lastBase = 0; + FT_ULong lastBase = 0; + + + if ( defp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + numRanges = TT_NEXT_ULONG( defp ); /* defp + numRanges * 4 > valid->limit ? */ if ( numRanges > (FT_ULong)( valid->limit - defp ) / 4 ) @@ -2865,13 +3002,18 @@ /* and the non-default table (these glyphs are specified here) */ if ( nondefOff != 0 ) { - FT_Byte* ndp = table + nondefOff; - FT_ULong numMappings = TT_NEXT_ULONG( ndp ); - FT_ULong i, lastUni = 0; + FT_Byte* ndp = table + nondefOff; + FT_ULong numMappings; + FT_ULong i, lastUni = 0; + + + if ( ndp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + numMappings = TT_NEXT_ULONG( ndp ); - /* numMappings * 4 > (FT_ULong)( valid->limit - ndp ) ? */ - if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 4 ) + /* numMappings * 5 > (FT_ULong)( valid->limit - ndp ) ? */ + if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 5 ) FT_INVALID_TOO_SHORT; for ( i = 0; i < numMappings; ++i ) @@ -3316,7 +3458,7 @@ ni = 1; i = 0; - for ( ;; ) + for (;;) { if ( nuni > duni + dcnt ) { diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c index ad2975d..c1bd7f0 100644 --- a/src/sfnt/ttload.c +++ b/src/sfnt/ttload.c @@ -151,7 +151,8 @@ /* Here, we */ /* */ - /* - check that `num_tables' is valid (and adjust it if necessary) */ + /* - check that `num_tables' is valid (and adjust it if necessary); */ + /* also return the number of valid table entries */ /* */ /* - look for a `head' table, check its size, and parse it to check */ /* whether its `magic' field is correctly set */ @@ -167,7 +168,8 @@ /* */ static FT_Error check_table_dir( SFNT_Header sfnt, - FT_Stream stream ) + FT_Stream stream, + FT_UShort* valid ) { FT_Error error; FT_UShort nn, valid_entries = 0; @@ -209,7 +211,10 @@ /* we ignore invalid tables */ if ( table.Offset > stream->size ) + { + FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); continue; + } else if ( table.Length > stream->size - table.Offset ) { /* Some tables have such a simple structure that clipping its */ @@ -273,11 +278,11 @@ has_meta = 1; } - sfnt->num_tables = valid_entries; + *valid = valid_entries; - if ( sfnt->num_tables == 0 ) + if ( !valid_entries ) { - FT_TRACE2(( "check_table_dir: no tables found\n" )); + FT_TRACE2(( "check_table_dir: no valid tables found\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } @@ -333,8 +338,7 @@ SFNT_HeaderRec sfnt; FT_Error error; FT_Memory memory = stream->memory; - TT_TableRec* entry; - FT_Int nn; + FT_UShort nn, valid_entries; static const FT_Frame_Field offset_table_fields[] = { @@ -375,85 +379,114 @@ if ( sfnt.format_tag != TTAG_OTTO ) { /* check first */ - error = check_table_dir( &sfnt, stream ); + error = check_table_dir( &sfnt, stream, &valid_entries ); if ( error ) { FT_TRACE2(( "tt_face_load_font_dir:" " invalid table directory for TrueType\n" )); - goto Exit; } } + else + valid_entries = sfnt.num_tables; - face->num_tables = sfnt.num_tables; + face->num_tables = valid_entries; face->format_tag = sfnt.format_tag; if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) goto Exit; - if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || - FT_FRAME_ENTER( face->num_tables * 16L ) ) + if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || + FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) goto Exit; - entry = face->dir_tables; - FT_TRACE2(( "\n" " tag offset length checksum\n" " ----------------------------------\n" )); + valid_entries = 0; for ( nn = 0; nn < sfnt.num_tables; nn++ ) { - entry->Tag = FT_GET_TAG4(); - entry->CheckSum = FT_GET_ULONG(); - entry->Offset = FT_GET_ULONG(); - entry->Length = FT_GET_ULONG(); + TT_TableRec entry; + FT_UShort i; + FT_Bool duplicate; + + + entry.Tag = FT_GET_TAG4(); + entry.CheckSum = FT_GET_ULONG(); + entry.Offset = FT_GET_ULONG(); + entry.Length = FT_GET_ULONG(); /* ignore invalid tables that can't be sanitized */ - if ( entry->Offset > stream->size ) + if ( entry.Offset > stream->size ) continue; - else if ( entry->Length > stream->size - entry->Offset ) + else if ( entry.Length > stream->size - entry.Offset ) { - if ( entry->Tag == TTAG_hmtx || - entry->Tag == TTAG_vmtx ) + if ( entry.Tag == TTAG_hmtx || + entry.Tag == TTAG_vmtx ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_ULong old_length = entry->Length; + FT_ULong old_length = entry.Length; #endif /* make metrics table length a multiple of 4 */ - entry->Length = ( stream->size - entry->Offset ) & ~3U; + entry.Length = ( stream->size - entry.Offset ) & ~3U; FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" - " (sanitized; original length %08lx)\n", - (FT_Char)( entry->Tag >> 24 ), - (FT_Char)( entry->Tag >> 16 ), - (FT_Char)( entry->Tag >> 8 ), - (FT_Char)( entry->Tag ), - entry->Offset, - entry->Length, - entry->CheckSum, + " (sanitized; original length %08lx)", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum, old_length )); - entry++; } else continue; } +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum )); +#endif + + /* ignore duplicate tables – the first one wins */ + duplicate = 0; + for ( i = 0; i < valid_entries; i++ ) + { + if ( face->dir_tables[i].Tag == entry.Tag ) + { + duplicate = 1; + break; + } + } + if ( duplicate ) + { + FT_TRACE2(( " (duplicate, ignored)\n" )); + continue; + } else { - FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx\n", - (FT_Char)( entry->Tag >> 24 ), - (FT_Char)( entry->Tag >> 16 ), - (FT_Char)( entry->Tag >> 8 ), - (FT_Char)( entry->Tag ), - entry->Offset, - entry->Length, - entry->CheckSum )); - entry++; + FT_TRACE2(( "\n" )); + + /* we finally have a valid entry */ + face->dir_tables[valid_entries++] = entry; } } + /* final adjustment to number of tables */ + face->num_tables = valid_entries; + FT_FRAME_EXIT(); FT_TRACE2(( "table directory loaded\n\n" )); diff --git a/src/sfnt/ttsbit.c b/src/sfnt/ttsbit.c index 143f276..09260b8 100644 --- a/src/sfnt/ttsbit.c +++ b/src/sfnt/ttsbit.c @@ -104,7 +104,8 @@ version = FT_NEXT_LONG( p ); num_strikes = FT_NEXT_ULONG( p ); - if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL ) + if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL && + ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00030000UL ) { error = FT_THROW( Unknown_File_Format ); goto Exit; @@ -247,6 +248,8 @@ case TT_SBIT_TABLE_TYPE_CBLC: { FT_Byte* strike; + FT_Char max_before_bl; + FT_Char min_after_bl; strike = face->sbit_table + 8 + strike_index * 48; @@ -254,26 +257,83 @@ metrics->x_ppem = (FT_UShort)strike[44]; metrics->y_ppem = (FT_UShort)strike[45]; - metrics->ascender = (FT_Char)strike[16] << 6; /* hori.ascender */ - metrics->descender = (FT_Char)strike[17] << 6; /* hori.descender */ - metrics->height = metrics->ascender - metrics->descender; + metrics->ascender = (FT_Char)strike[16] * 64; /* hori.ascender */ + metrics->descender = (FT_Char)strike[17] * 64; /* hori.descender */ + + /* Due to fuzzy wording in the EBLC documentation, we find both */ + /* positive and negative values for `descender'. Additionally, */ + /* many fonts have both `ascender' and `descender' set to zero */ + /* (which is definitely wrong). MS Windows simply ignores all */ + /* those values... For these reasons we apply some heuristics */ + /* to get a reasonable, non-zero value for the height. */ + + max_before_bl = (FT_Char)strike[24]; + min_after_bl = (FT_Char)strike[25]; + + if ( metrics->descender > 0 ) + { + /* compare sign of descender with `min_after_bl' */ + if ( min_after_bl < 0 ) + metrics->descender = -metrics->descender; + } + + else if ( metrics->descender == 0 ) + { + if ( metrics->ascender == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid ascender and descender\n" + " " + " values for strike (%d, %d)\n", + metrics->x_ppem, metrics->y_ppem )); + + /* sanitize buggy ascender and descender values */ + if ( max_before_bl || min_after_bl ) + { + metrics->ascender = max_before_bl * 64; + metrics->descender = min_after_bl * 64; + } + else + { + metrics->ascender = metrics->y_ppem * 64; + metrics->descender = 0; + } + } + } + +#if 0 + else + ; /* if we have a negative descender, simply use it */ +#endif + + metrics->height = metrics->ascender - metrics->descender; + if ( metrics->height == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid height value\n" + " " + " for strike (%d, %d)\n", + metrics->x_ppem, metrics->y_ppem )); + metrics->height = metrics->y_ppem * 64; + metrics->descender = metrics->ascender - metrics->height; + } /* Is this correct? */ metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */ strike[18] + /* max_width */ (FT_Char)strike[23] /* min_advance_SB */ - ) << 6; + ) * 64; return FT_Err_Ok; } case TT_SBIT_TABLE_TYPE_SBIX: { FT_Stream stream = face->root.stream; - FT_UInt offset, upem; - FT_UShort ppem, resolution; + FT_UInt offset; + FT_UShort upem, ppem, resolution; TT_HoriHeader *hori; FT_ULong table_size; - FT_Pos ppem_, upem_; /* to reduce casts */ + FT_Pos ppem_; /* to reduce casts */ FT_Error error; FT_Byte* p; @@ -307,14 +367,16 @@ metrics->y_ppem = ppem; ppem_ = (FT_Pos)ppem; - upem_ = (FT_Pos)upem; - metrics->ascender = ppem_ * hori->Ascender * 64 / upem_; - metrics->descender = ppem_ * hori->Descender * 64 / upem_; - metrics->height = ppem_ * ( hori->Ascender - - hori->Descender + - hori->Line_Gap ) * 64 / upem_; - metrics->max_advance = ppem_ * hori->advance_Width_Max * 64 / upem_; + metrics->ascender = + FT_MulDiv( hori->Ascender, ppem_ * 64, upem ); + metrics->descender = + FT_MulDiv( hori->Descender, ppem_ * 64, upem ); + metrics->height = + FT_MulDiv( hori->Ascender - hori->Descender + hori->Line_Gap, + ppem_ * 64, upem ); + metrics->max_advance = + FT_MulDiv( hori->advance_Width_Max, ppem_ * 64, upem ); return error; } @@ -547,13 +609,16 @@ tt_sbit_decoder_load_image( TT_SBitDecoder decoder, FT_UInt glyph_index, FT_Int x_pos, - FT_Int y_pos ); + FT_Int y_pos, + FT_UInt recurse_count ); - typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, - FT_Byte* p, - FT_Byte* plimit, - FT_Int x_pos, - FT_Int y_pos ); + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( + TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ); static FT_Error @@ -561,7 +626,8 @@ FT_Byte* p, FT_Byte* limit, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { FT_Error error = FT_Err_Ok; FT_Byte* line; @@ -569,6 +635,8 @@ FT_UInt bit_height, bit_width; FT_Bitmap* bitmap; + FT_UNUSED( recurse_count ); + /* check that we can write the glyph into the bitmap */ bitmap = decoder->bitmap; @@ -700,7 +768,8 @@ FT_Byte* p, FT_Byte* limit, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { FT_Error error = FT_Err_Ok; FT_Byte* line; @@ -709,6 +778,8 @@ FT_Bitmap* bitmap; FT_UShort rval; + FT_UNUSED( recurse_count ); + /* check that we can write the glyph into the bitmap */ bitmap = decoder->bitmap; @@ -738,6 +809,12 @@ goto Exit; } + if ( !line_bits || !height ) + { + /* nothing to do */ + goto Exit; + } + /* now do the blit */ /* adjust `line' to point to the first byte of the bitmap */ @@ -824,7 +901,8 @@ FT_Byte* p, FT_Byte* limit, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { FT_Error error = FT_Err_Ok; FT_UInt num_components, nn; @@ -858,8 +936,11 @@ /* NB: a recursive call */ - error = tt_sbit_decoder_load_image( decoder, gindex, - x_pos + dx, y_pos + dy ); + error = tt_sbit_decoder_load_image( decoder, + gindex, + x_pos + dx, + y_pos + dy, + recurse_count + 1 ); if ( error ) break; } @@ -891,11 +972,14 @@ FT_Byte* p, FT_Byte* limit, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { FT_Error error = FT_Err_Ok; FT_ULong png_len; + FT_UNUSED( recurse_count ); + if ( limit - p < 4 ) { @@ -937,7 +1021,8 @@ FT_ULong glyph_start, FT_ULong glyph_size, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { FT_Error error; FT_Stream stream = decoder->stream; @@ -947,7 +1032,8 @@ /* seek into the EBDT table now */ - if ( glyph_start + glyph_size > decoder->ebdt_size ) + if ( !glyph_size || + glyph_start + glyph_size > decoder->ebdt_size ) { error = FT_THROW( Invalid_Argument ); goto Exit; @@ -1063,7 +1149,7 @@ goto Fail; } - error = loader( decoder, p, p_limit, x_pos, y_pos ); + error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count ); } Fail: @@ -1078,13 +1164,9 @@ tt_sbit_decoder_load_image( TT_SBitDecoder decoder, FT_UInt glyph_index, FT_Int x_pos, - FT_Int y_pos ) + FT_Int y_pos, + FT_UInt recurse_count ) { - /* - * First, we find the correct strike range that applies to this - * glyph index. - */ - FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; FT_Byte* p_limit = decoder->eblc_limit; FT_ULong num_ranges = decoder->strike_index_count; @@ -1092,6 +1174,17 @@ FT_ULong image_start = 0, image_end = 0, image_offset; + /* arbitrary recursion limit */ + if ( recurse_count > 100 ) + { + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " recursion depth exceeded\n" )); + goto Failure; + } + + + /* First, we find the correct strike range that applies to this */ + /* glyph index. */ for ( ; num_ranges > 0; num_ranges-- ) { start = FT_NEXT_USHORT( p ); @@ -1256,7 +1349,8 @@ image_start, image_end, x_pos, - y_pos ); + y_pos, + recurse_count ); Failure: return FT_THROW( Invalid_Table ); @@ -1419,6 +1513,7 @@ error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, + 0, 0 ); tt_sbit_decoder_done( decoder ); } |