| /**************************************************************************** |
| * |
| * cffparse.c |
| * |
| * CFF token stream parser (body) |
| * |
| * Copyright (C) 1996-2022 by |
| * David Turner, Robert Wilhelm, and Werner Lemberg. |
| * |
| * This file is part of the FreeType project, and may only be used, |
| * modified, and distributed under the terms of the FreeType project |
| * license, LICENSE.TXT. By continuing to use, modify, or distribute |
| * this file you indicate that you have read the license and |
| * understand and accept it fully. |
| * |
| */ |
| |
| |
| #include "cffparse.h" |
| #include <freetype/internal/ftstream.h> |
| #include <freetype/internal/ftdebug.h> |
| #include <freetype/internal/ftcalc.h> |
| #include <freetype/internal/psaux.h> |
| #include <freetype/ftlist.h> |
| |
| #include "cfferrs.h" |
| #include "cffload.h" |
| |
| |
| /************************************************************************** |
| * |
| * The macro FT_COMPONENT is used in trace mode. It is an implicit |
| * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
| * messages during execution. |
| */ |
| #undef FT_COMPONENT |
| #define FT_COMPONENT cffparse |
| |
| |
| 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_ZERO( parser ); |
| |
| #if 0 |
| parser->top = parser->stack; |
| #endif |
| 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_QNEW_ARRAY( parser->stack, stackSize ) ) |
| { |
| FT_FREE( parser->stack ); |
| goto Exit; |
| } |
| |
| parser->stackSize = stackSize; |
| parser->top = parser->stack; /* empty stack */ |
| |
| Exit: |
| return error; |
| } |
| |
| |
| #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
| static void |
| finalize_t2_strings( FT_Memory memory, |
| void* data, |
| void* user ) |
| { |
| CFF_T2_String t2 = (CFF_T2_String)data; |
| |
| |
| FT_UNUSED( user ); |
| |
| memory->free( memory, t2->start ); |
| memory->free( memory, data ); |
| } |
| #endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ |
| |
| |
| FT_LOCAL_DEF( void ) |
| cff_parser_done( CFF_Parser parser ) |
| { |
| FT_Memory memory = parser->library->memory; /* for FT_FREE */ |
| |
| |
| FT_FREE( parser->stack ); |
| |
| #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
| FT_List_Finalize( &parser->t2_strings, |
| finalize_t2_strings, |
| memory, |
| NULL ); |
| #endif |
| } |
| |
| |
| /* Assuming `first >= last'. */ |
| |
| static FT_Error |
| cff_parser_within_limits( CFF_Parser parser, |
| FT_Byte* first, |
| FT_Byte* last ) |
| { |
| #ifndef CFF_CONFIG_OPTION_OLD_ENGINE |
| |
| /* Fast path for regular FreeType builds with the "new" engine; */ |
| /* `first >= parser->start' can be assumed. */ |
| |
| FT_UNUSED( first ); |
| |
| return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument ); |
| |
| #else /* CFF_CONFIG_OPTION_OLD_ENGINE */ |
| |
| FT_ListNode node; |
| |
| |
| if ( first >= parser->start && |
| last < parser->limit ) |
| return FT_Err_Ok; |
| |
| node = parser->t2_strings.head; |
| |
| while ( node ) |
| { |
| CFF_T2_String t2 = (CFF_T2_String)node->data; |
| |
| |
| if ( first >= t2->start && |
| last < t2->limit ) |
| return FT_Err_Ok; |
| |
| node = node->next; |
| } |
| |
| return FT_THROW( Invalid_Argument ); |
| |
| #endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ |
| } |
| |
| |
| /* read an integer */ |
| static FT_Long |
| cff_parse_integer( CFF_Parser parser, |
| FT_Byte* start ) |
| { |
| FT_Byte* p = start; |
| FT_Int v = *p++; |
| FT_Long val = 0; |
| |
| |
| if ( v == 28 ) |
| { |
| if ( cff_parser_within_limits( parser, p, p + 1 ) ) |
| goto Bad; |
| |
| val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] ); |
| } |
| else if ( v == 29 ) |
| { |
| if ( cff_parser_within_limits( parser, p, p + 3 ) ) |
| goto Bad; |
| |
| val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) | |
| ( (FT_ULong)p[1] << 16 ) | |
| ( (FT_ULong)p[2] << 8 ) | |
| (FT_ULong)p[3] ); |
| } |
| else if ( v < 247 ) |
| { |
| val = v - 139; |
| } |
| else if ( v < 251 ) |
| { |
| if ( cff_parser_within_limits( parser, p, p ) ) |
| goto Bad; |
| |
| val = ( v - 247 ) * 256 + p[0] + 108; |
| } |
| else |
| { |
| if ( cff_parser_within_limits( parser, p, p ) ) |
| goto Bad; |
| |
| val = -( v - 251 ) * 256 - p[0] - 108; |
| } |
| |
| Exit: |
| return val; |
| |
| Bad: |
| val = 0; |
| FT_TRACE4(( "!!!END OF DATA:!!!" )); |
| goto Exit; |
| } |
| |
| |
| static const FT_Long power_tens[] = |
| { |
| 1L, |
| 10L, |
| 100L, |
| 1000L, |
| 10000L, |
| 100000L, |
| 1000000L, |
| 10000000L, |
| 100000000L, |
| 1000000000L |
| }; |
| |
| /* maximum values allowed for multiplying */ |
| /* with the corresponding `power_tens' element */ |
| static const FT_Long power_ten_limits[] = |
| { |
| FT_LONG_MAX / 1L, |
| FT_LONG_MAX / 10L, |
| FT_LONG_MAX / 100L, |
| FT_LONG_MAX / 1000L, |
| FT_LONG_MAX / 10000L, |
| FT_LONG_MAX / 100000L, |
| FT_LONG_MAX / 1000000L, |
| FT_LONG_MAX / 10000000L, |
| FT_LONG_MAX / 100000000L, |
| FT_LONG_MAX / 1000000000L, |
| }; |
| |
| |
| /* read a real */ |
| static FT_Fixed |
| cff_parse_real( CFF_Parser parser, |
| FT_Byte* start, |
| FT_Long power_ten, |
| FT_Long* scaling ) |
| { |
| FT_Byte* p = start; |
| FT_Int nib; |
| FT_UInt phase; |
| |
| FT_Long result, number, exponent; |
| FT_Int sign = 0, exponent_sign = 0, have_overflow = 0; |
| FT_Long exponent_add, integer_length, fraction_length; |
| |
| |
| if ( scaling ) |
| *scaling = 0; |
| |
| result = 0; |
| |
| number = 0; |
| exponent = 0; |
| |
| exponent_add = 0; |
| integer_length = 0; |
| fraction_length = 0; |
| |
| /* First of all, read the integer part. */ |
| phase = 4; |
| |
| for (;;) |
| { |
| /* If we entered this iteration with phase == 4, we need to */ |
| /* read a new byte. This also skips past the initial 0x1E. */ |
| if ( phase ) |
| { |
| p++; |
| |
| /* Make sure we don't read past the end. */ |
| if ( cff_parser_within_limits( parser, p, p ) ) |
| goto Bad; |
| } |
| |
| /* Get the nibble. */ |
| nib = (FT_Int)( p[0] >> phase ) & 0xF; |
| phase = 4 - phase; |
| |
| if ( nib == 0xE ) |
| sign = 1; |
| else if ( nib > 9 ) |
| break; |
| else |
| { |
| /* Increase exponent if we can't add the digit. */ |
| if ( number >= 0xCCCCCCCL ) |
| exponent_add++; |
| /* Skip leading zeros. */ |
| else if ( nib || number ) |
| { |
| integer_length++; |
| number = number * 10 + nib; |
| } |
| } |
| } |
| |
| /* Read fraction part, if any. */ |
| if ( nib == 0xA ) |
| for (;;) |
| { |
| /* If we entered this iteration with phase == 4, we need */ |
| /* to read a new byte. */ |
| if ( phase ) |
| { |
| p++; |
| |
| /* Make sure we don't read past the end. */ |
| if ( cff_parser_within_limits( parser, p, p ) ) |
| goto Bad; |
| } |
| |
| /* Get the nibble. */ |
| nib = ( p[0] >> phase ) & 0xF; |
| phase = 4 - phase; |
| if ( nib >= 10 ) |
| break; |
| |
| /* Skip leading zeros if possible. */ |
| if ( !nib && !number ) |
| exponent_add--; |
| /* Only add digit if we don't overflow. */ |
| else if ( number < 0xCCCCCCCL && fraction_length < 9 ) |
| { |
| fraction_length++; |
| number = number * 10 + nib; |
| } |
| } |
| |
| /* Read exponent, if any. */ |
| if ( nib == 12 ) |
| { |
| exponent_sign = 1; |
| nib = 11; |
| } |
| |
| if ( nib == 11 ) |
| { |
| for (;;) |
| { |
| /* If we entered this iteration with phase == 4, */ |
| /* we need to read a new byte. */ |
| if ( phase ) |
| { |
| p++; |
| |
| /* Make sure we don't read past the end. */ |
| if ( cff_parser_within_limits( parser, p, p ) ) |
| goto Bad; |
| } |
| |
| /* Get the nibble. */ |
| nib = ( p[0] >> phase ) & 0xF; |
| phase = 4 - phase; |
| if ( nib >= 10 ) |
| break; |
| |
| /* Arbitrarily limit exponent. */ |
| if ( exponent > 1000 ) |
| have_overflow = 1; |
| else |
| exponent = exponent * 10 + nib; |
| } |
| |
| if ( exponent_sign ) |
| exponent = -exponent; |
| } |
| |
| if ( !number ) |
| goto Exit; |
| |
| if ( have_overflow ) |
| { |
| if ( exponent_sign ) |
| goto Underflow; |
| else |
| goto Overflow; |
| } |
| |
| /* We don't check `power_ten' and `exponent_add'. */ |
| exponent += power_ten + exponent_add; |
| |
| if ( scaling ) |
| { |
| /* Only use `fraction_length'. */ |
| fraction_length += integer_length; |
| exponent += integer_length; |
| |
| if ( fraction_length <= 5 ) |
| { |
| if ( number > 0x7FFFL ) |
| { |
| result = FT_DivFix( number, 10 ); |
| *scaling = exponent - fraction_length + 1; |
| } |
| else |
| { |
| if ( exponent > 0 ) |
| { |
| FT_Long new_fraction_length, shift; |
| |
| |
| /* Make `scaling' as small as possible. */ |
| new_fraction_length = FT_MIN( exponent, 5 ); |
| shift = new_fraction_length - fraction_length; |
| |
| if ( shift > 0 ) |
| { |
| exponent -= new_fraction_length; |
| number *= power_tens[shift]; |
| if ( number > 0x7FFFL ) |
| { |
| number /= 10; |
| exponent += 1; |
| } |
| } |
| else |
| exponent -= fraction_length; |
| } |
| else |
| exponent -= fraction_length; |
| |
| result = (FT_Long)( (FT_ULong)number << 16 ); |
| *scaling = exponent; |
| } |
| } |
| else |
| { |
| if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL ) |
| { |
| result = FT_DivFix( number, power_tens[fraction_length - 4] ); |
| *scaling = exponent - 4; |
| } |
| else |
| { |
| result = FT_DivFix( number, power_tens[fraction_length - 5] ); |
| *scaling = exponent - 5; |
| } |
| } |
| } |
| else |
| { |
| integer_length += exponent; |
| fraction_length -= exponent; |
| |
| if ( integer_length > 5 ) |
| goto Overflow; |
| if ( integer_length < -5 ) |
| goto Underflow; |
| |
| /* Remove non-significant digits. */ |
| if ( integer_length < 0 ) |
| { |
| number /= power_tens[-integer_length]; |
| fraction_length += integer_length; |
| } |
| |
| /* this can only happen if exponent was non-zero */ |
| if ( fraction_length == 10 ) |
| { |
| number /= 10; |
| fraction_length -= 1; |
| } |
| |
| /* Convert into 16.16 format. */ |
| if ( fraction_length > 0 ) |
| { |
| if ( ( number / power_tens[fraction_length] ) > 0x7FFFL ) |
| goto Exit; |
| |
| result = FT_DivFix( number, power_tens[fraction_length] ); |
| } |
| else |
| { |
| number *= power_tens[-fraction_length]; |
| |
| if ( number > 0x7FFFL ) |
| goto Overflow; |
| |
| result = (FT_Long)( (FT_ULong)number << 16 ); |
| } |
| } |
| |
| Exit: |
| if ( sign ) |
| result = -result; |
| |
| return result; |
| |
| Overflow: |
| result = 0x7FFFFFFFL; |
| FT_TRACE4(( "!!!OVERFLOW:!!!" )); |
| goto Exit; |
| |
| Underflow: |
| result = 0; |
| FT_TRACE4(( "!!!UNDERFLOW:!!!" )); |
| goto Exit; |
| |
| Bad: |
| result = 0; |
| FT_TRACE4(( "!!!END OF DATA:!!!" )); |
| goto Exit; |
| } |
| |
| |
| /* read a number, either integer or real */ |
| FT_LOCAL_DEF( FT_Long ) |
| cff_parse_num( CFF_Parser parser, |
| FT_Byte** d ) |
| { |
| if ( **d == 30 ) |
| { |
| /* binary-coded decimal is truncated to integer */ |
| return cff_parse_real( parser, *d, 0, NULL ) >> 16; |
| } |
| |
| else if ( **d == 255 ) |
| { |
| /* 16.16 fixed point is used internally for CFF2 blend results. */ |
| /* Since these are trusted values, a limit check is not needed. */ |
| |
| /* After the 255, 4 bytes give the number. */ |
| /* The blend value is converted to integer, with rounding; */ |
| /* due to the right-shift we don't need the lowest byte. */ |
| #if 0 |
| return (FT_Short)( |
| ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | |
| ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | |
| ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | |
| (FT_UInt32)*( d[0] + 4 ) ) + 0x8000U ) >> 16 ); |
| #else |
| return (FT_Short)( |
| ( ( ( (FT_UInt32)*( d[0] + 1 ) << 16 ) | |
| ( (FT_UInt32)*( d[0] + 2 ) << 8 ) | |
| (FT_UInt32)*( d[0] + 3 ) ) + 0x80U ) >> 8 ); |
| #endif |
| } |
| |
| else |
| return cff_parse_integer( parser, *d ); |
| } |
| |
| |
| /* read a floating point number, either integer or real */ |
| static FT_Fixed |
| do_fixed( CFF_Parser parser, |
| FT_Byte** d, |
| FT_Long scaling ) |
| { |
| if ( **d == 30 ) |
| return cff_parse_real( parser, *d, scaling, NULL ); |
| else |
| { |
| FT_Long val = cff_parse_integer( parser, *d ); |
| |
| |
| if ( scaling ) |
| { |
| if ( FT_ABS( val ) > power_ten_limits[scaling] ) |
| { |
| val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; |
| goto Overflow; |
| } |
| |
| val *= power_tens[scaling]; |
| } |
| |
| if ( val > 0x7FFF ) |
| { |
| val = 0x7FFFFFFFL; |
| goto Overflow; |
| } |
| else if ( val < -0x7FFF ) |
| { |
| val = -0x7FFFFFFFL; |
| goto Overflow; |
| } |
| |
| return (FT_Long)( (FT_ULong)val << 16 ); |
| |
| Overflow: |
| FT_TRACE4(( "!!!OVERFLOW:!!!" )); |
| return val; |
| } |
| } |
| |
| |
| /* read a floating point number, either integer or real */ |
| static FT_Fixed |
| cff_parse_fixed( CFF_Parser parser, |
| FT_Byte** d ) |
| { |
| return do_fixed( parser, d, 0 ); |
| } |
| |
| |
| /* read a floating point number, either integer or real, */ |
| /* but return `10^scaling' times the number read in */ |
| static FT_Fixed |
| cff_parse_fixed_scaled( CFF_Parser parser, |
| FT_Byte** d, |
| FT_Long scaling ) |
| { |
| return do_fixed( parser, d, scaling ); |
| } |
| |
| |
| /* read a floating point number, either integer or real, */ |
| /* and return it as precise as possible -- `scaling' returns */ |
| /* the scaling factor (as a power of 10) */ |
| static FT_Fixed |
| cff_parse_fixed_dynamic( CFF_Parser parser, |
| FT_Byte** d, |
| FT_Long* scaling ) |
| { |
| FT_ASSERT( scaling ); |
| |
| if ( **d == 30 ) |
| return cff_parse_real( parser, *d, 0, scaling ); |
| else |
| { |
| FT_Long number; |
| FT_Int integer_length; |
| |
| |
| number = cff_parse_integer( parser, d[0] ); |
| |
| if ( number > 0x7FFFL ) |
| { |
| for ( integer_length = 5; integer_length < 10; integer_length++ ) |
| if ( number < power_tens[integer_length] ) |
| break; |
| |
| if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL ) |
| { |
| *scaling = integer_length - 4; |
| return FT_DivFix( number, power_tens[integer_length - 4] ); |
| } |
| else |
| { |
| *scaling = integer_length - 5; |
| return FT_DivFix( number, power_tens[integer_length - 5] ); |
| } |
| } |
| else |
| { |
| *scaling = 0; |
| return (FT_Long)( (FT_ULong)number << 16 ); |
| } |
| } |
| } |
| |
| |
| static FT_Error |
| cff_parse_font_matrix( CFF_Parser parser ) |
| { |
| CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; |
| FT_Matrix* matrix = &dict->font_matrix; |
| FT_Vector* offset = &dict->font_offset; |
| FT_ULong* upm = &dict->units_per_em; |
| FT_Byte** data = parser->stack; |
| |
| |
| if ( parser->top >= parser->stack + 6 ) |
| { |
| FT_Fixed values[6]; |
| FT_Long scalings[6]; |
| |
| FT_Long min_scaling, max_scaling; |
| int i; |
| |
| |
| dict->has_font_matrix = TRUE; |
| |
| /* We expect a well-formed font matrix, this is, the matrix elements */ |
| /* `xx' and `yy' are of approximately the same magnitude. To avoid */ |
| /* loss of precision, we use the magnitude of the largest matrix */ |
| /* element to scale all other elements. The scaling factor is then */ |
| /* contained in the `units_per_em' value. */ |
| |
| max_scaling = FT_LONG_MIN; |
| min_scaling = FT_LONG_MAX; |
| |
| for ( i = 0; i < 6; i++ ) |
| { |
| values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] ); |
| if ( values[i] ) |
| { |
| if ( scalings[i] > max_scaling ) |
| max_scaling = scalings[i]; |
| if ( scalings[i] < min_scaling ) |
| min_scaling = scalings[i]; |
| } |
| } |
| |
| if ( max_scaling < -9 || |
| max_scaling > 0 || |
| ( max_scaling - min_scaling ) < 0 || |
| ( max_scaling - min_scaling ) > 9 ) |
| { |
| FT_TRACE1(( "cff_parse_font_matrix:" |
| " strange scaling values (minimum %ld, maximum %ld),\n", |
| min_scaling, max_scaling )); |
| FT_TRACE1(( " " |
| " using default matrix\n" )); |
| goto Unlikely; |
| } |
| |
| for ( i = 0; i < 6; i++ ) |
| { |
| FT_Fixed value = values[i]; |
| FT_Long divisor, half_divisor; |
| |
| |
| if ( !value ) |
| continue; |
| |
| divisor = power_tens[max_scaling - scalings[i]]; |
| half_divisor = divisor >> 1; |
| |
| if ( value < 0 ) |
| { |
| if ( FT_LONG_MIN + half_divisor < value ) |
| values[i] = ( value - half_divisor ) / divisor; |
| else |
| values[i] = FT_LONG_MIN / divisor; |
| } |
| else |
| { |
| if ( FT_LONG_MAX - half_divisor > value ) |
| values[i] = ( value + half_divisor ) / divisor; |
| else |
| values[i] = FT_LONG_MAX / divisor; |
| } |
| } |
| |
| matrix->xx = values[0]; |
| matrix->yx = values[1]; |
| matrix->xy = values[2]; |
| matrix->yy = values[3]; |
| offset->x = values[4]; |
| offset->y = values[5]; |
| |
| *upm = (FT_ULong)power_tens[-max_scaling]; |
| |
| FT_TRACE4(( " [%f %f %f %f %f %f]\n", |
| (double)matrix->xx / *upm / 65536, |
| (double)matrix->xy / *upm / 65536, |
| (double)matrix->yx / *upm / 65536, |
| (double)matrix->yy / *upm / 65536, |
| (double)offset->x / *upm / 65536, |
| (double)offset->y / *upm / 65536 )); |
| |
| if ( !FT_Matrix_Check( matrix ) ) |
| { |
| FT_TRACE1(( "cff_parse_font_matrix:" |
| " degenerate values, using default matrix\n" )); |
| goto Unlikely; |
| } |
| |
| return FT_Err_Ok; |
| } |
| else |
| return FT_THROW( Stack_Underflow ); |
| |
| Unlikely: |
| /* Return default matrix in case of unlikely values. */ |
| |
| matrix->xx = 0x10000L; |
| matrix->yx = 0; |
| matrix->xy = 0; |
| matrix->yy = 0x10000L; |
| offset->x = 0; |
| offset->y = 0; |
| *upm = 1; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| static FT_Error |
| cff_parse_font_bbox( CFF_Parser parser ) |
| { |
| CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; |
| FT_BBox* bbox = &dict->font_bbox; |
| FT_Byte** data = parser->stack; |
| FT_Error error; |
| |
| |
| error = FT_ERR( Stack_Underflow ); |
| |
| if ( parser->top >= parser->stack + 4 ) |
| { |
| bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); |
| bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); |
| bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); |
| bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) ); |
| error = FT_Err_Ok; |
| |
| FT_TRACE4(( " [%ld %ld %ld %ld]\n", |
| bbox->xMin / 65536, |
| bbox->yMin / 65536, |
| bbox->xMax / 65536, |
| bbox->yMax / 65536 )); |
| } |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| cff_parse_private_dict( CFF_Parser parser ) |
| { |
| CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; |
| FT_Byte** data = parser->stack; |
| FT_Error error; |
| |
| |
| error = FT_ERR( Stack_Underflow ); |
| |
| if ( parser->top >= parser->stack + 2 ) |
| { |
| FT_Long tmp; |
| |
| |
| tmp = cff_parse_num( parser, data++ ); |
| if ( tmp < 0 ) |
| { |
| FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" )); |
| error = FT_THROW( Invalid_File_Format ); |
| goto Fail; |
| } |
| dict->private_size = (FT_ULong)tmp; |
| |
| tmp = cff_parse_num( parser, data ); |
| if ( tmp < 0 ) |
| { |
| FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" )); |
| error = FT_THROW( Invalid_File_Format ); |
| goto Fail; |
| } |
| dict->private_offset = (FT_ULong)tmp; |
| |
| FT_TRACE4(( " %lu %lu\n", |
| dict->private_size, dict->private_offset )); |
| |
| error = FT_Err_Ok; |
| } |
| |
| Fail: |
| return error; |
| } |
| |
| |
| /* The `MultipleMaster' operator comes before any */ |
| /* top DICT operators that contain T2 charstrings. */ |
| |
| static FT_Error |
| cff_parse_multiple_master( CFF_Parser parser ) |
| { |
| CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; |
| FT_Error error; |
| |
| |
| #ifdef FT_DEBUG_LEVEL_TRACE |
| /* beautify tracing message */ |
| if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] < 4 ) |
| FT_TRACE1(( "Multiple Master CFFs not supported yet," |
| " handling first master design only\n" )); |
| else |
| FT_TRACE1(( " (not supported yet," |
| " handling first master design only)\n" )); |
| #endif |
| |
| error = FT_ERR( Stack_Underflow ); |
| |
| /* currently, we handle only the first argument */ |
| if ( parser->top >= parser->stack + 5 ) |
| { |
| FT_Long num_designs = cff_parse_num( parser, parser->stack ); |
| |
| |
| if ( num_designs > 16 || num_designs < 2 ) |
| { |
| FT_ERROR(( "cff_parse_multiple_master:" |
| " Invalid number of designs\n" )); |
| error = FT_THROW( Invalid_File_Format ); |
| } |
| else |
| { |
| dict->num_designs = (FT_UShort)num_designs; |
| dict->num_axes = (FT_UShort)( parser->top - parser->stack - 4 ); |
| |
| parser->num_designs = dict->num_designs; |
| parser->num_axes = dict->num_axes; |
| |
| error = FT_Err_Ok; |
| } |
| } |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| cff_parse_cid_ros( CFF_Parser parser ) |
| { |
| CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; |
| FT_Byte** data = parser->stack; |
| FT_Error error; |
| |
| |
| error = FT_ERR( Stack_Underflow ); |
| |
| if ( parser->top >= parser->stack + 3 ) |
| { |
| dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ ); |
| dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ ); |
| if ( **data == 30 ) |
| FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); |
| dict->cid_supplement = cff_parse_num( parser, data ); |
| if ( dict->cid_supplement < 0 ) |
| FT_TRACE1(( "cff_parse_cid_ros: negative supplement %ld is found\n", |
| dict->cid_supplement )); |
| error = FT_Err_Ok; |
| |
| FT_TRACE4(( " %d %d %ld\n", |
| dict->cid_registry, |
| dict->cid_ordering, |
| dict->cid_supplement )); |
| } |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| cff_parse_vsindex( CFF_Parser parser ) |
| { |
| /* vsindex operator can only be used in a Private DICT */ |
| CFF_Private priv = (CFF_Private)parser->object; |
| FT_Byte** data = parser->stack; |
| CFF_Blend blend; |
| FT_Error error; |
| |
| |
| if ( !priv || !priv->subfont ) |
| { |
| error = FT_THROW( Invalid_File_Format ); |
| goto Exit; |
| } |
| |
| blend = &priv->subfont->blend; |
| |
| if ( blend->usedBV ) |
| { |
| FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" )); |
| error = FT_THROW( Syntax_Error ); |
| goto Exit; |
| } |
| |
| priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); |
| |
| FT_TRACE4(( " %d\n", priv->vsindex )); |
| |
| error = FT_Err_Ok; |
| |
| Exit: |
| return error; |
| } |
| |
| |
| static FT_Error |
| cff_parse_blend( CFF_Parser parser ) |
| { |
| /* blend operator can only be used in a Private DICT */ |
| CFF_Private priv = (CFF_Private)parser->object; |
| CFF_SubFont subFont; |
| CFF_Blend blend; |
| FT_UInt numBlends; |
| FT_Error error; |
| |
| |
| if ( !priv || !priv->subfont ) |
| { |
| error = FT_THROW( Invalid_File_Format ); |
| goto Exit; |
| } |
| |
| subFont = priv->subfont; |
| blend = &subFont->blend; |
| |
| if ( cff_blend_check_vector( blend, |
| priv->vsindex, |
| subFont->lenNDV, |
| subFont->NDV ) ) |
| { |
| error = cff_blend_build_vector( blend, |
| priv->vsindex, |
| subFont->lenNDV, |
| subFont->NDV ); |
| if ( error ) |
| goto Exit; |
| } |
| |
| numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 ); |
| if ( numBlends > parser->stackSize ) |
| { |
| FT_ERROR(( "cff_parse_blend: Invalid number of blends\n" )); |
| error = FT_THROW( Invalid_File_Format ); |
| goto Exit; |
| } |
| |
| FT_TRACE4(( " %d value%s blended\n", |
| numBlends, |
| numBlends == 1 ? "" : "s" )); |
| |
| error = cff_blend_doBlend( subFont, parser, numBlends ); |
| |
| blend->usedBV = TRUE; |
| |
| Exit: |
| 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_THROW( 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 )); |
| |
| 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 ) \ |
| CFF_FIELD( code, name, id, cff_kind_fixed ) |
| #define CFF_FIELD_FIXED_1000( code, name, id ) \ |
| CFF_FIELD( code, name, id, cff_kind_fixed_thousand ) |
| #define CFF_FIELD_STRING( code, name, id ) \ |
| CFF_FIELD( code, name, id, cff_kind_string ) |
| #define CFF_FIELD_BOOL( code, name, id ) \ |
| CFF_FIELD( code, name, id, cff_kind_bool ) |
| |
| |
| #undef CFF_FIELD |
| #undef CFF_FIELD_DELTA |
| |
| |
| #ifndef FT_DEBUG_LEVEL_TRACE |
| |
| |
| #define CFF_FIELD_CALLBACK( code, name, id ) \ |
| { \ |
| cff_kind_callback, \ |
| code | CFFCODE, \ |
| 0, 0, \ |
| cff_parse_ ## name, \ |
| 0, 0 \ |
| }, |
| |
| #define CFF_FIELD_BLEND( code, id ) \ |
| { \ |
| cff_kind_blend, \ |
| code | CFFCODE, \ |
| 0, 0, \ |
| cff_parse_blend, \ |
| 0, 0 \ |
| }, |
| |
| #define CFF_FIELD( code, name, id, kind ) \ |
| { \ |
| kind, \ |
| code | CFFCODE, \ |
| FT_FIELD_OFFSET( name ), \ |
| FT_FIELD_SIZE( name ), \ |
| 0, 0, 0 \ |
| }, |
| |
| #define CFF_FIELD_DELTA( code, name, max, id ) \ |
| { \ |
| cff_kind_delta, \ |
| code | CFFCODE, \ |
| FT_FIELD_OFFSET( name ), \ |
| FT_FIELD_SIZE_DELTA( name ), \ |
| 0, \ |
| max, \ |
| FT_FIELD_OFFSET( num_ ## name ) \ |
| }, |
| |
| static const CFF_Field_Handler cff_field_handlers[] = |
| { |
| |
| #include "cfftoken.h" |
| |
| { 0, 0, 0, 0, 0, 0, 0 } |
| }; |
| |
| |
| #else /* FT_DEBUG_LEVEL_TRACE */ |
| |
| |
| |
| #define CFF_FIELD_CALLBACK( code, name, id ) \ |
| { \ |
| cff_kind_callback, \ |
| code | CFFCODE, \ |
| 0, 0, \ |
| cff_parse_ ## name, \ |
| 0, 0, \ |
| id \ |
| }, |
| |
| #define CFF_FIELD_BLEND( code, id ) \ |
| { \ |
| cff_kind_blend, \ |
| code | CFFCODE, \ |
| 0, 0, \ |
| cff_parse_blend, \ |
| 0, 0, \ |
| id \ |
| }, |
| |
| #define CFF_FIELD( code, name, id, kind ) \ |
| { \ |
| kind, \ |
| code | CFFCODE, \ |
| FT_FIELD_OFFSET( name ), \ |
| FT_FIELD_SIZE( name ), \ |
| 0, 0, 0, \ |
| id \ |
| }, |
| |
| #define CFF_FIELD_DELTA( code, name, max, id ) \ |
| { \ |
| cff_kind_delta, \ |
| code | CFFCODE, \ |
| FT_FIELD_OFFSET( name ), \ |
| FT_FIELD_SIZE_DELTA( name ), \ |
| 0, \ |
| max, \ |
| FT_FIELD_OFFSET( num_ ## name ), \ |
| id \ |
| }, |
| |
| static const CFF_Field_Handler cff_field_handlers[] = |
| { |
| |
| #include "cfftoken.h" |
| |
| { 0, 0, 0, 0, 0, 0, 0, 0 } |
| }; |
| |
| |
| #endif /* FT_DEBUG_LEVEL_TRACE */ |
| |
| |
| FT_LOCAL_DEF( FT_Error ) |
| cff_parser_run( CFF_Parser parser, |
| FT_Byte* start, |
| FT_Byte* limit ) |
| { |
| FT_Byte* p = start; |
| FT_Error error = FT_Err_Ok; |
| |
| #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
| PSAux_Service psaux; |
| |
| FT_Library library = parser->library; |
| FT_Memory memory = library->memory; |
| #endif |
| |
| parser->top = parser->stack; |
| parser->start = start; |
| parser->limit = limit; |
| parser->cursor = start; |
| |
| while ( p < limit ) |
| { |
| FT_UInt v = *p; |
| |
| |
| /* Opcode 31 is legacy MM T2 operator, not a number. */ |
| /* Opcode 255 is reserved and should not appear in fonts; */ |
| /* it is used internally for CFF2 blends. */ |
| if ( v >= 27 && v != 31 && v != 255 ) |
| { |
| /* it's a number; we will push its position on the stack */ |
| if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) |
| goto Stack_Overflow; |
| |
| *parser->top++ = p; |
| |
| /* now, skip it */ |
| if ( v == 30 ) |
| { |
| /* skip real number */ |
| p++; |
| for (;;) |
| { |
| /* An unterminated floating point number at the */ |
| /* end of a dictionary is invalid but harmless. */ |
| if ( p >= limit ) |
| goto Exit; |
| v = p[0] >> 4; |
| if ( v == 15 ) |
| break; |
| v = p[0] & 0xF; |
| if ( v == 15 ) |
| break; |
| p++; |
| } |
| } |
| else if ( v == 28 ) |
| p += 2; |
| else if ( v == 29 ) |
| p += 4; |
| else if ( v > 246 ) |
| p += 1; |
| } |
| #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
| else if ( v == 31 ) |
| { |
| /* a Type 2 charstring */ |
| |
| CFF_Decoder decoder; |
| CFF_FontRec cff_rec; |
| FT_Byte* charstring_base; |
| FT_ULong charstring_len; |
| |
| FT_Fixed* stack; |
| FT_ListNode node; |
| CFF_T2_String t2; |
| FT_Fixed t2_size; |
| FT_Byte* q; |
| |
| |
| charstring_base = ++p; |
| |
| /* search `endchar' operator */ |
| for (;;) |
| { |
| if ( p >= limit ) |
| goto Exit; |
| if ( *p == 14 ) |
| break; |
| p++; |
| } |
| |
| charstring_len = (FT_ULong)( p - charstring_base ) + 1; |
| |
| /* construct CFF_Decoder object */ |
| FT_ZERO( &decoder ); |
| FT_ZERO( &cff_rec ); |
| |
| cff_rec.top_font.font_dict.num_designs = parser->num_designs; |
| cff_rec.top_font.font_dict.num_axes = parser->num_axes; |
| decoder.cff = &cff_rec; |
| |
| psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" ); |
| if ( !psaux ) |
| { |
| FT_ERROR(( "cff_parser_run: cannot access `psaux' module\n" )); |
| error = FT_THROW( Missing_Module ); |
| goto Exit; |
| } |
| |
| error = psaux->cff_decoder_funcs->parse_charstrings_old( |
| &decoder, charstring_base, charstring_len, 1 ); |
| if ( error ) |
| goto Exit; |
| |
| /* Now copy the stack data in the temporary decoder object, */ |
| /* converting it back to charstring number representations */ |
| /* (this is ugly, I know). */ |
| |
| node = (FT_ListNode)memory->alloc( memory, |
| sizeof ( FT_ListNodeRec ) ); |
| if ( !node ) |
| goto Out_Of_Memory_Error; |
| |
| FT_List_Add( &parser->t2_strings, node ); |
| |
| t2 = (CFF_T2_String)memory->alloc( memory, |
| sizeof ( CFF_T2_StringRec ) ); |
| if ( !t2 ) |
| goto Out_Of_Memory_Error; |
| |
| node->data = t2; |
| |
| /* `5' is the conservative upper bound of required bytes per stack */ |
| /* element. */ |
| |
| t2_size = 5 * ( decoder.top - decoder.stack ); |
| |
| q = (FT_Byte*)memory->alloc( memory, t2_size ); |
| if ( !q ) |
| goto Out_Of_Memory_Error; |
| |
| t2->start = q; |
| t2->limit = q + t2_size; |
| |
| stack = decoder.stack; |
| |
| while ( stack < decoder.top ) |
| { |
| FT_ULong num; |
| FT_Bool neg; |
| |
| |
| if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) |
| goto Stack_Overflow; |
| |
| *parser->top++ = q; |
| |
| if ( *stack < 0 ) |
| { |
| num = (FT_ULong)NEG_LONG( *stack ); |
| neg = 1; |
| } |
| else |
| { |
| num = (FT_ULong)*stack; |
| neg = 0; |
| } |
| |
| if ( num & 0xFFFFU ) |
| { |
| if ( neg ) |
| num = (FT_ULong)-num; |
| |
| *q++ = 255; |
| *q++ = ( num & 0xFF000000U ) >> 24; |
| *q++ = ( num & 0x00FF0000U ) >> 16; |
| *q++ = ( num & 0x0000FF00U ) >> 8; |
| *q++ = num & 0x000000FFU; |
| } |
| else |
| { |
| num >>= 16; |
| |
| if ( neg ) |
| { |
| if ( num <= 107 ) |
| *q++ = (FT_Byte)( 139 - num ); |
| else if ( num <= 1131 ) |
| { |
| *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 ); |
| *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); |
| } |
| else |
| { |
| num = (FT_ULong)-num; |
| |
| *q++ = 28; |
| *q++ = (FT_Byte)( num >> 8 ); |
| *q++ = (FT_Byte)( num & 0xFF ); |
| } |
| } |
| else |
| { |
| if ( num <= 107 ) |
| *q++ = (FT_Byte)( num + 139 ); |
| else if ( num <= 1131 ) |
| { |
| *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); |
| *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); |
| } |
| else |
| { |
| *q++ = 28; |
| *q++ = (FT_Byte)( num >> 8 ); |
| *q++ = (FT_Byte)( num & 0xFF ); |
| } |
| } |
| } |
| |
| stack++; |
| } |
| } |
| #endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ |
| else |
| { |
| /* This is not a number, hence it's an operator. Compute its code */ |
| /* and look for it in our current list. */ |
| |
| FT_UInt code; |
| FT_UInt num_args; |
| const CFF_Field_Handler* field; |
| |
| |
| if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) |
| goto Stack_Overflow; |
| |
| num_args = (FT_UInt)( parser->top - parser->stack ); |
| *parser->top = p; |
| code = v; |
| |
| if ( v == 12 ) |
| { |
| /* two byte operator */ |
| p++; |
| if ( p >= limit ) |
| goto Syntax_Error; |
| |
| code = 0x100 | p[0]; |
| } |
| code = code | parser->object_code; |
| |
| for ( field = cff_field_handlers; field->kind; field++ ) |
| { |
| if ( field->code == (FT_Int)code ) |
| { |
| /* we found our field's handler; read it */ |
| FT_Long val; |
| FT_Byte* q = (FT_Byte*)parser->object + field->offset; |
| |
| |
| #ifdef FT_DEBUG_LEVEL_TRACE |
| FT_TRACE4(( " %s", field->id )); |
| #endif |
| |
| /* check that we have enough arguments -- except for */ |
| /* delta encoded arrays, which can be empty */ |
| if ( field->kind != cff_kind_delta && num_args < 1 ) |
| goto Stack_Underflow; |
| |
| switch ( field->kind ) |
| { |
| case cff_kind_bool: |
| case cff_kind_string: |
| case cff_kind_num: |
| val = cff_parse_num( parser, parser->stack ); |
| goto Store_Number; |
| |
| case cff_kind_fixed: |
| val = cff_parse_fixed( parser, parser->stack ); |
| goto Store_Number; |
| |
| case cff_kind_fixed_thousand: |
| val = cff_parse_fixed_scaled( parser, parser->stack, 3 ); |
| |
| Store_Number: |
| switch ( field->size ) |
| { |
| case (8 / FT_CHAR_BIT): |
| *(FT_Byte*)q = (FT_Byte)val; |
| break; |
| |
| case (16 / FT_CHAR_BIT): |
| *(FT_Short*)q = (FT_Short)val; |
| break; |
| |
| case (32 / FT_CHAR_BIT): |
| *(FT_Int32*)q = (FT_Int)val; |
| break; |
| |
| default: /* for 64-bit systems */ |
| *(FT_Long*)q = val; |
| } |
| |
| #ifdef FT_DEBUG_LEVEL_TRACE |
| switch ( field->kind ) |
| { |
| case cff_kind_bool: |
| FT_TRACE4(( " %s\n", val ? "true" : "false" )); |
| break; |
| |
| case cff_kind_string: |
| FT_TRACE4(( " %ld (SID)\n", val )); |
| break; |
| |
| case cff_kind_num: |
| FT_TRACE4(( " %ld\n", val )); |
| break; |
| |
| case cff_kind_fixed: |
| FT_TRACE4(( " %f\n", (double)val / 65536 )); |
| break; |
| |
| case cff_kind_fixed_thousand: |
| FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 )); |
| break; |
| |
| default: |
| ; /* never reached */ |
| } |
| #endif |
| |
| break; |
| |
| case cff_kind_delta: |
| { |
| FT_Byte* qcount = (FT_Byte*)parser->object + |
| field->count_offset; |
| |
| FT_Byte** data = parser->stack; |
| |
| |
| if ( num_args > field->array_max ) |
| num_args = field->array_max; |
| |
| FT_TRACE4(( " [" )); |
| |
| /* store count */ |
| *qcount = (FT_Byte)num_args; |
| |
| val = 0; |
| while ( num_args > 0 ) |
| { |
| val = ADD_LONG( val, cff_parse_num( parser, data++ ) ); |
| switch ( field->size ) |
| { |
| case (8 / FT_CHAR_BIT): |
| *(FT_Byte*)q = (FT_Byte)val; |
| break; |
| |
| case (16 / FT_CHAR_BIT): |
| *(FT_Short*)q = (FT_Short)val; |
| break; |
| |
| case (32 / FT_CHAR_BIT): |
| *(FT_Int32*)q = (FT_Int)val; |
| break; |
| |
| default: /* for 64-bit systems */ |
| *(FT_Long*)q = val; |
| } |
| |
| FT_TRACE4(( " %ld", val )); |
| |
| q += field->size; |
| num_args--; |
| } |
| |
| FT_TRACE4(( "]\n" )); |
| } |
| break; |
| |
| default: /* callback or blend */ |
| error = field->reader( parser ); |
| if ( error ) |
| goto Exit; |
| } |
| goto Found; |
| } |
| } |
| |
| /* this is an unknown operator, or it is unsupported; */ |
| /* we will ignore it for now. */ |
| |
| Found: |
| /* clear stack */ |
| /* TODO: could clear blend stack here, */ |
| /* but we don't have access to subFont */ |
| if ( field->kind != cff_kind_blend ) |
| parser->top = parser->stack; |
| } |
| p++; |
| } /* while ( p < limit ) */ |
| |
| Exit: |
| return error; |
| |
| #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
| Out_Of_Memory_Error: |
| error = FT_THROW( Out_Of_Memory ); |
| goto Exit; |
| #endif |
| |
| Stack_Overflow: |
| error = FT_THROW( Invalid_Argument ); |
| goto Exit; |
| |
| Stack_Underflow: |
| error = FT_THROW( Invalid_Argument ); |
| goto Exit; |
| |
| Syntax_Error: |
| error = FT_THROW( Invalid_Argument ); |
| goto Exit; |
| } |
| |
| |
| /* END */ |