summaryrefslogtreecommitdiffstats
path: root/modules/freetype2/src/cff/cffparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/freetype2/src/cff/cffparse.c')
-rw-r--r--modules/freetype2/src/cff/cffparse.c1621
1 files changed, 1621 insertions, 0 deletions
diff --git a/modules/freetype2/src/cff/cffparse.c b/modules/freetype2/src/cff/cffparse.c
new file mode 100644
index 0000000000..e16206fd55
--- /dev/null
+++ b/modules/freetype2/src/cff/cffparse.c
@@ -0,0 +1,1621 @@
+/****************************************************************************
+ *
+ * cffparse.c
+ *
+ * CFF token stream parser (body)
+ *
+ * Copyright (C) 1996-2023 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 / (double)*upm / 65536,
+ (double)matrix->xy / (double)*upm / 65536,
+ (double)matrix->yx / (double)*upm / 65536,
+ (double)matrix->yy / (double)*upm / 65536,
+ (double)offset->x / (double)*upm / 65536,
+ (double)offset->y / (double)*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 */