The Type 1 parser now skips over top-level procedures as required

for a `Simplified Parser'.  This makes the parser more robust as it
doesn't poke around in PostScript code.  Additionally, it makes the
FontDirectory hackery in src/type1/t1load.c unnecessary.

* src/psaux/psobjs.c (IS_OCTAL_DIGIT): New macro.
(skip_literal_string): Add FT_Error as return value.
Handle escapes better.
(skip_string): Add FT_Error as return value.
Don't set `parser->error' but return error code directly.
(skip_procedure): New function.
(ps_parser_skip_PS_token): Handle procedures.
Update code.
(ps_parser_to_token): Update code.
(ps_parser_load_field_table): Handle bbox entries also.

* src/type1/t1load.c (parse_dict): Remove FontDirectory hackery.
Add commented-out code for synthetic fonts.
This commit is contained in:
Werner Lemberg 2006-06-26 09:40:00 +00:00
parent a2da05c2c5
commit c011f4cba1
3 changed files with 213 additions and 103 deletions

View File

@ -1,3 +1,24 @@
2006-06-25 Jens Claudius <jens.claudius@yahoo.com>
The Type 1 parser now skips over top-level procedures as required
for a `Simplified Parser'. This makes the parser more robust as it
doesn't poke around in PostScript code. Additionally, it makes the
FontDirectory hackery in src/type1/t1load.c unnecessary.
* src/psaux/psobjs.c (IS_OCTAL_DIGIT): New macro.
(skip_literal_string): Add FT_Error as return value.
Handle escapes better.
(skip_string): Add FT_Error as return value.
Don't set `parser->error' but return error code directly.
(skip_procedure): New function.
(ps_parser_skip_PS_token): Handle procedures.
Update code.
(ps_parser_to_token): Update code.
(ps_parser_load_field_table): Handle bbox entries also.
* src/type1/t1load.c (parse_dict): Remove FontDirectory hackery.
Add commented-out code for synthetic fonts.
2006-06-24 Eugeniy Meshcheryakov <eugen@univ.kiev.ua>
Fix two hinting bugs as reported in

View File

@ -312,45 +312,94 @@
}
/* first character must be `(' */
#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
static void
/* first character must be `('; */
/* *acur is positioned at the character after the closing `)' */
static FT_Error
skip_literal_string( FT_Byte* *acur,
FT_Byte* limit )
{
FT_Byte* cur = *acur;
FT_Int embed = 0;
FT_Byte* cur = *acur;
FT_Int embed = 0;
FT_Error error = PSaux_Err_Invalid_File_Format;
unsigned int i;
while ( cur < limit )
{
if ( *cur == '\\' )
cur++;
else if ( *cur == '(' )
FT_Byte c = *cur;
++cur;
if ( c == '\\' )
{
/* Red Book 3rd ed., section `Literal Text Strings', p. 29: */
/* A backslash can introduce three different types */
/* of escape sequences: */
/* - a special escaped char like \r, \n, etc. */
/* - a one-, two-, or three-digit octal number */
/* - none of the above in which case the backslash is ignored */
if ( cur == limit )
/* error (or to be ignored?) */
break;
switch ( *cur )
{
/* skip `special' escape */
case 'n':
case 'r':
case 't':
case 'b':
case 'f':
case '\\':
case '(':
case ')':
++cur;
break;
default:
/* skip octal escape or ignore backslash */
for ( i = 0; i < 3 && cur < limit; ++i )
{
if ( ! IS_OCTAL_DIGIT( *cur ) )
break;
++cur;
}
}
}
else if ( c == '(' )
embed++;
else if ( *cur == ')' )
else if ( c == ')' )
{
embed--;
if ( embed == 0 )
{
cur++;
error = PSaux_Err_Ok;
break;
}
}
cur++;
}
*acur = cur;
return error;
}
/* first character must be `<' */
static void
skip_string( PS_Parser parser )
static FT_Error
skip_string( FT_Byte* *acur,
FT_Byte* limit )
{
FT_Byte* cur = parser->cursor;
FT_Byte* limit = parser->limit;
FT_Byte* cur = *acur;
FT_Error err = PSaux_Err_Ok;
while ( ++cur < limit )
@ -367,12 +416,72 @@
if ( cur < limit && *cur != '>' )
{
FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
parser->error = PSaux_Err_Invalid_File_Format;
err = PSaux_Err_Invalid_File_Format;
}
else
cur++;
parser->cursor = cur;
*acur = cur;
return err;
}
/* first character must be the opening brace that */
/* starts the procedure */
/* NB: [ and ] need not match: */
/* `/foo {[} def' is a valid PostScript fragment, */
/* even within a Type1 font */
static FT_Error
skip_procedure( FT_Byte* *acur,
FT_Byte* limit )
{
FT_Byte* cur;
FT_Int embed = 0;
FT_Error error = PSaux_Err_Ok;
FT_ASSERT( **acur == '{' );
for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
{
switch ( *cur )
{
case '{':
++embed;
break;
case '}':
--embed;
if ( embed == 0 )
{
++cur;
goto end;
}
break;
case '(':
error = skip_literal_string( &cur, limit );
break;
case '<':
error = skip_string( &cur, limit );
break;
case '%':
skip_comment( &cur, limit );
break;
}
}
end:
if ( embed != 0 )
error = PSaux_Err_Invalid_File_Format;
*acur = cur;
return error;
}
@ -393,6 +502,7 @@
FT_Byte* cur = parser->cursor;
FT_Byte* limit = parser->limit;
FT_Error error = PSaux_Err_Ok;
skip_spaces( &cur, limit ); /* this also skips comments */
@ -400,16 +510,23 @@
goto Exit;
/* self-delimiting, single-character tokens */
if ( *cur == '[' || *cur == ']' ||
*cur == '{' || *cur == '}' )
if ( *cur == '[' || *cur == ']' )
{
cur++;
goto Exit;
}
/* skip balanced expressions (procedures and strings) */
if ( *cur == '{' ) /* {...} */
{
error = skip_procedure( &cur, limit );
goto Exit;
}
if ( *cur == '(' ) /* (...) */
{
skip_literal_string( &cur, limit );
error = skip_literal_string( &cur, limit );
goto Exit;
}
@ -419,11 +536,11 @@
{
cur++;
cur++;
goto Exit;
}
parser->cursor = cur;
skip_string( parser );
return;
else
error = skip_string( &cur, limit );
goto Exit;
}
if ( *cur == '>' )
@ -433,7 +550,7 @@
{
FT_ERROR(( "ps_parser_skip_PS_token: "
"unexpected closing delimiter `>'\n" ));
parser->error = PSaux_Err_Invalid_File_Format;
error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
cur++;
@ -446,20 +563,17 @@
/* anything else */
while ( cur < limit )
{
if ( *cur == ')' )
{
FT_ERROR(( "ps_parser_skip_PS_token: "
"unexpected closing delimiter `)'\n" ));
parser->error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
else if ( IS_PS_DELIM( *cur ) )
/* `*cur' might be invalid (e.g., `)' or `}'), but this is handled */
/* by the caller which will see this when it continues parsing */
if ( IS_PS_DELIM( *cur ) )
break;
cur++;
}
Exit:
FT_ASSERT( parser->error == PSaux_Err_Ok );
parser->error = error;
parser->cursor = cur;
}
@ -480,7 +594,6 @@
{
FT_Byte* cur;
FT_Byte* limit;
FT_Byte starter, ender;
FT_Int embed;
@ -503,26 +616,27 @@
case '(':
token->type = T1_TOKEN_TYPE_STRING;
token->start = cur;
skip_literal_string( &cur, limit );
if ( cur < limit )
if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
token->limit = cur;
break;
/************* check for programs/array *****************/
case '{':
token->type = T1_TOKEN_TYPE_ARRAY;
ender = '}';
goto Lookup_Ender;
token->type = T1_TOKEN_TYPE_ARRAY;
token->start = cur;
if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
token->limit = cur;
break;
/************* check for table/array ********************/
/* XXX: in theory we should also look for "<<" */
/* since this is semantically equivalent to "["; */
/* in practice it doesn't matter (?) */
case '[':
token->type = T1_TOKEN_TYPE_ARRAY;
ender = ']';
/* fall through */
Lookup_Ender:
token->type = T1_TOKEN_TYPE_ARRAY;
embed = 1;
starter = *cur;
token->start = cur++;
/* we need this to catch `[ ]' */
@ -532,9 +646,11 @@
while ( cur < limit && !parser->error )
{
if ( *cur == starter )
/* XXX: this is wrong because it does not */
/* skip comments, procedures, and strings */
if ( *cur == '[' )
embed++;
else if ( *cur == ender )
else if ( *cur == ']' )
{
embed--;
if ( embed <= 0 )
@ -1038,11 +1154,10 @@
T1_FieldRec fieldrec = *(T1_Field)field;
#if 1
fieldrec.type = T1_FIELD_TYPE_INTEGER;
if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY )
if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
field->type == T1_FIELD_TYPE_BBOX )
fieldrec.type = T1_FIELD_TYPE_FIXED;
#endif
ps_parser_to_token_array( parser, elements,
T1_MAX_TABLE_ELEMENTS, &num_elements );
@ -1057,9 +1172,10 @@
old_cursor = parser->cursor;
old_limit = parser->limit;
/* we store the elements count */
*(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
(FT_Byte)num_elements;
/* we store the elements count if necessary */
if ( field->type != T1_FIELD_TYPE_BBOX )
*(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
(FT_Byte)num_elements;
/* we now load each element, adjusting the field.offset on each one */
token = elements;

View File

@ -242,7 +242,7 @@
return axismap->design_points[j - 1] +
FT_MulDiv( t,
axismap->design_points[j] -
axismap->design_points[j] -
axismap->design_points[j - 1],
1L );
}
@ -732,7 +732,7 @@
FT_Memory memory = face->root.memory;
T1_ToTokenArray( parser, axis_tokens,
T1_ToTokenArray( parser, axis_tokens,
T1_MAX_MM_AXIS, &num_axis );
if ( num_axis < 0 )
{
@ -1724,59 +1724,32 @@
cur = parser->root.cursor;
/* look for `FontDirectory' which causes problems for some fonts */
if ( *cur == 'F' && cur + 25 < limit &&
ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
{
FT_Byte* cur2;
/* skip the `FontDirectory' keyword */
T1_Skip_PS_Token( parser );
T1_Skip_Spaces ( parser );
cur = cur2 = parser->root.cursor;
/* look up the `known' keyword */
while ( cur < limit )
{
if ( *cur == 'k' && cur + 5 < limit &&
ft_strncmp( (char*)cur, "known", 5 ) == 0 )
break;
T1_Skip_PS_Token( parser );
if ( parser->root.error )
goto Exit;
T1_Skip_Spaces( parser );
cur = parser->root.cursor;
}
if ( cur < limit )
{
T1_TokenRec token;
/* skip the `known' keyword and the token following it */
T1_Skip_PS_Token( parser );
T1_ToToken( parser, &token );
/* if the last token was an array, skip it! */
if ( token.type == T1_TOKEN_TYPE_ARRAY )
cur2 = parser->root.cursor;
}
parser->root.cursor = cur2;
have_integer = 0;
}
/* look for `eexec' */
else if ( *cur == 'e' && cur + 5 < limit &&
ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
/* cur[5] must be a token delimiter; */
/* eexec encryption is optional, so look for `eexec' */
if ( *cur == 'e' && cur + 5 < limit &&
ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
break;
/* cur[9] must be a token delimiter; */
/* look for `closefile' which ends the eexec section */
else if ( *cur == 'c' && cur + 9 < limit &&
else if ( *cur == 'c' && cur + 9 < limit &&
ft_strncmp( (char*)cur, "closefile", 9 ) == 0 )
break;
#ifdef TO_BE_DONE
/* in a synthetic font the base font starts after a */
/* `FontDictionary' token that is placed after a Private dict */
/* cur[13] must be a token delimiter */
else if ( *cur == 'F' && cur + 13 < limit &&
ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
{
if ( loader->private_encountered )
loader->fontdir_after_private = 1;
parser->root.cursor += 13;
}
#endif
/* check whether we have an integer */
else if ( ft_isdigit( *cur ) )
{
@ -1969,7 +1942,7 @@
{
FT_UInt n;
for ( n = 0; n < T1_FIELD_COUNT; n++ )
keyword_flags[n] = 0;
@ -1989,7 +1962,7 @@
keyword_flags );
if ( error )
goto Exit;
/* ensure even-ness of `num_blue_values' */
priv->num_blue_values &= ~1;