blob: 3c2e5c2f76483468c5911b9eaa4890e1f4e35a40 [file] [log] [blame]
#include <ftconfig.h>
#include <ftdebug.h>
#include <t1types.h>
#include <t1tokens.h>
#include <t1parse.h>
#include <stdio.h>
#undef FT_COMPONENT
#define FT_COMPONENT trace_t1load
typedef T1_Error (*T1_Parse_Func)( T1_Parser* parser );
/*************************************************************************/
/* */
/* <Function> Init_T1_Parser */
/* */
/* <Description> */
/* Initialise a given parser object to build a given T1_Face */
/* */
/* <Input> */
/* parser :: handle to the newly built parser object */
/* face :: handle to target T1 face object */
/* */
LOCAL_FUNC
void Init_T1_Parser( T1_Parser* parser,
T1_Face face,
T1_Tokenizer tokenizer )
{
parser->error = 0;
parser->face = face;
parser->tokenizer = tokenizer;
parser->top = parser->stack;
parser->limit = parser->stack + T1_MAX_STACK_DEPTH;
parser->state_index = 0;
parser->state_stack[0] = dict_none;
parser->encoding_type = t1_encoding_none;
parser->encoding_names = 0;
parser->encoding_offsets = 0;
parser->encoding_lengths = 0;
parser->dump_tokens = 0;
face->type1.lenIV = 4; /* XXX : is it sure ?? */
}
/*************************************************************************/
/* */
/* <Function> Next_T1_Token */
/* */
/* <Description> */
/* grabs the next significant token from a parser's input stream. */
/* this function ignores a number of tokens, and translates */
/* alternate forms into their common ones.. */
/* */
/* <Input> */
/* parser :: handle to source parser */
/* */
/* <Output> */
/* token :: the extracted token descriptor */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
LOCAL_FUNC
T1_Error Next_T1_Token( T1_Parser* parser,
T1_Token* token )
{
T1_Error error;
T1_Tokenizer tokzer = parser->tokenizer;
L1:
error = Read_Token( tokzer );
if (error) return error;
/* We now must ignore a number of tokens like "dup", "executeonly", */
/* "readonly", etc... */
*token = tokzer->token;
if ( token->kind == tok_keyword )
switch( token->kind2 )
{
case key_dup:
case key_execonly:
case key_readonly:
case key_noaccess:
case key_userdict:
/* do nothing - loop */
goto L1;
/* We also translate some other keywords from their alternative */
/* to their "normal" form.. */
case key_NP_alternate:
token->kind2 = key_NP;
break;
case key_RD_alternate:
token->kind2 = key_RD;
break;
case key_ND_alternate:
token->kind2 = key_ND;
break;
default:
;
}
/* Dump the token when requested. This feature is only available */
/* in the 'error' and 'trace' debug levels.. */
#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE )
if ( parser->dump_tokens )
{
T1_String temp_string[128];
T1_Int len;
len = token->len;
if ( len > 127 ) len = 127;
strncpy( temp_string,
(T1_String*)tokzer->base + token->start,
len );
temp_string[len] = '\0';
FT_ERROR(( "%s\n", temp_string ));
}
#endif
return T1_Err_Ok;
}
static
T1_Error Expect_Keyword( T1_Parser* parser,
T1_TokenType keyword )
{
T1_Token token;
T1_Error error;
error = Next_T1_Token( parser, &token );
if (error) goto Exit;
if ( token.kind != tok_keyword ||
token.kind2 != keyword )
{
error = T1_Err_Syntax_Error;
FT_ERROR(( "T1.Parse: keyword '%s' expected.\n",
t1_keywords[ keyword - key_first_ ] ));
}
Exit:
return error;
}
static
T1_Error Expect_Keyword2( T1_Parser* parser,
T1_TokenType keyword1,
T1_TokenType keyword2 )
{
T1_Token token;
T1_Error error;
error = Next_T1_Token( parser, &token );
if (error) goto Exit;
if ( token.kind != tok_keyword ||
( token.kind2 != keyword1 &&
token.kind2 != keyword2 ) )
{
error = T1_Err_Syntax_Error;
FT_ERROR(( "T1.Parse: keyword '%s' or '%s' expected.\n",
t1_keywords[ keyword1 - key_first_ ],
t1_keywords[ keyword2 - key_first_ ] ));
}
Exit:
return error;
}
static
void Parse_Encoding( T1_Parser* parser )
{
T1_Token* token = parser->top+1;
FT_Memory memory = parser->face->root.memory;
T1_Encoding* encode = &parser->face->type1.encoding;
T1_Error error = 0;
if (token->kind == tok_keyword &&
(token->kind2 == key_StandardEncoding ||
token->kind2 == key_ExpertEncoding ) )
{
encode->num_chars = 256;
encode->code_first = 32;
encode->code_last = 255;
if ( ALLOC_ARRAY( encode->char_index, 256, T1_Short ) )
goto Exit;
encode->char_name = 0; /* no need to store glyph names */
/* Now copy the encoding */
switch (token->kind2)
{
case key_ExpertEncoding : parser->encoding_type = t1_encoding_expert;
default : parser->encoding_type = t1_encoding_standard; break;
}
}
else
{
FT_ERROR(( "T1.Parse_Encoding: invalid encoding type\n" ));
error = T1_Err_Syntax_Error;
}
Exit:
parser->error = error;
}
/**********************************************************************/
/* */
/* */
/* IMPLEMENTATION OF THE "DEF" KEYWORD DEPENDING ON */
/* CURRENT DICTIONARY STATE */
/* */
/* */
/**********************************************************************/
/**************************************************************************/
/* */
/* <Function> Do_Def_Font */
/* */
/* <Description> */
/* This function performs a 'def' when in the Font dictionary */
/* Its purpose is to build the T1_Face attributes directly from */
/* the stream.. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_Def_Font( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_Face face = parser->face;
T1_Font* type1 = &face->type1;
switch ( top[0].kind2 )
{
case imm_FontName:
/* in some cases, the /FontName is an immediate like */
/* /TimesNewRoman. In this case, we simply copy the */
/* token string (without the /).. */
if (top[1].kind == tok_immediate)
{
FT_Memory memory = parser->tokenizer->memory;
T1_Error error;
T1_Int len = top[1].len;
if ( ALLOC( type1->font_name, len+1 ) )
{
parser->error = error;
return error;
}
MEM_Copy( type1->font_name,
parser->tokenizer->base + top[1].start,
len );
type1->font_name[len] = '\0';
}
else
type1->font_name = CopyString( parser );
break;
case imm_Encoding:
Parse_Encoding( parser );
break;
case imm_PaintType:
type1->paint_type = (T1_Byte)CopyInteger( parser );
break;
case imm_FontType:
type1->font_type = (T1_Byte)CopyInteger( parser );
break;
case imm_FontMatrix:
CopyMatrix( parser, &type1->font_matrix );
break;
case imm_FontBBox:
CopyBBox( parser, &type1->font_bbox );
break;
case imm_UniqueID:
type1->unique_id = CopyInteger( parser );
break;
case imm_StrokeWidth:
type1->stroke_width = CopyInteger( parser );
break;
case imm_FontID:
type1->font_id = CopyInteger( parser );
break;
default:
/* ignore all other things */
parser->error = T1_Err_Ok;
}
return parser->error;
}
/**************************************************************************/
/* */
/* <Function> Do_Def_FontInfo */
/* */
/* <Description> */
/* This function performs a 'def' when in the FontInfo dictionary */
/* Its purpose is to build the T1_FontInfo structure directly from */
/* the stream.. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_Def_FontInfo( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_Font* info = &parser->face->type1;
switch ( top[0].kind2 )
{
case imm_version:
info->version = CopyString( parser );
break;
case imm_Notice:
info->notice = CopyString( parser );
break;
case imm_FullName:
info->full_name = CopyString( parser );
break;
case imm_FamilyName:
info->family_name = CopyString( parser );
break;
case imm_Weight:
info->weight = CopyString( parser );
break;
case imm_ItalicAngle:
info->italic_angle = CopyInteger( parser );
break;
case imm_isFixedPitch:
info->is_fixed_pitch = CopyBoolean( parser );
break;
case imm_UnderlinePosition:
info->underline_position = (T1_Short)CopyInteger( parser );
break;
case imm_UnderlineThickness:
info->underline_thickness = (T1_Short)CopyInteger( parser );
break;
default:
/* ignore all other things */
parser->error = T1_Err_Ok;
}
return parser->error;
}
/**************************************************************************/
/* */
/* <Function> Do_Def_Private */
/* */
/* <Description> */
/* This function performs a 'def' when in the Private dictionary */
/* Its purpose is to build the T1_Private structure directly from */
/* the stream.. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_Def_Private( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_Font* priv = &parser->face->type1;
switch ( top[0].kind2 )
{
case imm_RD: case imm_RD_alternate: /* Ignore the definitions */
case imm_ND: case imm_ND_alternate: /* of RD, NP, ND and their */
case imm_NP: case imm_NP_alternate: /* alternate forms ... */
parser->error = T1_Err_Ok;
break;
case imm_BlueValues:
CopyArray( parser, &priv->num_blues,
priv->blue_values, 14 );
break;
case imm_OtherBlues:
CopyArray( parser, &priv->num_other_blues,
priv->other_blues, 10 );
break;
case imm_FamilyBlues:
CopyArray( parser, &priv->num_family_blues,
priv->family_blues, 14 );
break;
case imm_FamilyOtherBlues:
CopyArray( parser, &priv->num_family_other_blues,
priv->family_other_blues, 10 );
break;
case imm_BlueScale:
priv->blue_scale = CopyFloat( parser, 0x10000 );
break;
case imm_BlueShift:
priv->blue_shift = CopyInteger( parser );
break;
case imm_BlueFuzz:
priv->blue_fuzz = CopyInteger( parser );
break;
case imm_StdHW:
CopyArray( parser, 0, (T1_Short*)&priv->standard_width, 1 );
break;
case imm_StdVW:
CopyArray( parser, 0, (T1_Short*)&priv->standard_height, 1 );
break;
case imm_StemSnapH:
CopyArray( parser, &priv->num_snap_widths,
priv->stem_snap_widths, 12 );
break;
case imm_StemSnapV:
CopyArray( parser, &priv->num_snap_heights,
priv->stem_snap_heights, 12 );
break;
case imm_ForceBold:
priv->force_bold = CopyBoolean( parser );
break;
case imm_LanguageGroup:
priv->language_group = CopyInteger( parser );
break;
case imm_password:
priv->password = CopyInteger( parser );
break;
case imm_UniqueID:
priv->unique_id = CopyInteger( parser );
break;
case imm_lenIV:
priv->lenIV = CopyInteger( parser );
break;
case imm_MinFeature:
CopyArray( parser, 0, priv->min_feature, 2 );
break;
default:
/* ignore all other things */
parser->error = T1_Err_Ok;
}
return parser->error;
}
/**************************************************************************/
/* */
/* <Function> Do_Def_Error */
/* */
/* <Description> */
/* This function returns a simple syntax error when invoked. It is */
/* ued for the "def" keyword when in the "encoding", "subrs", */
/* "othersubrs" and "charstrings" dictionary states.. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_Def_Error( T1_Parser* parser )
{
FT_ERROR(( "T1.Load : 'def' keyword encountered in bad dictionary/array\n" ));
parser->error = T1_Err_Syntax_Error;
return parser->error;
}
static
T1_Error Do_Def_Ignore( T1_Parser* parser )
{
(void)parser;
return T1_Err_Ok;
}
static
T1_Parse_Func def_funcs[ dict_max ] =
{
Do_Def_Error,
Do_Def_Font,
Do_Def_FontInfo,
Do_Def_Ignore,
Do_Def_Private,
Do_Def_Ignore,
Do_Def_Ignore,
Do_Def_Ignore,
Do_Def_Ignore,
Do_Def_Ignore,
Do_Def_Ignore,
};
/**********************************************************************/
/* */
/* */
/* IMPLEMENTATION OF THE "PUT" KEYWORD DEPENDING ON */
/* CURRENT DICTIONARY STATE */
/* */
/* */
/**********************************************************************/
/**************************************************************************/
/* */
/* <Function> Do_Put_Encoding */
/* */
/* <Description> */
/* This function performs a 'put' when in the Encoding array */
/* The glyph name is copied into the T1 recorder, and the charcode */
/* and glyph name pointer are written into the face object encoding */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_Put_Encoding( T1_Parser* parser )
{
T1_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Encoding* encode = &face->type1.encoding;
T1_Int index;
/* record and check the character code */
if ( top[0].kind != tok_number )
{
FT_TRACE4(( "T1.Parse.put: number expected\n" ));
goto Syntax_Error;
}
index = (T1_Int)CopyInteger( parser );
if (parser->error) return parser->error;
if ( index < 0 || index >= encode->num_chars )
{
FT_TRACE4(( "T1.Parse.put: invalid character code\n" ));
goto Syntax_Error;
}
/* record the immediate name */
if ( top[1].kind != tok_immediate )
{
FT_TRACE4(( "T1.Parse.put: immediate name expected\n" ));
goto Syntax_Error;
}
/* if the glyph name is '.notdef', store a NULL char name */
/* otherwise, record the glyph name.. */
if ( top[1].kind == imm_notdef )
{
parser->table.elements[ index ] = 0;
parser->table.lengths [ index ] = 0;
}
else
{
T1_String temp_name[128];
T1_Token* token = top+1;
T1_Int len = token->len-1;
/* copy immediate name */
if (len > 127) len = 127;
MEM_Copy( temp_name, parser->tokenizer->base + token->start+1, len );
temp_name[len] = '\0';
error = T1_Add_Table( &parser->table, index, (T1_Byte*)temp_name, len+1 );
/* adjust code_first and code_last */
if ( index < encode->code_first ) encode->code_first = index;
if ( index > encode->code_last ) encode->code_last = index;
}
return error;
Syntax_Error:
/* ignore the error, and simply clear the stack */
FT_TRACE4(( "T1.Put.Encoding: invalid syntax encountered\n" ));
parser->top = parser->stack;
return T1_Err_Ok;
}
/**********************************************************************/
/* */
/* */
/* IMPLEMENTATION OF THE "RD" KEYWORD DEPENDING ON */
/* CURRENT DICTIONARY STATE */
/* */
/* */
/**********************************************************************/
/**************************************************************************/
/* */
/* <Function> Do_RD_Subrs */
/* */
/* <Description> */
/* This function performs a 'RD' when in the Subrs dictionary */
/* It simply records the array of bytecodes/charstrings corresponding */
/* to the sub-routine.. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_RD_Subrs( T1_Parser* parser )
{
T1_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Tokenizer tokzer = parser->tokenizer;
T1_Int index, count;
/* record and check the character code */
if ( top[0].kind != tok_number ||
top[1].kind != tok_number )
{
FT_ERROR(( "T1.Parse.put: number expected\n" ));
goto Syntax_Error;
}
index = (T1_Int)CopyInteger( parser );
error = parser->error; if (error) goto Exit;
count = (T1_Int)CopyInteger( parser );
error = parser->error; if (error) goto Exit;
if ( index < 0 || index >= face->type1.num_subrs )
{
FT_ERROR(( "T1.Parse.put: invalid character code\n" ));
goto Syntax_Error;
}
/* decrypt charstring and skip them */
{
T1_Byte* base = tokzer->base + tokzer->cursor;
t1_decrypt( base, count, 4330 );
tokzer->cursor += count;
base += face->type1.lenIV;
count -= face->type1.lenIV;
error = T1_Add_Table( &parser->table, index, base, count );
}
/* consume the closing NP or 'put' */
error = Expect_Keyword2( parser, key_NP, key_put );
Exit:
return error;
Syntax_Error:
return T1_Err_Syntax_Error;
}
/**************************************************************************/
/* */
/* <Function> Do_RD_CharStrings */
/* */
/* <Description> */
/* This function performs a 'RD' when in the CharStrings dictionary */
/* It simply records the array of bytecodes/charstrings corresponding */
/* to the glyph program string. */
/* */
/* <Input> */
/* parser :: handle to current parser. */
/* */
/* <Return> */
/* Error code. 0 means success */
/* */
static
T1_Error Do_RD_Charstrings( T1_Parser* parser )
{
T1_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Tokenizer tokzer = parser->tokenizer;
T1_Int index, count;
/* check the character name argument */
if ( top[0].kind != tok_immediate )
{
FT_ERROR(( "T1.Parse.RD: immediate character name expected\n" ));
goto Syntax_Error;
}
/* check the count argument */
if ( top[1].kind != tok_number )
{
FT_ERROR(( "T1.Parse.put: number expected\n" ));
goto Syntax_Error;
}
parser->args++;
count = (T1_Int)CopyInteger( parser );
error = parser->error; if (error) goto Exit;
/* record the glyph name and get the corresponding glyph index */
if ( top[0].kind2 == imm_notdef )
index = 0;
else
{
T1_String temp_name[128];
T1_Token* token = top;
T1_Int len = token->len-1;
/* copy immediate name */
if (len > 127) len = 127;
MEM_Copy( temp_name, parser->tokenizer->base + token->start+1, len );
temp_name[len] = '\0';
index = parser->cur_name++;
error = T1_Add_Table( &parser->table, index*2, (T1_Byte*)temp_name, len+1 );
if (error) goto Exit;
}
/* decrypt and record charstring, then skip them */
{
T1_Byte* base = tokzer->base + tokzer->cursor;
t1_decrypt( base, count, 4330 );
tokzer->cursor += count; /* skip */
base += face->type1.lenIV;
count -= face->type1.lenIV;
error = T1_Add_Table( &parser->table, index*2+1, base, count );
}
/* consume the closing ND */
if (!error)
error = Expect_Keyword( parser, key_ND );
Exit:
return error;
Syntax_Error:
return T1_Err_Syntax_Error;
}
static
T1_Error Expect_Dict_Arguments( T1_Parser* parser,
T1_Int num_args,
T1_TokenType immediate,
T1_DictState new_state,
T1_Int *count )
{
/* check that we have enough arguments in the stack, including */
/* the 'dict' keyword.. */
if ( parser->top - parser->stack < num_args )
{
FT_ERROR(( "T1.Parse.Dict : expecting at least %d arguments",
num_args ));
goto Syntax_Error;
}
/* check that we have the correct immediate, if needed */
if ( num_args == 2 )
{
if ( parser->top[-2].kind != tok_immediate ||
parser->top[-2].kind2 != immediate )
{
FT_ERROR(( "T1.Parse.Dict : expecting '/%s' dictionary\n",
t1_immediates[ immediate - imm_first_ ] ));
goto Syntax_Error;
}
}
parser->args = parser->top-1;
/* check that the count argument is a number */
if ( parser->args->kind != tok_number )
{
FT_ERROR(( "T1.Parse.Dict : expecting numerical count argument for 'dict'\n" ));
goto Syntax_Error;
}
if (count)
{
*count = CopyInteger( parser );
if (parser->error) return parser->error;
}
/* save the dictionary state */
parser->state_stack[ ++parser->state_index ] = new_state;
/* consume the 'begin' keyword, and clear the stack */
parser->top -= num_args;
return Expect_Keyword( parser, key_begin );
Syntax_Error:
return T1_Err_Syntax_Error;
}
static
T1_Error Expect_Array_Arguments( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_Error error = T1_Err_Ok;
T1_DictState new_state;
T1_Int count;
T1_Face face = parser->face;
FT_Memory memory = face->root.memory;
/* Check arguments format */
if ( top - parser->stack < 2 )
{
FT_ERROR(( "T1.Parse.array: two arguments expected\n" ));
error = T1_Err_Stack_Underflow;
goto Exit;
}
parser->top -= 2;
top -= 2;
parser->args = top + 1;
if ( top[0].kind != tok_immediate )
{
FT_ERROR(( "T1.Parse.array: first argument must be an immediate name\n" ));
goto Syntax_Error;
}
if ( top[1].kind != tok_number )
{
FT_ERROR(( "T1.Parse.array: second argument must be a number\n" ));
goto Syntax_Error;
}
count = (T1_Int)CopyInteger( parser );
/* Is this an array we know about ?? */
switch ( top[0].kind2 )
{
case imm_Encoding:
{
T1_Encoding* encode = &face->type1.encoding;
new_state = dict_encoding;
encode->code_first = count;
encode->code_last = 0;
encode->num_chars = count;
/* allocate the table of character indexes. The table of */
/* character names is allocated through init_t1_recorder */
if ( ALLOC_ARRAY( encode->char_index, count, T1_Short ) )
return error;
error = T1_New_Table( &parser->table, count, memory );
if (error) goto Exit;
parser->encoding_type = t1_encoding_array;
}
break;
case imm_Subrs:
{
new_state = dict_subrs;
face->type1.num_subrs = count;
error = T1_New_Table( &parser->table, count, memory );
if (error) goto Exit;
}
break;
case imm_CharStrings:
new_state = dict_charstrings;
break;
default:
new_state = dict_unknown_array;
}
parser->state_stack[ ++parser->state_index ] = new_state;
Exit:
return error;
Syntax_Error:
return T1_Err_Syntax_Error;
}
static
T1_Error Finalise_Parsing( T1_Parser* parser )
{
T1_Face face = parser->face;
T1_Font* type1 = &face->type1;
FT_Memory memory = face->root.memory;
T1_Table* strings = &parser->table;
PSNames_Interface* psnames = (PSNames_Interface*)face->psnames;
T1_Int num_glyphs;
T1_Int n;
T1_Error error;
num_glyphs = type1->num_glyphs = parser->cur_name;
/* allocate glyph names and charstrings arrays */
if ( ALLOC_ARRAY( type1->glyph_names , num_glyphs, T1_String* ) ||
ALLOC_ARRAY( type1->charstrings , num_glyphs, T1_Byte* ) ||
ALLOC_ARRAY( type1->charstrings_len, num_glyphs, T1_Int* ) )
return error;
/* copy glyph names and charstrings offsets and lengths */
type1->charstrings_block = strings->block;
for ( n = 0; n < num_glyphs; n++ )
{
type1->glyph_names[n] = (T1_String*)strings->elements[2*n];
type1->charstrings[n] = strings->elements[2*n+1];
type1->charstrings_len[n] = strings->lengths [2*n+1];
}
/* now free the old tables */
FREE( strings->elements );
FREE( strings->lengths );
if (!psnames)
{
FT_ERROR(( "T1.Parse.Finalise : PSNames module missing !!\n" ));
return T1_Err_Unimplemented_Feature;
}
/* Compute encoding if required. */
if (parser->encoding_type == t1_encoding_none)
{
FT_ERROR(( "T1.Parse.Finalise : no encoding specified in font file\n" ));
return T1_Err_Syntax_Error;
}
{
T1_Int n;
T1_Encoding* encode = &type1->encoding;
encode->code_first = encode->num_chars-1;
encode->code_last = 0;
for ( n = 0; n < encode->num_chars; n++ )
{
T1_String** names;
T1_Int index;
T1_Int m;
switch (parser->encoding_type)
{
case t1_encoding_standard:
index = psnames->adobe_std_encoding[n];
names = 0;
break;
case t1_encoding_expert:
index = psnames->adobe_expert_encoding[n];
names = 0;
break;
default:
index = n;
names = (T1_String**)parser->encoding_offsets;
}
encode->char_index[n] = 0;
if (index)
{
T1_String* name;
if (names)
name = names[index];
else
name = (T1_String*)psnames->adobe_std_strings(index);
if ( name )
{
T1_Int len = strlen(name);
/* lookup glyph index from name */
for ( m = 0; m < num_glyphs; m++ )
{
if ( strncmp( type1->glyph_names[m], name, len ) == 0 )
{
encode->char_index[n] = m;
break;
}
}
if ( n < encode->code_first ) encode->code_first = n;
if ( n > encode->code_last ) encode->code_last = n;
}
}
}
parser->encoding_type = t1_encoding_none;
FREE( parser->encoding_names );
FREE( parser->encoding_lengths );
FREE( parser->encoding_offsets );
}
return T1_Err_Ok;
}
LOCAL_FUNC
T1_Error Parse_T1_FontProgram( T1_Parser* parser )
{
T1_Error error;
T1_Font* type1 = &parser->face->type1;
for (;;)
{
T1_Token token;
T1_Token* top;
T1_DictState dict_state;
T1_Int dict_index;
error = Next_T1_Token( parser, &token );
top = parser->top;
dict_index = parser->state_index;
dict_state = parser->state_stack[ dict_index ];
switch ( token.kind )
{
/* A keyword was detected */
case tok_keyword:
switch (token.kind2)
{
case key_dict:
switch (dict_state)
{
case dict_none:
/* All right, we're beggining the font dictionary */
/* check that we only have one number argument, then */
/* consume the 'begin' and change to 'dict_font' */
/* state.. */
error = Expect_Dict_Arguments( parser, 1, tok_error,
dict_font, 0 );
if (error) goto Exit;
/* clear stack from all the previous content. This */
/* could be some stupid Postscript code ... */
parser->top = parser->stack;
break;
case dict_font:
/* This must be the /FontInfo dictionary, so check */
/* That we have at least two arguments, that they */
/* are "/FontInfo" and a number, then change the */
/* dictionary state.. */
error = Expect_Dict_Arguments( parser, 2, imm_FontInfo,
dict_fontinfo, 0 );
if (error) goto Exit;
break;
case dict_none2:
error = Expect_Dict_Arguments( parser, 2, imm_Private,
dict_private, 0 );
if (error) goto Exit;
break;
case dict_private:
{
T1_Face face = parser->face;
T1_Int count;
error = Expect_Dict_Arguments( parser, 2, imm_CharStrings,
dict_charstrings, &count );
if (error) goto Exit;
type1->num_glyphs = count;
error = T1_New_Table( &parser->table, count*2, face->root.memory );
if (error) goto Exit;
/* record '.notdef' as the first glyph in the font */
error = T1_Add_Table( &parser->table, 0, (T1_Byte*)".notdef", 8 );
parser->cur_name = 1;
/* XXXXX : DO SOMETHING HERE */
}
break;
default:
/* All other uses are invalid */
FT_ERROR(( "T1.Parse: invalid use of the 'dict' keyword\n" ));
goto Syntax_Error;
}
break;
case key_array:
/* Are we in an array yet ? Is so, raise an error */
switch (dict_state)
{
case dict_encoding: case dict_subrs:
case dict_othersubrs: case dict_charstrings:
case dict_unknown_array:
FT_ERROR(( "T1.Parse.array: nested array definitions\n" ));
goto Syntax_Error;
default:
;
}
error = Expect_Array_Arguments( parser );
if (error) goto Exit;
break;
case key_ND:
case key_NP:
case key_def:
/* Are we in an array ? If so, finalise it.. */
switch ( dict_state )
{
case dict_encoding: /* finish encoding array */
{
/* copy table names to the face object */
T1_Done_Table( &parser->table );
parser->encoding_names = parser->table.block;
parser->encoding_lengths = parser->table.lengths;
parser->encoding_offsets = parser->table.elements;
parser->state_index--;
}
break;
case dict_subrs:
{
/* copy recorder sub-routines */
T1_Done_Table( &parser->table );
parser->subrs = parser->table.block;
type1->subrs = parser->table.elements;
type1->subrs_len = parser->table.lengths;
parser->state_index--;
}
break;
case dict_charstrings:
case dict_othersubrs:
case dict_unknown_array:
FT_ERROR(( "T1.Parser.def: unsupported array\n" ));
goto Syntax_Error;
break;
default: /* normal 'def' processing */
{
/* Check that we have sufficient operands in the stack */
if ( top >= parser->stack+2 )
{
/* Now check that the first operand is an immediate */
/* If so, call the appropriate "def" routine based */
/* on the current parser state.. */
if ( top[-2].kind == tok_immediate )
{
parser->top -= 2;
parser->args = parser->top + 1;
error = def_funcs[dict_state](parser);
}
else
{
/* This is an error, but some fonts contain some */
/* stupid Postscript code. We simply ignore */
/* an invalid 'def' by clearing the stack */
#if 0
FT_ERROR(( "T1.Parse.def: immediate expected\n" ));
goto Syntax_Error;
#else
parser->top = parser->stack;
#endif
}
}
else
{
FT_ERROR(( "T1.Parse.def: not enough arguments\n" ));
goto Stack_Underflow;
}
}
}
break;
case key_index:
if ( top <= parser->stack )
{
FT_ERROR(( "T1.Parse.index: not enough arguments\n" ));
goto Stack_Underflow;
}
/* simply ignore ?? */
parser->top --;
break;
case key_put:
/* Check that we have sufficient operands in stack */
if ( top < parser->stack+2 )
{
FT_ERROR(( "T1.Parse.put: not enough arguments\n" ));
goto Stack_Underflow;
}
parser->top -= 2;
parser->args = parser->top;
switch (dict_state)
{
case dict_encoding:
error = Do_Put_Encoding( parser );
if (error) goto Exit;
break;
case dict_unknown_array: /* ignore the put */
break;
default:
#if 0
FT_ERROR(( "T1.Parse.put: invalid context\n" ));
goto Syntax_Error;
#else
/* invalid context, simply ignore the put and */
/* clear the stack (stupid Postscript code..) */
FT_TRACE4(( "T1.Parse.put: invalid context. ignored.\n" ));
parser->top = parser->stack;
#endif
}
break;
case key_RD:
/* Check that we have sufficient operands in stack */
if ( top < parser->stack+2 )
{
FT_ERROR(( "T1.Parse.RD: not enough arguments\n" ));
goto Stack_Underflow;
}
parser->top -= 2;
parser->args = parser->top;
switch (dict_state)
{
case dict_subrs:
error = Do_RD_Subrs( parser );
if (error) goto Exit;
break;
case dict_charstrings:
error = Do_RD_Charstrings( parser );
if (error) goto Exit;
break;
default:
FT_ERROR(( "T1.Parse.RD: invalid context\n" ));
goto Syntax_Error;
}
break;
case key_end:
/* Were we in a dictionary or in an array ? */
if ( dict_index <= 0 )
{
FT_ERROR(( "T1.Parse.end: no dictionary defined\n" ));
goto Syntax_Error;
}
switch (dict_state)
{
/* Jump to the private dictionary if we're closing the */
/* /Font dictionary.. */
case dict_font:
goto Open_Private;
/* Exit the parser when closing the CharStrings dictionary */
case dict_charstrings:
return Finalise_Parsing( parser );
default:
/* Pop the current dictionary state and return to previous */
/* one. Consume the "def".. */
/* Because some buggy fonts (BitStream) have incorrect */
/* syntax, we never escape from the private dictionary */
if (dict_state != dict_private)
parser->state_index--;
/* many fonts use a NP instead of def or put, so */
/* we simply ignore the nest token.. */
#if 0
error = Expect_Keyword2( parser, key_def, key_put );
if (error) goto Exit;
#else
(void)Expect_Keyword2( parser, key_def, key_put );
#endif
}
break;
case key_for:
/* check that we have four arguments, and simply */
/* ignore them.. */
if ( top - parser->stack < 4 )
{
FT_ERROR(( "T1.Parse.for: not enough arguments\n" ));
goto Stack_Underflow;
}
parser->top -= 4;
break;
case key_currentdict:
Open_Private:
parser->state_index = 0;
parser->state_stack[0] = dict_none2;
error = Open_PrivateDict( parser->tokenizer );
if (error) goto Exit;
break;
case key_true:
case key_false:
case key_StandardEncoding:
case key_ExpertEncoding:
goto Push_Element;
default:
FT_ERROR(( "T1.Parser: invalid keyword in context\n" ));
error = T1_Err_Syntax_Error;
}
break;
/* A number was detected */
case tok_string:
case tok_program:
case tok_immediate:
case tok_array:
case tok_hexarray:
case tok_any:
case tok_number: /* push number on stack */
Push_Element:
if ( top >= parser->limit )
{
error = T1_Err_Stack_Overflow;
goto Exit;
}
else
*parser->top++ = token;
break;
/* anything else is an error per se the spec, but we */
/* frequently encountre stupid postscript code in fonts, */
/* so just ignore them.. */
default:
error = T1_Err_Ok; /* ignore token */
}
if (error)
return error;
}
Exit:
return error;
Syntax_Error:
return T1_Err_Syntax_Error;
Stack_Underflow:
return T1_Err_Stack_Underflow;
}