* src/psaux/t1decode.c (T1_Operator, t1_args_count): Add opcode 15.

(t1_decoder_parse_charstrings): Operator with
opcode 15 pops its two arguments.
Handle the case where the pops of an othersubr may be part of a
subroutine.
Handle unknown othersubrs gracefully: count their operands and let
the following pop operators push the operands as the results onto
the Type1 stack.
Improve handling of setcurrentpoint opcode.
This commit is contained in:
Werner Lemberg 2006-06-26 19:12:51 +00:00
parent e9a746674a
commit 24703f8b39
2 changed files with 163 additions and 49 deletions

View File

@ -1,3 +1,15 @@
2006-06-26 Jens Claudius <jens.claudius@yahoo.com>
* src/psaux/t1decode.c (T1_Operator, t1_args_count): Add opcode 15.
(t1_decoder_parse_charstrings): Operator with
opcode 15 pops its two arguments.
Handle the case where the pops of an othersubr may be part of a
subroutine.
Handle unknown othersubrs gracefully: count their operands and let
the following pop operators push the operands as the results onto
the Type1 stack.
Improve handling of setcurrentpoint opcode.
2006-06-25 Jens Claudius <jens.claudius@yahoo.com>
The Type 1 parser now skips over top-level procedures as required

View File

@ -4,7 +4,7 @@
/* */
/* PostScript Type 1 decoding routines (body). */
/* */
/* Copyright 2000-2001, 2002, 2003, 2004, 2005 by */
/* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@ -65,6 +65,7 @@
op_pop,
op_return,
op_setcurrentpoint,
op_unknown15,
op_max /* never remove this one */
@ -99,7 +100,8 @@
1, /* callsubr */
0, /* pop */
0, /* return */
2 /* setcurrentpoint */
2, /* setcurrentpoint */
2 /* opcode 15 (undocumented and obsolete) */
};
@ -323,6 +325,8 @@
FT_Byte* limit;
T1_Builder builder = &decoder->builder;
FT_Pos x, y, orig_x, orig_y;
FT_Int known_othersubr_result_cnt = 0;
FT_Int unknown_othersubr_result_cnt = 0;
T1_Hints_Funcs hinter;
@ -344,6 +348,8 @@
hinter = (T1_Hints_Funcs)builder->hints_funcs;
FT_TRACE4(( "\nStart charstring\n" ));
zone->base = charstring_base;
limit = zone->limit = charstring_base + charstring_len;
ip = zone->cursor = zone->base;
@ -365,6 +371,11 @@
FT_Long value = 0;
FT_ASSERT( known_othersubr_result_cnt == 0 ||
unknown_othersubr_result_cnt == 0 );
FT_TRACE5(( " (%d)", decoder->top - decoder->stack ));
/*********************************************************************/
/* */
/* Decode operator or operand */
@ -414,7 +425,7 @@
break;
case 15: /* undocumented, obsolete operator */
op = op_none;
op = op_unknown15;
break;
case 21:
@ -520,6 +531,23 @@
}
}
if ( unknown_othersubr_result_cnt > 0 )
{
switch ( op )
{
case op_callsubr:
case op_return:
case op_none:
case op_pop:
break;
default:
/* all operands have been transferred by previous pops */
unknown_othersubr_result_cnt = 0;
break;
}
}
/*********************************************************************/
/* */
/* Push value on stack, or process operator */
@ -540,16 +568,43 @@
}
else if ( op == op_callothersubr ) /* callothersubr */
{
FT_Int subr_no;
FT_Int arg_cnt;
FT_TRACE4(( " callothersubr" ));
if ( top - decoder->stack < 2 )
goto Stack_Underflow;
top -= 2;
switch ( (FT_Int)top[1] )
subr_no = (FT_Int)top[1];
arg_cnt = (FT_Int)top[0];
if ( arg_cnt > top - decoder->stack )
goto Stack_Underflow;
/***********************************************************/
/* */
/* remove all operands to callsubr from the stack */
/* */
/* for handled othersubrs, where we know the number of */
/* arguments, we increase the stack by the value of */
/* known_othersubr_result_cnt */
/* */
/* for unhandled othersubrs the following pops adjust the */
/* stack pointer as necessary */
top -= arg_cnt;
known_othersubr_result_cnt = 0;
unknown_othersubr_result_cnt = 0;
switch ( subr_no )
{
case 1: /* start flex feature */
if ( top[0] != 0 )
if ( arg_cnt != 0 )
goto Unexpected_OtherSubr;
decoder->flex_state = 1;
@ -564,7 +619,7 @@
FT_Int idx;
if ( top[0] != 0 )
if ( arg_cnt != 0 )
goto Unexpected_OtherSubr;
/* note that we should not add a point for index 0; */
@ -580,7 +635,7 @@
break;
case 0: /* end flex feature */
if ( top[0] != 3 )
if ( arg_cnt != 3 )
goto Unexpected_OtherSubr;
if ( decoder->flex_state == 0 ||
@ -591,40 +646,15 @@
goto Syntax_Error;
}
/* now consume the remaining `pop pop setcurpoint' */
if ( ip + 6 > limit ||
ip[0] != 12 || ip[1] != 17 || /* pop */
ip[2] != 12 || ip[3] != 17 || /* pop */
ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */
{
FT_ERROR(( "t1_decoder_parse_charstrings: "
"invalid flex charstring\n" ));
goto Syntax_Error;
}
ip += 6;
decoder->flex_state = 0;
/* the two `results' are popped by the following setcurrentpoint */
known_othersubr_result_cnt = 2;
break;
case 3: /* change hints */
if ( top[0] != 1 )
if ( arg_cnt != 1 )
goto Unexpected_OtherSubr;
/* eat the following `pop' */
if ( ip + 2 > limit )
{
FT_ERROR(( "t1_decoder_parse_charstrings: "
"invalid escape (12+%d)\n", ip[-1] ));
goto Syntax_Error;
}
if ( ip[0] != 12 || ip[1] != 17 )
{
FT_ERROR(( "t1_decoder_parse_charstrings: " ));
FT_ERROR(( "`pop' expected, found (%d %d)\n", ip[0], ip[1] ));
goto Syntax_Error;
}
ip += 2;
known_othersubr_result_cnt = 1;
if ( hinter )
hinter->reset( hinter->hints, builder->current->n_points );
@ -656,18 +686,14 @@
goto Syntax_Error;
}
num_points = (FT_UInt)top[1] - 13 + ( top[1] == 18 );
if ( top[0] != (FT_Int)( num_points * blend->num_designs ) )
num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 );
if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) )
{
FT_ERROR(( "t1_decoder_parse_charstrings: " ));
FT_ERROR(( "incorrect number of mm arguments\n" ));
goto Syntax_Error;
}
top -= blend->num_designs * num_points;
if ( top < decoder->stack )
goto Stack_Underflow;
/* we want to compute: */
/* */
/* a0*w0 + a1*w1 + ... + ak*wk */
@ -695,16 +721,26 @@
*values++ = tmp;
}
/* note that `top' will be incremented later by calls to `pop' */
known_othersubr_result_cnt = num_points;
break;
}
default:
FT_ERROR(( "t1_decoder_parse_charstrings: "
"unknown othersubr [%d %d], wish me luck!\n",
arg_cnt, subr_no ));
unknown_othersubr_result_cnt = arg_cnt;
break;
Unexpected_OtherSubr:
FT_ERROR(( "t1_decoder_parse_charstrings: "
"invalid othersubr [%d %d]!\n", top[0], top[1] ));
"invalid othersubr [%d %d]!\n", arg_cnt, subr_no ));
goto Syntax_Error;
}
top += known_othersubr_result_cnt;
decoder->top = top;
}
else /* general operator */
@ -712,9 +748,38 @@
FT_Int num_args = t1_args_count[op];
FT_ASSERT( num_args >= 0 );
if ( top - decoder->stack < num_args )
goto Stack_Underflow;
/* XXX Operators usually take their operands from the */
/* bottom of the stack, i.e., the operands are */
/* decoder->stack[0], ..., decoder->stack[num_args - 1]; */
/* only div, callsubr, and callothersubr are different. */
/* In practice it doesn't matter (?). */
#ifdef FT_DEBUG_LEVEL_TRACE
switch ( op )
{
case op_callsubr:
case op_div:
case op_callothersubr:
case op_pop:
case op_return:
break;
default:
if ( top - decoder->stack != num_args )
FT_TRACE0(( "\nMore operands on the stack than expected "
"(have %d, expected %d)\n",
top - decoder->stack, num_args ));
break;
}
#endif /* FT_DEBUG_LEVEL_TRACE */
top -= num_args;
switch ( op )
@ -997,8 +1062,22 @@
case op_pop:
FT_TRACE4(( " pop" ));
/* theoretically, the arguments are already on the stack */
top++;
if ( known_othersubr_result_cnt > 0 )
{
known_othersubr_result_cnt--;
/* ignore, we pushed the operands ourselves */
break;
}
if ( unknown_othersubr_result_cnt == 0 )
{
FT_ERROR(( "t1_decoder_parse_charstrings: "
"no more operands for othersubr!\n" ));
goto Syntax_Error;
}
unknown_othersubr_result_cnt--;
top++; /* `push' the operand to callothersubr onto the stack */
break;
case op_return:
@ -1073,9 +1152,27 @@
case op_setcurrentpoint:
FT_TRACE4(( " setcurrentpoint" ));
FT_ERROR(( "t1_decoder_parse_charstrings: " ));
FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
goto Syntax_Error;
/* From the T1 specs, section 6.4: */
/* */
/* The setcurrentpoint command is used only in */
/* conjunction with results from OtherSubrs procedures. */
/* known_othersubr_result_cnt != 0 is already handled above */
if ( decoder->flex_state != 1 )
{
FT_ERROR(( "t1_decoder_parse_charstrings: " ));
FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
goto Syntax_Error;
}
else
decoder->flex_state = 0;
break;
case op_unknown15:
FT_TRACE4(( " opcode_15" ));
/* nothing to do except to pop the two arguments */
break;
default:
FT_ERROR(( "t1_decoder_parse_charstrings: "
@ -1083,6 +1180,11 @@
goto Syntax_Error;
}
/* XXX Operators usually clear the operand stack; */
/* only div, callsubr, callothersubr, pop, and */
/* return are different. */
/* In practice it doesn't matter (?). */
decoder->top = top;
} /* general operator processing */