updated version of the experimental Type 1 driver

(this thing now works even better than the "regular"
driver, but is much smaller).

Provides no hinter !!
This commit is contained in:
David Turner 2000-02-15 12:55:57 +00:00
parent 861ba624db
commit 95bec28220
11 changed files with 1198 additions and 429 deletions

View File

@ -108,16 +108,16 @@ T1Z_COMPILE := $(FT_COMPILE) $(T1Z_INCLUDE:%=$I%)
T1Z_DRV_SRC := $(T1Z_DIR_)t1parse.c \
$(T1Z_DIR_)t1load.c \
$(T1Z_DIR_)t1driver.c \
$(T1Z_DIR_)t1encode.c \
$(T1Z_DIR_)t1afm.c \
$(T1Z_DIR_)t1gload.c
# Type1 driver headers
#
T1Z_DRV_H := $(T1Z_DIR_)t1errors.h \
$(T1Z_DIR_)t1config.h \
$(T1SHARED_H) \
$(T1Z_DRV_SRC:%.c=%.h)
$(T1Z_DIR_)t1config.h \
$(T1SHARED_H) \
$(T1Z_DRV_SRC:%.c=%.h)
# driver object(s)

222
src/type1z/t1afm.c Normal file
View File

@ -0,0 +1,222 @@
/***************************************************************************
*
* t1afm.c - support for reading Type 1 AFM files
*
*
***************************************************************************/
#include <t1afm.h>
#include <ftstream.h>
#include <t1types.h>
#include <stdlib.h> /* for qsort */
LOCAL_FUNC
void T1_Done_AFM( FT_Memory memory, T1_AFM* afm )
{
FREE( afm->kern_pairs );
afm->num_pairs = 0;
}
#undef IS_KERN_PAIR
#define IS_KERN_PAIR(p) ( p[0] == 'K' && p[1] == 'P' )
#define IS_ALPHANUM(c) ( (c >= 'A' && c <= 'Z') || \
(c >= 'a' && c <= 'z') || \
(c >= '0' && c <= '9') || \
(c == '_' && c == '.') )
/* read a glyph name and return the equivalent glyph index */
static
FT_UInt afm_atoindex( FT_Byte* *start, FT_Byte* limit, T1_Font* type1 )
{
FT_Byte* p = *start;
FT_Int len;
FT_UInt result = 0;
char temp[64];
/* skip whitespace */
while ( (*p == ' ' || *p == '\t' || *p == ':' || *p == ';') && p < limit )
p++;
*start = p;
/* now, read glyph name */
while ( IS_ALPHANUM(*p) && p < limit ) p++;
len = p - *start;
if (len > 0 && len < 64)
{
FT_Int n;
/* copy glyph name to intermediate array */
MEM_Copy( temp, start, len );
temp[len] = 0;
/* lookup glyph name in face array */
for ( n = 0; n < type1->num_glyphs; n++ )
{
char* gname = (char*)type1->glyph_names;
if ( gname && gname[0] == temp[0] && strcmp(gname,temp) == 0 )
{
result = n;
break;
}
}
}
*start = p;
return result;
}
/* read an integer */
static
int afm_atoi( FT_Byte** start, FT_Byte* limit )
{
FT_Byte* p = *start;
int sum = 0;
/* skip everything that is not a number */
while ( p < limit && (*p < '0' || *p > '9') )
p++;
while ( p < limit && (*p >= '0' || *p < '9') )
{
sum = sum*10 + (*p - '0');
p++;
}
*start = p;
return sum;
}
#undef KERN_INDEX
#define KERN_INDEX(g1,g2) (((T1_ULong)g1 << 16) | g2)
/* compare two kerning pairs */
static
int compare_kern_pairs( const void* a, const void* b )
{
T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
T1_ULong index1 = KERN_INDEX(pair1->glyph1,pair1->glyph2);
T1_ULong index2 = KERN_INDEX(pair2->glyph1,pair2->glyph2);
return ( index1 < index2 ? -1 :
( index1 > index2 ? 1 : 0 ));
}
/* parse an AFM file - for now, only read the kerning pairs */
LOCAL_FUNC
FT_Error T1_Read_AFM( FT_Stream stream,
FT_Face t1_face )
{
FT_Error error;
FT_Memory memory = stream->memory;
FT_Byte* start;
FT_Byte* limit;
FT_Byte* p;
FT_Int count = 0;
T1_Kern_Pair* pair;
T1_Font* type1 = &((T1_Face)t1_face)->type1;
T1_AFM* afm = 0;
if ( !ACCESS_Frame(stream->size) )
return error;
start = (FT_Byte*)stream->cursor;
limit = (FT_Byte*)stream->limit;
p = start;
/* we are now going to count the occurences of "KP" or "KPX" in */
/* the AFM file.. */
count = 0;
for ( p = start; p < limit-3; p++ )
{
if ( IS_KERN_PAIR(p) )
count++;
}
/* Actually, kerning pairs are simply optional !! */
if (count == 0)
goto Exit;
/* allocate the pairs */
if ( ALLOC( afm, sizeof(*afm ) ) ||
ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) )
goto Exit;
/* now, read each kern pair */
pair = afm->kern_pairs;
afm->num_pairs = count;
/* save in face object */
((T1_Face)t1_face)->afm_data = afm;
for ( p = start; p < limit-3; p++ )
{
if ( IS_KERN_PAIR(p) )
{
FT_Byte* q;
/* skip keyword (KP or KPX) */
q = p+2;
if (*q == 'X') q++;
pair->glyph1 = afm_atoindex( &q, limit, type1 );
pair->glyph2 = afm_atoindex( &q, limit, type1 );
pair->kerning.x = afm_atoi( &q, limit );
pair->kerning.y = 0;
if ( p[2] != 'X' )
pair->kerning.y = afm_atoi( &q, limit );
pair++;
}
}
/* now, sort the kern pairs according to their glyph indices */
qsort( afm->kern_pairs, count, sizeof(T1_Kern_Pair), compare_kern_pairs );
Exit:
if (error)
FREE( afm );
FORGET_Frame();
return error;
}
/* find the kerning for a given glyph pair */
LOCAL_FUNC
void T1_Get_Kerning( T1_AFM* afm,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
{
T1_Kern_Pair *min, *mid, *max;
T1_ULong index = KERN_INDEX(glyph1,glyph2);
/* simple binary search */
min = afm->kern_pairs;
max = min + afm->num_pairs-1;
while (min <= max)
{
T1_ULong midi;
mid = min + (max-min)/2;
midi = KERN_INDEX(mid->glyph1,mid->glyph2);
if ( midi == index )
{
*kerning = mid->kerning;
return;
}
if ( midi < index ) min = mid+1;
else max = mid-1;
}
kerning->x = 0;
kerning->y = 0;
}

47
src/type1z/t1afm.h Normal file
View File

@ -0,0 +1,47 @@
/***************************************************************************
*
* t1afm.h - support for reading Type 1 AFM files
*
*
***************************************************************************/
#ifndef T1AFM_H
#define T1AFM_H
#include <ftobjs.h>
/* In this version, we only read the kerning table from the */
/* AFM file. We may add support for ligatures a bit later.. */
typedef struct T1_Kern_Pair_
{
FT_UInt glyph1;
FT_UInt glyph2;
FT_Vector kerning;
} T1_Kern_Pair;
typedef struct T1_AFM_
{
FT_Int num_pairs;
T1_Kern_Pair* kern_pairs;
} T1_AFM;
LOCAL_DEF
FT_Error T1_Read_AFM( FT_Stream stream,
FT_Face face );
LOCAL_DEF
void T1_Done_AFM( FT_Memory memory,
T1_AFM* afm );
LOCAL_DEF
void T1_Get_Kerning( T1_AFM* afm,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning );
#endif /* T1AFM_H */

View File

@ -42,4 +42,11 @@
/* */
#undef T1_CONFIG_OPTION_DISABLE_HINTER
/* Define this configuration macro if you want to prevent the */
/* compilation of "t1afm", which is in charge of reading Type1 */
/* AFM files into an existing face. Note that when set, the T1 */
/* driver will be unable to produce kerning distances.. */
/* */
#undef T1_CONFIG_OPTION_NO_AFM
#endif /* T1CONFIG_H */

View File

@ -17,13 +17,16 @@
#include <t1driver.h>
#include <t1gload.h>
#include <t1afm.h>
#include <ftdebug.h>
#include <ftstream.h>
#include <psnames.h>
#undef FT_COMPONENT
#define FT_COMPONENT trace_t1driver
#ifndef T1_CONFIG_OPTION_NO_AFM
/*************************************************************************/
/* */
/* <Function> */
@ -52,15 +55,68 @@
/* time). */
/* */
static
void* Get_Interface( FT_Driver* driver,
const FT_String* interface )
FTDriver_Interface Get_Interface( FT_Driver driver,
const FT_String* interface )
{
UNUSED(driver);
UNUSED(interface);
if ( strcmp( (const char*)interface, "attach_file" ) == 0 )
return (FTDriver_Interface)T1_Read_AFM;
return 0;
}
/*************************************************************************/
/* */
/* <Function> */
/* Get_Kerning */
/* */
/* <Description> */
/* A driver method used to return the kerning vector between two */
/* glyphs of the same face. */
/* */
/* <Input> */
/* face :: A handle to the source face object. */
/* */
/* left_glyph :: The index of the left glyph in the kern pair. */
/* */
/* right_glyph :: The index of the right glyph in the kern pair. */
/* */
/* <Output> */
/* kerning :: The kerning vector. This is in font units for */
/* scalable formats, and in pixels for fixed-sizes */
/* formats. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* Only horizontal layouts (left-to-right & right-to-left) are */
/* supported by this function. Other layouts, or more sophisticated */
/* kernings are out of scope of this method (the basic driver */
/* interface is meant to be simple). */
/* */
/* They can be implemented by format-specific interfaces. */
/* */
static
T1_Error Get_Kerning( T1_Face face,
T1_UInt left_glyph,
T1_UInt right_glyph,
T1_Vector* kerning )
{
T1_AFM* afm;
kerning->x = 0;
kerning->y = 0;
afm = (T1_AFM*)face->afm_data;
if (afm)
T1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
return T1_Err_Ok;
}
#endif
/******************************************************************/
/* */
/* <Function> Set_Char_Sizes */
@ -130,6 +186,171 @@
return T1_Reset_Size(size);
}
/*************************************************************************/
/* */
/* <Function> */
/* Get_Char_Index */
/* */
/* <Description> */
/* Uses a charmap to return a given character code's glyph index. */
/* */
/* <Input> */
/* charmap :: A handle to the source charmap object. */
/* charcode :: The character code. */
/* */
/* <Return> */
/* Glyph index. 0 means `undefined character code'. */
/* */
static
T1_UInt Get_Char_Index( FT_CharMap charmap,
T1_Long charcode )
{
T1_Face face;
T1_UInt result = 0;
PSNames_Interface* psnames;
face = (T1_Face)charmap->face;
psnames = (PSNames_Interface*)face->psnames;
if (psnames)
switch (charmap->encoding)
{
/********************************************************************/
/* */
/* Unicode encoding support */
/* */
case ft_encoding_unicode:
{
/* use the "psnames" module to synthetize the Unicode charmap */
result = psnames->lookup_unicode( &face->unicode_map,
(T1_ULong)charcode );
/* the function returns 0xFFFF when the Unicode charcode has */
/* no corresponding glyph.. */
if (result == 0xFFFF)
result = 0;
goto Exit;
}
/********************************************************************/
/* */
/* Custom Type 1 encoding */
/* */
case ft_encoding_adobe_custom:
{
T1_Encoding* encoding = &face->type1.encoding;
if (charcode >= encoding->code_first &&
charcode <= encoding->code_last)
{
result = encoding->char_index[charcode];
}
goto Exit;
}
/********************************************************************/
/* */
/* Adobe Standard & Expert encoding support */
/* */
default:
if (charcode < 256)
{
FT_UInt code;
FT_Int n;
const char* glyph_name;
code = psnames->adobe_std_encoding[charcode];
if (charmap->encoding == ft_encoding_adobe_expert)
code = psnames->adobe_expert_encoding[charcode];
glyph_name = psnames->adobe_std_strings(code);
if (!glyph_name) break;
for ( n = 0; n < face->type1.num_glyphs; n++ )
{
const char* gname = face->type1.glyph_names[n];
if ( gname && gname[0] == glyph_name[0] &&
strcmp( gname, glyph_name ) == 0 )
{
result = n;
break;
}
}
}
}
Exit:
return result;
}
static
T1_Error Init_Face( FT_Stream stream,
FT_Int face_index,
T1_Face face )
{
T1_Error error;
error = T1_Init_Face(stream, face_index, face);
if (!error)
{
FT_Face root = &face->root;
FT_CharMap charmap = face->charmaprecs;
/* synthetize a Unicode charmap if there is support in the "psnames" */
/* module.. */
if (face->psnames)
{
PSNames_Interface* psnames = (PSNames_Interface*)face->psnames;
if (psnames->unicode_value)
{
error = psnames->build_unicodes( root->memory,
face->type1.num_glyphs,
(const char**)face->type1.glyph_names,
&face->unicode_map );
if (!error)
{
root->charmap = charmap;
charmap->face = (FT_Face)face;
charmap->encoding = ft_encoding_unicode;
charmap->platform_id = 3;
charmap->encoding_id = 1;
charmap++;
}
/* simply clear the error in case of failure (which really) */
/* means that out of memory or no unicode glyph names */
error = 0;
}
}
/* now, support either the standard, expert, or custom encodings */
charmap->face = (FT_Face)face;
charmap->platform_id = 7; /* a new platform id for Adobe fonts ?? */
switch (face->type1.encoding_type)
{
case t1_encoding_standard:
charmap->encoding = ft_encoding_adobe_standard;
charmap->encoding_id = 0;
break;
case t1_encoding_expert:
charmap->encoding = ft_encoding_adobe_expert;
charmap->encoding_id = 1;
break;
default:
charmap->encoding = ft_encoding_adobe_custom;
charmap->encoding_id = 2;
break;
}
root->charmaps = face->charmaps;
root->num_charmaps = charmap - face->charmaprecs + 1;
face->charmaps[0] = &face->charmaprecs[0];
face->charmaps[1] = &face->charmaprecs[1];
}
return error;
}
/******************************************************************/
/* */
@ -206,7 +427,7 @@
/* */
EXPORT_FUNC
const FT_DriverInterface t1_driver_interface =
const FT_DriverInterface t1z_driver_interface =
{
sizeof( FT_DriverRec ),
sizeof( T1_FaceRec ),
@ -214,18 +435,28 @@
sizeof( T1_GlyphSlotRec ),
"type1",
100, /* driver version == 1.0 */
200, /* requires FreeType 2.0 or above */
100,
200,
0, /* format interface */
(FTDriver_initDriver) T1_Init_Driver,
(FTDriver_doneDriver) T1_Done_Driver,
(FTDriver_getInterface) Get_Interface,
(FTDriver_initFace) T1_Init_Face,
#ifdef T1_CONFIG_OPTION_NO_AFM
(FTDriver_getInterface) 0,
#else
(FTDriver_getInterface) Get_Interface,
#endif
(FTDriver_initFace) Init_Face,
(FTDriver_doneFace) T1_Done_Face,
#ifdef T1_CONFIG_OPTION_NO_AFM
(FTDriver_getKerning) 0,
#else
(FTDriver_getKerning) Get_Kerning,
#endif
(FTDriver_initSize) T1_Init_Size,
(FTDriver_doneSize) T1_Done_Size,
@ -236,36 +467,38 @@
(FTDriver_doneGlyphSlot) T1_Done_GlyphSlot,
(FTDriver_loadGlyph) T1_Load_Glyph,
(FTDriver_getCharIndex) 0,
(FTDriver_getCharIndex) Get_Char_Index,
};
/*************************************************************************/
/* */
/* <Function> */
/* getDriverInterface */
/* */
/* <Description> */
/* This function is used when compiling the font driver as a */
/* shared library (`.DLL' or `.so'). It will be used by the */
/* high-level library of FreeType to retrieve the address of the */
/* driver's generic interface. */
/* */
/* It shouldn't be implemented in a static build, as each driver must */
/* have the same function as an exported entry point. */
/* */
/* <Return> */
/* The address of the TrueType's driver generic interface. The */
/* format-specific interface can then be retrieved through the method */
/* interface->get_format_interface. */
/* */
#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
/******************************************************************/
/* */
/* <Function> Get_FreeType_Driver_Interface */
/* */
/* <Description> */
/* This function is used when compiling the TrueType driver */
/* as a shared library (.DLL or .so). It will be used by the */
/* high-level library of FreeType to retrieve the address of */
/* the driver's generic interface. */
/* */
/* It shouldn't be implemented in a static build, as each */
/* driver must have the same function as an exported entry */
/* point. */
/* */
/* <Return> */
/* address of TrueType's driver generic interface. The */
/* forma-specific interface can then be retrieved through */
/* the method interface->get_format_interface.. */
/* */
#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
EXPORT_FUNC
FT_DriverInterface* getDriverInterface( void )
{
return &t1_driver_interface;
}
#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */
#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */

View File

@ -22,7 +22,7 @@
#include <t1errors.h>
EXPORT_DEF
const FT_DriverInterface t1_driver_interface;
const FT_DriverInterface t1z_driver_interface;
#endif /* T1DRIVER_H */

View File

@ -17,9 +17,75 @@
#include <t1gload.h>
#include <ftdebug.h>
#include <t1encode.h>
#include <ftstream.h>
#undef FT_COMPONENT
#define FT_COMPONENT trace_t1gload
typedef enum T1_Operator_
{
op_none = 0,
op_endchar,
op_hsbw,
op_seac,
op_sbw,
op_closepath,
op_hlineto,
op_hmoveto,
op_hvcurveto,
op_rlineto,
op_rmoveto,
op_rrcurveto,
op_vhcurveto,
op_vlineto,
op_vmoveto,
op_dotsection,
op_hstem,
op_hstem3,
op_vstem,
op_vstem3,
op_div,
op_callothersubr,
op_callsubr,
op_pop,
op_return,
op_setcurrentpoint,
op_max /* never remove this one */
} T1_Operator;
static const T1_Int t1_args_count[ op_max ] =
{
0, /* none */
0, /* endchar */
2, /* hsbw */
5, /* seac */
4, /* sbw */
0, /* closepath */
1, /* hlineto */
1, /* hmoveto */
4, /* hvcurveto */
2, /* rlineto */
2, /* rmoveto */
6, /* rrcurveto */
4, /* vhcurveto */
1, /* vlineto */
1, /* vmoveto */
0, /* dotsection */
2, /* hstem */
6, /* hstem3 */
2, /* vstem */
6, /* vstem3 */
2, /* div */
-1, /* callothersubr */
1, /* callsubr */
0, /* pop */
0, /* return */
2 /* setcurrentpoint */
};
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
@ -264,17 +330,26 @@
if (outline->n_contours > 0)
outline->contours[ outline->n_contours-1 ] = outline->n_points-1;
outline->n_contours++;
return T1_Err_Ok;
}
/* if a path was begun, add its first on-curve point */
static
T1_Error start_point( T1_Builder* builder,
T1_Pos x,
T1_Pos y )
{
return builder->path_begun && add_point1( builder, x, y );
/* test wether we're building a new contour */
if (!builder->path_begun)
{
T1_Error error;
builder->path_begun = 1;
error = add_contour( builder );
if (error) return error;
}
return add_point1( builder, x, y );
}
@ -312,20 +387,22 @@
T1_Int lookup_glyph_by_stdcharcode( T1_Face face,
T1_Int charcode )
{
T1_Int n;
const T1_String* glyph_name;
T1_Int n;
const T1_String* glyph_name;
PSNames_Interface* psnames = (PSNames_Interface*)face->psnames;
/* check range of standard char code */
if (charcode < 0 || charcode > 255)
return -1;
glyph_name = t1_standard_strings[t1_standard_encoding[charcode]];
glyph_name = psnames->adobe_std_strings(
psnames->adobe_std_encoding[charcode]);
for ( n = 0; n < face->type1.num_glyphs; n++ )
{
T1_String* name = (T1_String*)face->type1.glyph_names[n];
if ( name && name[0] == glyph_name[0] && strcmp(name,glyph_name) == 0 )
if ( name && strcmp(name,glyph_name) == 0 )
return n;
}
@ -506,62 +583,364 @@
while ( ip < limit )
{
T1_Int* top = decoder->top;
T1_Operator op = op_none;
T1_Long value = 0;
/********************************************************************/
/* */
/* Decode operator or operand */
/* */
/* */
/* First of all, decompress operator or value */
switch (*ip++)
{
case 1: /* hstem */
case 3: /* vstem */
case 1: op = op_hstem; break;
case 3: op = op_vstem; break;
case 4: op = op_vmoveto; break;
case 5: op = op_rlineto; break;
case 6: op = op_hlineto; break;
case 7: op = op_vlineto; break;
case 8: op = op_rrcurveto; break;
case 9: op = op_closepath; break;
case 10: op = op_callsubr; break;
case 11: op = op_return; break;
case 13: op = op_hsbw; break;
case 14: op = op_endchar; break;
case 21: op = op_rmoveto; break;
case 22: op = op_hmoveto; break;
case 30: op = op_vhcurveto; break;
case 31: op = op_hvcurveto; break;
case 12:
{
Clear_Stack:
top = decoder->stack;
if (ip > limit)
{
FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+EOF)\n" ));
goto Syntax_Error;
}
switch (*ip++)
{
case 0: op = op_dotsection; break;
case 1: op = op_vstem3; break;
case 2: op = op_hstem3; break;
case 6: op = op_seac; break;
case 7: op = op_sbw; break;
case 12: op = op_div; break;
case 16: op = op_callothersubr; break;
case 17: op = op_pop; break;
case 33: op = op_setcurrentpoint; break;
default:
FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+%d)\n",
ip[-1] ));
goto Syntax_Error;
}
}
break;
case 255: /* four bytes integer */
{
if (ip+4 > limit)
{
FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" ));
goto Syntax_Error;
}
value = ((long)ip[0] << 24) |
((long)ip[1] << 16) |
((long)ip[2] << 8) |
ip[3];
ip += 4;
}
break;
default:
if (ip[-1] >= 32)
{
if (ip[-1] < 247)
value = (long)ip[-1] - 139;
else
{
if (++ip > limit)
{
FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" ));
goto Syntax_Error;
}
if (ip[-2] < 251)
value = ((long)(ip[-2]-247) << 8) + ip[-1] + 108;
else
value = -((((long)ip[-2]-251) << 8) + ip[-1] + 108 );
}
}
else
{
FT_ERROR(( "T1.Parse_CharStrings : invalid byte (%d)\n",
ip[-1] ));
goto Syntax_Error;
}
}
/********************************************************************/
/* */
/* Push value on stack, or process operator */
/* */
/* */
if ( op == op_none )
{
if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
{
FT_ERROR(( "T1.Parse_CharStrings : Stack overflow !!\n" ));
goto Syntax_Error;
}
FT_TRACE4(( " %ld", value ));
*top++ = value;
decoder->top = top;
}
else if ( op == op_callothersubr ) /* callothersubr */
{
FT_TRACE4(( " callothersubr" ));
if ( top - decoder->stack < 2 )
goto Stack_Underflow;
top -= 2;
switch ( top[1] )
{
case 1: /* start flex feature ---------------------- */
{
if ( top[0] != 0 ) goto Unexpected_OtherSubr;
decoder->flex_state = 1;
decoder->num_flex_vectors = 0;
if ( start_point(builder, x, y) ||
check_points(builder,6) ) goto Memory_Error;
}
break;
case 2: /* add flex vectors ------------------------ */
{
T1_Int index;
if ( top[0] != 0 ) goto Unexpected_OtherSubr;
/* note that we should not add a point for index 0 */
/* this will move our current position to the flex */
/* point without adding any point to the outline */
index = decoder->num_flex_vectors++;
if (index > 0 && index < 7)
add_point( builder,
x,
y,
(T1_Byte)( index==3 || index==6 ) );
}
break;
case 0: /* end flex feature ------------------------- */
{
if ( top[0] != 3 ) goto Unexpected_OtherSubr;
if ( decoder->flex_state == 0 ||
decoder->num_flex_vectors != 7 )
{
FT_ERROR(( "T1.Parse_CharStrings: unexpected flex end\n" ));
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.Parse_CharStrings: invalid flex charstring\n" ));
goto Syntax_Error;
}
ip += 6;
decoder->flex_state = 0;
break;
}
case 3: /* change hints ---------------------------- */
{
if ( top[0] != 1 ) goto Unexpected_OtherSubr;
/* eat the following "pop" */
if (ip+2 > limit)
{
FT_ERROR(( "T1.Parse_CharStrings: invalid escape (12+%d)\n",
ip[-1] ));
goto Syntax_Error;
}
if (ip[0] != 12 || ip[1] != 17)
{
FT_ERROR(( "T1.Parse_CharStrings: 'pop' expected, found (%d %d)\n",
ip[0], ip[1] ));
goto Syntax_Error;
}
ip += 2;
break;;
}
default:
Unexpected_OtherSubr:
FT_ERROR(( "T1.Parse_CharStrings: invalid othersubr [%d %d]!!\n",
top[0], top[1] ));
goto Syntax_Error;
}
decoder->top = top;
}
else /* general operator */
{
T1_Int num_args = t1_args_count[op];
if ( top - decoder->stack < num_args )
goto Stack_Underflow;
top -= num_args;
switch (op)
{
case op_endchar: /*************************************************/
{
FT_TRACE4(( " endchar" ));
close_contour( builder );
/* add current outline to the glyph slot */
builder->base.n_points += builder->current.n_points;
builder->base.n_contours += builder->current.n_contours;
/* return now !! */
FT_TRACE4(( "\n\n" ));
return T1_Err_Ok;
}
case op_hsbw: /****************************************************/
{
FT_TRACE4(( " hsbw" ));
builder->left_bearing.x += top[0];
builder->advance.x = top[1];
builder->advance.y = 0;
builder->last.x = x = top[0];
builder->last.y = y = 0;
/* the "metrics_only" indicates that we only want to compute */
/* the glyph's metrics (lsb + advance width), not load the */
/* rest of it.. so exit immediately */
if (builder->metrics_only)
return T1_Err_Ok;
break;
}
case 4: /* vmoveto */
case op_seac: /****************************************************/
/* return immediately after the processing */
return t1operator_seac( decoder, top[0], top[1],
top[2], top[3], top[4] );
case op_sbw: /****************************************************/
{
USE_ARGS(1);
y += top[0];
builder->path_begun = 1;
goto Clear_Stack;
FT_TRACE4(( " sbw" ));
builder->left_bearing.x += top[0];
builder->left_bearing.y += top[1];
builder->advance.x = top[2];
builder->advance.y = top[3];
builder->last.x = x = top[0];
builder->last.y = y = top[1];
/* the "metrics_only" indicates that we only want to compute */
/* the glyph's metrics (lsb + advance width), not load the */
/* rest of it.. so exit immediately */
if (builder->metrics_only)
return T1_Err_Ok;
break;
}
case 5: /* rlineto */
case op_closepath: /**********************************************/
{
FT_TRACE4(( " closepath" ));
close_contour( builder );
builder->path_begun = 0;
}
break;
case op_hlineto: /************************************************/
{
FT_TRACE4(( " hlineto" ));
if ( start_point( builder, x, y ) ) goto Memory_Error;
x += top[0];
goto Add_Line;
}
case op_hmoveto: /************************************************/
{
FT_TRACE4(( " hmoveto" ));
x += top[0];
break;
}
case op_hvcurveto: /**********************************************/
{
FT_TRACE4(( " hvcurveto" ));
if ( start_point( builder, x, y ) ||
check_points( builder, 3 ) ) goto Memory_Error;
x += top[0];
add_point( builder, x, y, 0 );
x += top[1];
y += top[2];
add_point( builder, x, y, 0 );
y += top[3];
add_point( builder, x, y, 1 );
break;
}
case op_rlineto: /*************************************************/
{
FT_TRACE4(( " rlineto" ));
if ( start_point( builder, x, y ) ) goto Memory_Error;
USE_ARGS(2);
x += top[0];
y += top[1];
Add_Line:
if (add_point1( builder, top[0], top[1] )) goto Memory_Error;
goto Clear_Stack;
if (add_point1( builder, x, y )) goto Memory_Error;
break;
}
case 6: /* hlineto */
case op_rmoveto: /*************************************************/
{
if ( start_point( builder, x, y ) ) goto Memory_Error;
USE_ARGS(1);
FT_TRACE4(( " rmoveto" ));
x += top[0];
goto Add_Line;
y += top[1];
break;
}
case 7: /* vlineto */
{
if ( start_point( builder, x, y ) ) goto Memory_Error;
USE_ARGS(1);
y += top[0];
goto Add_Line;
}
case 8: /* rrcurveto */
case op_rrcurveto: /***********************************************/
{
FT_TRACE4(( " rcurveto" ));
if ( start_point( builder, x, y ) ||
check_points( builder, 3 ) ) goto Memory_Error;
USE_ARGS(6);
x += top[0];
y += top[1];
add_point( builder, x, y, 0 );
@ -573,22 +952,64 @@
x += top[4];
y += top[5];
add_point( builder, x, y, 1 );
goto Clear_Stack;
break;
}
case 9: /* closepath */
case op_vhcurveto: /**********************************************/
{
close_contour( builder );
builder->path_begun = 0;
FT_TRACE4(( " vhcurveto" ));
if ( start_point( builder, x, y ) ||
check_points( builder, 3 ) ) goto Memory_Error;
y += top[0];
add_point( builder, x, y, 0 );
x += top[1];
y += top[2];
add_point( builder, x, y, 0 );
x += top[3];
add_point( builder, x, y, 1 );
break;
}
break;
case 10: /* callsubr */
case op_vlineto: /************************************************/
{
FT_TRACE4(( " vlineto" ));
if ( start_point( builder, x, y ) ) goto Memory_Error;
y += top[0];
goto Add_Line;
}
case op_vmoveto: /************************************************/
{
FT_TRACE4(( " vmoveto" ));
y += top[0];
break;
}
case op_div: /****************************************************/
{
FT_TRACE4(( " div" ));
if (top[1])
*top++ = top[0] / top[1];
else
{
FT_ERROR(( "T1.Parse_CharStrings : division by 0\n" ));
goto Syntax_Error;
}
break;
}
case op_callsubr: /***********************************************/
{
T1_Int index;
USE_ARGS(1);
FT_TRACE4(( " callsubr" ));
index = top[0];
if ( index < 0 || index >= num_subrs )
{
@ -618,13 +1039,21 @@
decoder->zone = zone;
ip = zone->base;
limit = zone->limit;
/* do not clear stack */
break;
}
break;
case 11: /* return */
case op_pop: /****************************************************/
{
FT_TRACE4(( " pop" ));
FT_ERROR(( "T1.Parse_CharStrings : unexpected POP\n" ));
goto Syntax_Error;
}
case op_return: /************************************************/
{
FT_TRACE4(( " return" ));
if ( zone <= decoder->zones )
{
FT_ERROR(( "T1.Parse_CharStrings : unexpected return\n" ));
@ -635,306 +1064,58 @@
ip = zone->cursor;
limit = zone->limit;
decoder->zone = zone;
break;
}
break;
case 13: /* hsbw */
case op_dotsection: /*********************************************/
{
USE_ARGS(2);
builder->left_bearing.x += top[0];
builder->advance.x = top[1];
builder->advance.y = 0;
builder->last.x = x = top[0];
builder->last.y = y = 0;
/* the "metrics_only" indicates that we only want to compute */
/* the glyph's metrics (lsb + advance width), not load the */
/* rest of it.. so exit immediately */
if (builder->metrics_only)
return T1_Err_Ok;
goto Clear_Stack;
FT_TRACE4(( " dotsection" ));
break;
}
case 14: /* endchar */
case op_hstem: /**************************************************/
{
close_contour( builder );
/* add current outline to the glyph slot */
builder->base.n_points += builder->current.n_points;
builder->base.n_contours += builder->current.n_contours;
/* return now !! */
return T1_Err_Ok;
FT_TRACE4(( " hstem" ));
break;
}
case 21: /* rmoveto */
case op_hstem3: /*************************************************/
{
USE_ARGS(2);
x += top[0];
y += top[1];
goto Clear_Stack;
FT_TRACE4(( " hstem3" ));
break;
}
case 22: /* hmoveto */
case op_vstem: /**************************************************/
{
USE_ARGS(1);
x += top[0];
goto Clear_Stack;
FT_TRACE4(( " vstem" ));
break;
}
case 30: /* vhcurveto */
case op_vstem3: /*************************************************/
{
if ( start_point( builder, x, y ) ||
check_points( builder, 3 ) ) goto Memory_Error;
USE_ARGS(4);
y += top[0];
add_point( builder, x, y, 0 );
x += top[1];
y += top[2];
add_point( builder, x, y, 0 );
x += top[3];
add_point( builder, x, y, 1 );
goto Clear_Stack;
FT_TRACE4(( " vstem3" ));
break;
}
case 31: /* hvcurveto */
case op_setcurrentpoint: /*****************************************/
{
if ( start_point( builder, x, y ) ||
check_points( builder, 3 ) ) goto Memory_Error;
USE_ARGS(4);
x += top[0];
add_point( builder, x, y, 0 );
x += top[1];
y += top[2];
add_point( builder, x, y, 0 );
y += top[3];
add_point( builder, x, y, 1 );
goto Clear_Stack;
FT_TRACE4(( " setcurrentpoint" ));
FT_ERROR(( "T1.Parse_CharStrings : unexpected SETCURRENTPOINT\n" ));
goto Syntax_Error;
}
case 12:
{
if (ip > limit)
{
FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+EOF)\n" ));
goto Syntax_Error;
}
default:
FT_ERROR(( "T1.Parse_CharStrings : unhandled opcode %d\n", op ));
goto Syntax_Error;
}
switch (*ip++)
{
case 0: /* dotsection */
case 1: /* vstem3 */
case 2: /* hstem3 */
goto Clear_Stack;
case 6: /* seac */
{
USE_ARGS(5);
/* return immediately to implement an accented character */
return t1operator_seac( decoder,
top[0], top[1], top[3],
top[4], top[5] );
}
case 7: /* sbw */
{
USE_ARGS(4);
builder->left_bearing.x += top[0];
builder->left_bearing.y += top[1];
builder->advance.x = top[2];
builder->advance.y = top[3];
builder->last.x = x = top[0];
builder->last.y = y = top[1];
/* the "metrics_only" indicates that we only want to compute */
/* the glyph's metrics (lsb + advance width), not load the */
/* rest of it.. so exit immediately */
if (builder->metrics_only)
return T1_Err_Ok;
goto Clear_Stack;
}
case 12: /* div */
{
USE_ARGS(2);
top[0] /= top[1];
top++;
}
break;
case 16: /* callothersubr */
{
USE_ARGS(1);
switch (top[0])
{
case 1: /* start flex feature ---------------------- */
{
decoder->flex_state = 1;
decoder->num_flex_vectors = 0;
if ( start_point(builder, x, y) ||
check_points(builder,6) ) goto Memory_Error;
}
break;
decoder->top = top;
} /* general operator processing */
case 2: /* add flex vectors ------------------------ */
{
T1_Int index;
/* note that we should not add a point for index 0 */
/* this will move our current position to the flex */
/* point without adding any point to the outline */
index = decoder->num_flex_vectors++;
if (index > 0 && index < 7)
add_point( builder,
x,
y,
(T1_Byte)( index==3 || index==6 ) );
}
break;
case 0: /* end flex feature ------------------------- */
{
USE_ARGS(3); /* ignore parameters */
if ( decoder->flex_state == 0 ||
decoder->num_flex_vectors != 7 )
{
FT_ERROR(( "T1.Parse_CharStrings: unexpected flex end\n" ));
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.Parse_CharStrings: invalid flex charstring\n" ));
goto Syntax_Error;
}
ip += 6;
decoder->flex_state = 0;
decoder->top = top;
goto Clear_Stack;
}
case 3: /* change hints ---------------------------- */
{
/* eat the following "pop" */
if (ip+2 > limit)
{
FT_ERROR(( "T1.Parse_CharStrings: invalid escape (12+%d)\n",
ip[-1] ));
goto Syntax_Error;
}
if (ip[0] != 12 || ip[1] != 17)
{
FT_ERROR(( "T1.Parse_CharStrings: 'pop' expected, found (%d %d)\n",
ip[0], ip[1] ));
goto Syntax_Error;
}
ip += 2;
goto Clear_Stack;
}
default:
FT_ERROR(( "T1.Parse_CharStrings: invalid othersubr %d !!\n",
top[0] ));
goto Syntax_Error;
}
}
case 17: /* pop - should not happen !! */
{
FT_ERROR(( "T1.Parse_CharStrings : 'pop' should not happen !!\n" ));
goto Syntax_Error;
}
case 33: /* setcurrentpoint */
{
FT_ERROR(( "T1.Parse_CharStrings : 'setcurrentpoint' should not happen !!\n" ));
goto Syntax_Error;
}
default:
FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+%d)\n",
ip[-1] ));
goto Syntax_Error;
}
}
break; /* escape - 12 */
case 255: /* four bytes integer */
{
if (ip+4 > limit)
{
FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" ));
goto Syntax_Error;
}
*top++ = ((long)ip[0] << 24) |
((long)ip[1] << 16) |
((long)ip[2] << 8) |
ip[3];
ip += 4;
}
break;
default:
{
T1_Long v, v2;
v = ip[-1];
if (v < 32)
{
FT_ERROR(( "T1.Parse_CharStrings : invalid byte (%d)\n",
ip[-1] ));
goto Syntax_Error;
}
/* compute value ---- */
/* */
if (v < 247) /* 1-byte value */
v -= 139;
else
{
if (++ip > limit) /* 2-bytes value, check limits */
{
FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" ));
goto Syntax_Error;
}
v2 = ip[-1] + 108;
if (v < 251)
v = ((v-247) << 8) + v2;
else
v = -(((v-251) << 8) + v2);
}
/* store value - is there enough room ?*/
if ( top >= decoder->stack + T1_MAX_CHARSTRINGS_OPERANDS )
{
FT_ERROR(( "T1.Parse_CharStrings : Stack overflow !!\n" ));
goto Syntax_Error;
}
*top++ = v;
decoder->top = top;
}
} /* big switch */
} /* while ip < limit */
FT_TRACE4(( "..end..\n\n" ));
return error;
Syntax_Error:

View File

@ -63,10 +63,8 @@
#include <t1types.h>
#include <t1errors.h>
#include <t1encode.h>
#include <t1config.h>
#include <t1load.h>
#include <stdio.h>
#undef FT_COMPONENT
@ -345,8 +343,12 @@
{
if ( cur[1] == 'e' &&
cur[2] == 'f' &&
is_space(cur[-1]) &&
is_space(cur[3]) )
break;
{
FT_TRACE6(( "encoding end\n" ));
break;
}
}
/* otherwise, we must find a number before anything else */
@ -382,6 +384,7 @@
}
face->type1.encoding_type = t1_encoding_array;
parser->cursor = cur;
}
/* Otherwise, we should have either "StandardEncoding" or */
/* "ExpertEncoding" */
@ -433,6 +436,10 @@
index = T1_ToInt(parser);
if (!read_binary_data(parser,&size,&base)) return;
T1_Decrypt( base, size, 4330 );
size -= face->type1.lenIV;
base += face->type1.lenIV;
error = T1_Add_Table( table, index, base, size );
if (error) goto Fail;
}
@ -481,13 +488,19 @@
cur = parser->cursor;
if (cur >= limit) break;
/* we stop when we find a "def" */
/* we stop when we find a "def" or "end" keyword */
if (*cur == 'd' &&
cur+3 < limit &&
cur[1] == 'e' &&
cur[2] == 'f' )
break;
if (*cur == 'e' &&
cur+3 < limit &&
cur[1] == 'n' &&
cur[2] == 'd' )
break;
if (*cur != '/')
skip_blackspace(parser);
else
@ -497,6 +510,7 @@
while (cur2 < limit && is_alpha(*cur2)) cur2++;
len = cur2-cur-1;
error = T1_Add_Table( name_table, n, cur+1, len+1 );
if (error) goto Fail;
@ -505,7 +519,11 @@
parser->cursor = cur2;
if (!read_binary_data(parser,&size,&base)) return;
T1_Decrypt( base, size, 4330 );
size -= face->type1.lenIV;
base += face->type1.lenIV;
error = T1_Add_Table( code_table, n, base, size );
if (error) goto Fail;
@ -514,6 +532,7 @@
break;
}
}
loader->num_glyphs = n;
return;
Fail:
@ -562,7 +581,7 @@
T1_Error parse_dict( T1_Face face,
T1_Loader* loader,
T1_Byte* base,
T1_Int size )
T1_Long size )
{
T1_Parser* parser = &loader->parser;
@ -571,8 +590,8 @@
parser->error = 0;
{
T1_Byte* cur = base;
T1_Byte* limit = cur + size;
T1_Byte* cur = base;
T1_Byte* limit = cur + size;
for ( ;cur < limit; cur++ )
{
@ -587,7 +606,7 @@
while (cur2 < limit && is_alpha(*cur2)) cur2++;
len = cur2-cur;
if (len > 0)
if (len > 0 && len < 20)
{
/* now, compare the immediate name to the keyword table */
T1_KeyWord* keyword = (T1_KeyWord*)t1_keywords;
@ -617,6 +636,7 @@
return parser->error;
cur = parser->cursor;
break;
}
}
keyword++;
@ -631,9 +651,11 @@
static
void t1_init_loader( T1_Loader* loader, T1_Face face )
{
MEM_Set( loader, 0, sizeof(*loader) );
loader->num_glyphs = 0;
loader->num_chars = 0;
/* initialize the tables - simply set their 'init' field to 0 */
loader->encoding_table.init = 0;
loader->charstrings.init = 0;
loader->glyph_names.init = 0;
@ -685,6 +707,18 @@
/* to the Type1 data */
type1->num_glyphs = loader.num_glyphs;
if ( !loader.subrs.init )
{
FT_ERROR(( "T1.Open_Face: no subrs array in face !!\n" ));
error = FT_Err_Invalid_File_Format;
}
if ( !loader.charstrings.init )
{
FT_ERROR(( "T1.Open_Face: no charstrings array in face !!\n" ));
error = FT_Err_Invalid_File_Format;
}
loader.subrs.init = 0;
type1->num_subrs = loader.num_subrs;
type1->subrs_block = loader.subrs.block;

View File

@ -20,6 +20,7 @@
#include <t1gload.h>
#include <t1load.h>
#include <psnames.h>
/* Required by tracing mode */
#undef FT_COMPONENT
@ -164,12 +165,25 @@
T1_Face face )
{
T1_Error error;
PSNames_Interface* psnames;
(void)face_index;
(void)face;
face->root.num_faces = 1;
psnames = (PSNames_Interface*)face->psnames;
if (!psnames)
{
/* look-up the PSNames driver */
FT_Driver psnames_driver;
psnames_driver = FT_Get_Driver( face->root.driver->library, "psnames" );
if (psnames_driver)
face->psnames = (PSNames_Interface*)
(psnames_driver->interface.format_interface);
}
/* open the tokenizer, this will also check the font format */
error = T1_Open_Face( face );
if (error) goto Exit;

View File

@ -367,9 +367,18 @@
cur++;
/* now, read the coordinates */
for ( ; cur < limit; cur++ )
for ( ; cur < limit; )
{
c = *cur;
/* skip whitespace in front of data */
for (;;)
{
c = *cur;
if ( c != ' ' && c != '\t' ) break;
cur++;
if (cur >= limit) goto Exit;
}
if (count >= max_coords || c == ender)
break;
@ -414,9 +423,18 @@
cur++;
/* now, read the values */
for ( ; cur < limit; cur++ )
for ( ; cur < limit; )
{
c = *cur;
/* skip whitespace in front of data */
for (;;)
{
c = *cur;
if ( c != ' ' && c != '\t' ) break;
cur++;
if (cur >= limit) goto Exit;
}
if (count >= max_values || c == ender)
break;
@ -442,10 +460,19 @@
T1_String* result;
FT_Error error;
/* first of all, skip everything until we encounter a string */
while ( cur < limit && *cur != '(' ) cur++;
cur++;
if (cur >= limit) return 0;
/* XXX : some stupid fonts have a "Notice" or "Copyright" string */
/* that simply doesn't begin with an opening parenthesis, even */
/* though they have a closing one !!! E.g. "amuncial.pfb" */
/* */
/* We must deal with these ill-fated cases there. Note that */
/* these fonts didn't work with the old Type 1 driver as the */
/* notice/copyright was not recognized as a valid string token */
/* and made the old token parser commit errors.. */
while ( cur < limit && (*cur == ' ' || *cur == '\t')) cur++;
if (cur+1 >= limit) return 0;
if (*cur == '(') cur++; /* skip the opening parenthesis, if there is one */
*cursor = cur;
count = 0;
@ -470,7 +497,7 @@
/* now copy the string */
MEM_Copy( result, *cursor, len );
result[len] = '\0';
*cursor = cur;
return result;
}
@ -632,43 +659,44 @@
else
parser->in_pfb = 1;
/* now, try to load the "size" bytes of the "base" dictionary we */
/* found previously */
/* if it's a memory-based resource, set up pointers */
if ( !stream->read )
{
parser->base_dict = (T1_Byte*)stream->base + stream->pos;
parser->base_len = size;
parser->in_memory = 1;
/* check that the "size" field is valid */
if ( FILE_Skip(size) ) goto Exit;
}
else
{
/* read segment in memory */
if ( ALLOC( parser->base_dict, size ) ||
FILE_Read( parser->base_dict, size ) )
goto Exit;
}
/* Now check font format, we must see a '%!PS-AdobeFont-1' */
/* or a '%!FontType' */
{
if ( size <= 16 ||
( strncmp( (const char*)parser->base_dict, "%!PS-AdobeFont-1", 16 ) &&
strncmp( (const char*)parser->base_dict, "%!FontType", 10 ) ) )
{
FT_TRACE2(( "Not a Type1 font\n" ));
error = T1_Err_Invalid_File_Format;
}
else
{
parser->cursor = parser->base_dict;
parser->limit = parser->cursor + parser->base_len;
}
}
/* now, try to load the "size" bytes of the "base" dictionary we */
/* found previously */
/* if it's a memory-based resource, set up pointers */
if ( !stream->read )
{
parser->base_dict = (T1_Byte*)stream->base + stream->pos;
parser->base_len = size;
parser->in_memory = 1;
/* check that the "size" field is valid */
if ( FILE_Skip(size) ) goto Exit;
}
else
{
/* read segment in memory */
if ( ALLOC( parser->base_dict, size ) ||
FILE_Read( parser->base_dict, size ) )
goto Exit;
parser->base_len = size;
}
/* Now check font format, we must see a '%!PS-AdobeFont-1' */
/* or a '%!FontType' */
{
if ( size <= 16 ||
( strncmp( (const char*)parser->base_dict, "%!PS-AdobeFont-1", 16 ) &&
strncmp( (const char*)parser->base_dict, "%!FontType", 10 ) ) )
{
FT_TRACE2(( "Not a Type1 font\n" ));
error = T1_Err_Invalid_File_Format;
}
else
{
parser->cursor = parser->base_dict;
parser->limit = parser->cursor + parser->base_len;
}
}
Exit:
if (error && !parser->in_memory)

View File

@ -34,5 +34,8 @@
#include <t1objs.c>
#include <t1driver.c>
#include <t1gload.c>
#include <t1encode.c>
#ifndef T1_CONFIG_OPTION_NO_AFM
#include <t1afm.c>
#endif