Al-Qurtas-Islamic-bank-The-.../src/type1/t1load.c

1595 lines
51 KiB
C

/***************************************************************************/
/* */
/* t1load.c */
/* */
/* Type 1 font loader (body). */
/* */
/* Copyright 1996-2000 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 <freetype/config/ftconfig.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/t1types.h>
#ifdef FT_FLAT_COMPILE
#include "t1tokens.h"
#include "t1parse.h"
#else
#include <type1/t1tokens.h>
#include <type1/t1parse.h>
#endif
#include <stdio.h>
#include <string.h> /* for strncpy(), strncmp(), strlen() */
/*************************************************************************/
/* */
/* 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 trace_t1load
typedef FT_Error (*T1_Parse_Func)( T1_Parser* parser );
/*************************************************************************/
/* */
/* <Function> */
/* Init_T1_Parser */
/* */
/* <Description> */
/* Initializes a given parser object to build a given T1_Face. */
/* */
/* <InOut> */
/* parser :: A handle to the newly built parser object. */
/* */
/* <Input> */
/* face :: A handle to the target Type 1 face object. */
/* */
/* tokenizer :: A handle to the target Type 1 token manager. */
/* */
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.private_dict.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 :: A handle to the source parser. */
/* */
/* <Output> */
/* token :: The extracted token descriptor. */
/* */
/* <Return> */
/* FreeTyoe error code. 0 means success. */
/* */
LOCAL_FUNC
FT_Error Next_T1_Token( T1_Parser* parser,
T1_Token* token )
{
FT_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:
;
}
#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE )
/* Dump the token when requested. This feature is only available */
/* in the `error' and `trace' debug levels. */
if ( parser->dump_tokens )
{
FT_String temp_string[128];
FT_Int len;
len = token->len;
if ( len > 127 )
len = 127;
strncpy( temp_string,
(FT_String*)tokzer->base + token->start,
len );
temp_string[len] = '\0';
FT_ERROR(( "%s\n", temp_string ));
}
#endif /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE */
return T1_Err_Ok;
}
static
FT_Error Expect_Keyword( T1_Parser* parser,
T1_TokenType keyword )
{
T1_Token token;
FT_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(( "Expect_Keyword: keyword `%s' expected.\n",
t1_keywords[keyword - key_first_] ));
}
Exit:
return error;
}
static
FT_Error Expect_Keyword2( T1_Parser* parser,
T1_TokenType keyword1,
T1_TokenType keyword2 )
{
T1_Token token;
FT_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(( "Expect_Keyword2: 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;
FT_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, FT_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;
break;
default:
parser->encoding_type = t1_encoding_standard;
break;
}
}
else
{
FT_ERROR(( "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' if in the Font dictionary. Its */
/* purpose is to build the T1_Face attributes directly from the */
/* stream. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static
FT_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;
FT_Error error;
FT_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 = (FT_Byte)CopyInteger( parser );
break;
case imm_FontType:
type1->font_type = (FT_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->private_dict.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' if in the FontInfo dictionary. Its */
/* purpose is to build the T1_FontInfo structure directly from the */
/* stream. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeTyoe error code. 0 means success. */
/* */
static
FT_Error Do_Def_FontInfo( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_FontInfo* info = &parser->face->type1.font_info;
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 = (FT_Short)CopyInteger( parser );
break;
case imm_UnderlineThickness:
info->underline_thickness = (FT_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' if in the Private dictionary. Its */
/* purpose is to build the T1_Private structure directly from the */
/* stream. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeTyoe error code. 0 means success. */
/* */
static
FT_Error Do_Def_Private( T1_Parser* parser )
{
T1_Token* top = parser->top;
T1_Private* priv = &parser->face->type1.private_dict;
switch ( top[0].kind2 )
{
/* Ignore the definitions of RD, NP, ND, and their alternate forms */
case imm_RD:
case imm_RD_alternate:
case imm_ND:
case imm_ND_alternate:
case imm_NP:
case imm_NP_alternate:
parser->error = T1_Err_Ok;
break;
case imm_BlueValues:
CopyArray( parser, &priv->num_blue_values,
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, 0x10000L );
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, (FT_Short*)&priv->standard_width, 1 );
break;
case imm_StdVW:
CopyArray( parser, 0, (FT_Short*)&priv->standard_height, 1 );
break;
case imm_StemSnapH:
CopyArray( parser, &priv->num_snap_widths,
priv->snap_widths, 12 );
break;
case imm_StemSnapV:
CopyArray( parser, &priv->num_snap_heights,
priv->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 */
/* used for the `def' keyword if in the `encoding', `subrs', */
/* `othersubrs', and `charstrings' dictionary states. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static
FT_Error Do_Def_Error( T1_Parser* parser )
{
FT_ERROR(( "Do_Def_Error:" ));
FT_ERROR(( " `def' keyword encountered in bad dictionary/array\n" ));
parser->error = T1_Err_Syntax_Error;
return parser->error;
}
static
FT_Error Do_Def_Ignore( T1_Parser* parser )
{
FT_UNUSED( 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' if 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. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static
FT_Error Do_Put_Encoding( T1_Parser* parser )
{
FT_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Encoding* encode = &face->type1.encoding;
FT_Int index;
/* record and check the character code */
if ( top[0].kind != tok_number )
{
FT_TRACE4(( "Do_Put_Encoding: number expected\n" ));
goto Syntax_Error;
}
index = (FT_Int)CopyInteger( parser );
if ( parser->error )
return parser->error;
if ( index < 0 || index >= encode->num_chars )
{
FT_TRACE4(( "Do_Put_Encoding: invalid character code\n" ));
goto Syntax_Error;
}
/* record the immediate name */
if ( top[1].kind != tok_immediate )
{
FT_TRACE4(( "Do_Put_Encoding: 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
{
FT_String temp_name[128];
T1_Token* token = top + 1;
FT_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,
(FT_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(( "Do_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 an `RD' if in the Subrs dictionary. It */
/* simply records the array of bytecodes/charstrings corresponding to */
/* the sub-routine. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static
FT_Error Do_RD_Subrs( T1_Parser* parser )
{
FT_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Tokenizer tokzer = parser->tokenizer;
FT_Int index, count;
/* record and check the character code */
if ( top[0].kind != tok_number ||
top[1].kind != tok_number )
{
FT_ERROR(( "Do_RD_Subrs: number expected\n" ));
goto Syntax_Error;
}
index = (FT_Int)CopyInteger( parser );
error = parser->error;
if ( error )
goto Exit;
count = (FT_Int)CopyInteger( parser );
error = parser->error;
if ( error )
goto Exit;
if ( index < 0 || index >= face->type1.num_subrs )
{
FT_ERROR(( "Do_RD_Subrs: invalid character code\n" ));
goto Syntax_Error;
}
/* decrypt charstring and skip it */
{
FT_Byte* base = tokzer->base + tokzer->cursor;
tokzer->cursor += count;
/* some fonts use a value of -1 for lenIV to indicate that */
/* the charstrings are unencoded. */
/* */
/* Thanks to Tom Kacvinsky for pointing this out. */
/* */
if ( face->type1.private_dict.lenIV >= 0 )
{
t1_decrypt( base, count, 4330 );
base += face->type1.private_dict.lenIV;
count -= face->type1.private_dict.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 an `RD' if in the CharStrings dictionary. */
/* It simply records the array of bytecodes/charstrings corresponding */
/* to the glyph program string. */
/* */
/* <InOut> */
/* parser :: A handle to the current parser. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static
FT_Error Do_RD_Charstrings( T1_Parser* parser )
{
FT_Error error = T1_Err_Ok;
T1_Face face = parser->face;
T1_Token* top = parser->top;
T1_Tokenizer tokzer = parser->tokenizer;
FT_Int index, count;
/* check the character name argument */
if ( top[0].kind != tok_immediate )
{
FT_ERROR(( "Do_RD_Charstrings: immediate character name expected\n" ));
goto Syntax_Error;
}
/* check the count argument */
if ( top[1].kind != tok_number )
{
FT_ERROR(( "Do_RD_Charstrings: number expected\n" ));
goto Syntax_Error;
}
parser->args++;
count = (FT_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
{
FT_String temp_name[128];
T1_Token* token = top;
FT_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,
(FT_Byte*)temp_name, len + 1 );
if ( error )
goto Exit;
}
/* decrypt and record charstring, then skip them */
{
FT_Byte* base = tokzer->base + tokzer->cursor;
tokzer->cursor += count; /* skip */
if ( face->type1.private_dict.lenIV >= 0 )
{
t1_decrypt( base, count, 4330 );
base += face->type1.private_dict.lenIV;
count -= face->type1.private_dict.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
FT_Error Expect_Dict_Arguments( T1_Parser* parser,
FT_Int num_args,
T1_TokenType immediate,
T1_DictState new_state,
FT_Int* count )
{
/* check that we have enough arguments in the stack, including */
/* the `dict' keyword */
if ( parser->top - parser->stack < num_args )
{
FT_ERROR(( "Expect_Dict_Arguments: 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(( "Expect_Dict_Arguments: 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(( "Expect_Dict_Arguments:" ));
FT_ERROR(( " 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
FT_Error Expect_Array_Arguments( T1_Parser* parser )
{
T1_Token* top = parser->top;
FT_Error error = T1_Err_Ok;
T1_DictState new_state;
FT_Int count;
T1_Face face = parser->face;
FT_Memory memory = face->root.memory;
/* Check arguments format */
if ( top - parser->stack < 2 )
{
FT_ERROR(( "Expect_Array_Arguments: 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(( "Expect_Array_Arguments:" ));
FT_ERROR(( " first argument must be an immediate name\n" ));
goto Syntax_Error;
}
if ( top[1].kind != tok_number )
{
FT_ERROR(( "Expect_Array_Arguments:" ));
FT_ERROR(( " second argument must be a number\n" ));
goto Syntax_Error;
}
count = (FT_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 indices. The table of */
/* character names is allocated through init_t1_recorder(). */
if ( ALLOC_ARRAY( encode->char_index, count, FT_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
FT_Error Finalize_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;
FT_Int num_glyphs;
FT_Int n;
FT_Error error;
num_glyphs = type1->num_glyphs = parser->cur_name;
/* allocate glyph names and charstrings arrays */
if ( ALLOC_ARRAY( type1->glyph_names, num_glyphs, FT_String* ) ||
ALLOC_ARRAY( type1->charstrings, num_glyphs, FT_Byte* ) ||
ALLOC_ARRAY( type1->charstrings_len, num_glyphs, FT_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] = (FT_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(( "Finalize_Parsing: `PSNames' module missing!\n" ));
return T1_Err_Unimplemented_Feature;
}
/* compute encoding if required */
if ( parser->encoding_type == t1_encoding_none )
{
FT_ERROR(( "Finalize_Parsing: no encoding specified in font file\n" ));
return T1_Err_Syntax_Error;
}
{
FT_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++ )
{
FT_String** names;
FT_Int index;
FT_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 = (FT_String**)parser->encoding_offsets;
}
encode->char_index[n] = 0;
if ( index )
{
FT_String* name;
if ( names )
name = names[index];
else
name = (FT_String*)psnames->adobe_std_strings(index);
if ( name )
{
FT_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;
}
/*************************************************************************/
/* */
/* <Function> */
/* Parse_T1_FontProgram */
/* */
/* <Description> */
/* Parses a given Type 1 font file and builds its face object. */
/* */
/* <InOut> */
/* parser :: A handle to the target parser object. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* The parser contains a handle to the target face object. */
/* */
LOCAL_FUNC
FT_Error Parse_T1_FontProgram( T1_Parser* parser )
{
FT_Error error;
T1_Font* type1 = &parser->face->type1;
for (;;)
{
T1_Token token;
T1_Token* top;
T1_DictState dict_state;
FT_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 has been detected */
case tok_keyword:
switch ( token.kind2 )
{
case key_dict:
switch ( dict_state )
{
case dict_none:
/* All right, we are beginning 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;
FT_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,
(FT_Byte*)".notdef", 8 );
parser->cur_name = 1;
/* XXX: DO SOMETHING HERE */
}
break;
default:
/* All other uses are invalid */
FT_ERROR(( "Parse_T1_FontProgram:" ));
FT_ERROR(( " invalid use of `dict' keyword\n" ));
goto Syntax_Error;
}
break;
case key_array:
/* Are we in an array yet? If 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(( "Parse_T1_FontProgram: 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, finalize 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;
type1->subrs_block = parser->table.block;
parser->state_index--;
break;
case dict_charstrings:
case dict_othersubrs:
case dict_unknown_array:
FT_ERROR(( "Parse_T1_FontProgram: 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 */
/* stupid Postscript code. We simply ignore */
/* an invalid `def' by clearing the stack. */
#if 0
FT_ERROR(( "Parse_T1_FontProgram: immediate expected\n" ));
goto Syntax_Error;
#else
parser->top = parser->stack;
#endif
}
}
else
{
FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
goto Stack_Underflow;
}
}
break;
case key_index:
if ( top <= parser->stack )
{
FT_ERROR(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram: invalid context\n" ));
goto Syntax_Error;
#else
/* invalid context; simply ignore the `put' and */
/* clear the stack (stupid Postscript code) */
FT_TRACE4(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram: no dictionary defined\n" ));
goto Syntax_Error;
}
switch ( dict_state )
{
/* jump to the private dictionary if we are closing the */
/* `/Font' dictionary */
case dict_font:
goto Open_Private;
/* exit the parser when closing the CharStrings dictionary */
case dict_charstrings:
return Finalize_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 `NP' instead of `def' or `put', so */
/* we simply ignore the next 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(( "Parse_T1_FontProgram: 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(( "Parse_T1_FontProgram:" ));
FT_ERROR(( " invalid keyword in context\n" ));
error = T1_Err_Syntax_Error;
}
break;
/* check for the presence of `/BlendAxisTypes' -- we cannot deal */
/* with multiple master fonts, so we must return a correct error */
/* code to allow another driver to load them */
case tok_immediate:
if ( token.kind2 == imm_BlendAxisTypes )
{
error = FT_Err_Unknown_File_Format;
goto Exit;
}
/* fallthrough */
/* A number was detected */
case tok_string:
case tok_program:
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 encounter 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;
}
/* END */