ref: e3f41982a2391d2fcb61b8883af98aa4e5b82df1
parent: 15ee9b5542f22ee85325889414e657aa2c1fc4cd
author: Werner Lemberg <[email protected]>
date: Thu Oct 16 11:48:39 EDT 2003
Completely revised Type 42 parser. It now handles both fonts produced with ttftot42 (tested version 0.3.1) and TrueTypeToType42.ps (tested version May 2001; it is necessary to fix the broken header comment to be `%!PS-TrueTypeFont...'). * src/type42/t42objs.c (T42_GlyphSlot_Load): Change fourth parameter to `FT_UInt'. * src/type42/t42objs.h: Updated. * src/type42/t42parse.h (T42_ParserRec): Change type of `in_memory' to FT_Bool. (T42_Loader): Change type of `num_chars' and `num_glyphs' to FT_UInt. Add `swap_table' element. * src/type42/t42parse.c (T42_KEYWORD_COUNT, T1_ToFixed, T1_ToCoordArray, T1_ToTokenArray): Removed. (T1_ToBytes): New macro. (t42_is_alpha, t42_hexval): Removed. (t42_is_space): Handle `\0'. (t42_parse_encoding): Updated to use new PostScript parser routines from psaux. Handle `/Encoding [ ... ]' also. (T42_Load_Status): New enumeration. (t42_parse_sfnts): Updated to use new PostScript parser routines from psaux. (t42_parse_charstrings): Updated to use new PostScript parser routines from psaux. Handle `/CharStrings << ... >>' also. Don't expect that /.notdef is the first element in dictionary. Copy code from type1 module to handle this. (t42_parse_dict): Updated to use new PostScript parser routines from psaux. Remove code for synthetic fonts (which can't occur in Type 42 fonts). (t42_loader_done): Release `swap_table'. * src/psaux/psobjs.c (skip_string): Increase `cur' properly. * src/type1/t1load.c (parse_charstrings): Make test for `.notdef' faster.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,47 @@
-2003-10-15: Graham Asher <[email protected]>
+2003-10-16 Werner Lemberg <[email protected]>
+
+ Completely revised Type 42 parser. It now handles both fonts
+ produced with ttftot42 (tested version 0.3.1) and
+ TrueTypeToType42.ps (tested version May 2001; it is necessary to
+ fix the broken header comment to be `%!PS-TrueTypeFont...').
+
+ * src/type42/t42objs.c (T42_GlyphSlot_Load): Change fourth
+ parameter to `FT_UInt'.
+ * src/type42/t42objs.h: Updated.
+
+ * src/type42/t42parse.h (T42_ParserRec): Change type of `in_memory'
+ to FT_Bool.
+ (T42_Loader): Change type of `num_chars' and `num_glyphs' to
+ FT_UInt.
+ Add `swap_table' element.
+ * src/type42/t42parse.c (T42_KEYWORD_COUNT, T1_ToFixed,
+ T1_ToCoordArray, T1_ToTokenArray): Removed.
+ (T1_ToBytes): New macro.
+ (t42_is_alpha, t42_hexval): Removed.
+ (t42_is_space): Handle `\0'.
+ (t42_parse_encoding): Updated to use new PostScript parser routines
+ from psaux.
+ Handle `/Encoding [ ... ]' also.
+ (T42_Load_Status): New enumeration.
+ (t42_parse_sfnts): Updated to use new PostScript parser routines
+ from psaux.
+ (t42_parse_charstrings): Updated to use new PostScript parser
+ routines from psaux.
+ Handle `/CharStrings << ... >>' also.
+ Don't expect that /.notdef is the first element in dictionary. Copy
+ code from type1 module to handle this.
+ (t42_parse_dict): Updated to use new PostScript parser routines
+ from psaux.
+ Remove code for synthetic fonts (which can't occur in Type 42
+ fonts).
+ (t42_loader_done): Release `swap_table'.
+
+ * src/psaux/psobjs.c (skip_string): Increase `cur' properly.
+
+ * src/type1/t1load.c (parse_charstrings): Make test for `.notdef'
+ faster.
+
+2003-10-15 Graham Asher <[email protected]>
* src/autohint/ahglobal.c (blue_chars), src/winfonts/winfnt.c
(fnt_cmap_class_rec, fnt_cmap_class), src/bdf/bdflib.c (empty,
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -410,9 +410,7 @@
FT_Byte* limit = parser->limit;
- cur++;
-
- while ( cur < limit )
+ while ( ++cur < limit )
{
int d;
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -1190,9 +1190,7 @@
/* the format is simple: */
/* `/glyphname' + binary data */
- /* */
- /* note that we stop when we find a `def' */
- /* */
+
T1_Skip_Spaces( parser );
cur = parser->root.cursor;
@@ -1236,8 +1234,9 @@
/* add a trailing zero to the name table */
name_table->elements[n][len] = '\0';
- /* record index of /.notdef */
- if ( ft_strcmp( (const char*)".notdef",
+ /* record index of /.notdef */
+ if ( *cur == '.' &&
+ ft_strcmp( ".notdef",
(const char*)(name_table->elements[n]) ) == 0 )
{
notdef_index = n;
@@ -1274,7 +1273,7 @@
loader->num_glyphs = n;
- /* if /.notdef is found but does not occupy index 0, do our magic. */
+ /* if /.notdef is found but does not occupy index 0, do our magic. */
if ( ft_strcmp( (const char*)".notdef",
(const char*)name_table->elements[0] ) &&
notdef_found )
--- a/src/type42/t42drivr.c
+++ b/src/type42/t42drivr.c
@@ -24,10 +24,9 @@
/* 2) Incremental fonts making use of the GlyphDirectory keyword */
/* will be loaded, but the rendering will be using the TrueType */
/* tables. */
- /* 3) The sfnts array is expected to be ASCII, not binary. */
- /* 4) As for Type1 fonts, CDevProc is not supported. */
- /* 5) The Metrics dictionary is not supported. */
- /* 6) AFM metrics are not supported. */
+ /* 3) As for Type1 fonts, CDevProc is not supported. */
+ /* 4) The Metrics dictionary is not supported. */
+ /* 5) AFM metrics are not supported. */
/* */
/* In other words, this driver supports Type42 fonts derived from */
/* TrueType fonts in a non-CID manner, as done by usual conversion */
--- a/src/type42/t42objs.c
+++ b/src/type42/t42objs.c
@@ -53,7 +53,8 @@
if ( error )
goto Exit;
- error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
+ error = t42_parse_dict( face, &loader,
+ parser->base_dict, parser->base_len );
if ( type1->font_type != 42 )
{
@@ -65,7 +66,8 @@
/* to the Type1 data */
type1->num_glyphs = loader.num_glyphs;
- if ( !loader.charstrings.init ) {
+ if ( !loader.charstrings.init )
+ {
FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
error = T42_Err_Invalid_File_Format;
}
@@ -121,8 +123,10 @@
if ( ft_strcmp( (const char*)".notdef",
(const char*)glyph_name ) != 0 )
{
- if ( charcode < min_char ) min_char = charcode;
- if ( charcode > max_char ) max_char = charcode;
+ if ( charcode < min_char )
+ min_char = charcode;
+ if ( charcode > max_char )
+ max_char = charcode;
}
break;
}
@@ -149,12 +153,12 @@
FT_Int num_params,
FT_Parameter* params )
{
- FT_Error error;
+ FT_Error error;
FT_Service_PsNames psnames;
- PSAux_Service psaux;
- FT_Face root = (FT_Face)&face->root;
- T1_Font type1 = &face->type1;
- PS_FontInfo info = &type1->font_info;
+ PSAux_Service psaux;
+ FT_Face root = (FT_Face)&face->root;
+ T1_Font type1 = &face->type1;
+ PS_FontInfo info = &type1->font_info;
FT_UNUSED( num_params );
FT_UNUSED( params );
@@ -189,7 +193,7 @@
goto Exit;
}
- /* Now, load the font program into the face object */
+ /* Now load the font program into the face object */
/* Init the face object fields */
/* Now set up root face fields */
@@ -350,7 +354,7 @@
#if 0
/* Select default charmap */
- if (root->num_charmaps)
+ if ( root->num_charmaps )
root->charmap = root->charmaps[0];
#endif
}
@@ -452,8 +456,6 @@
}
-
-
FT_LOCAL_DEF( FT_Error )
T42_Size_Init( T42_Size size )
{
@@ -601,7 +603,7 @@
FT_LOCAL_DEF( FT_Error )
T42_GlyphSlot_Load( FT_GlyphSlot glyph,
FT_Size size,
- FT_Int glyph_index,
+ FT_UInt glyph_index,
FT_Int32 load_flags )
{
FT_Error error;
--- a/src/type42/t42objs.h
+++ b/src/type42/t42objs.h
@@ -102,7 +102,7 @@
FT_LOCAL( FT_Error )
T42_GlyphSlot_Load( FT_GlyphSlot glyph,
FT_Size size,
- FT_Int glyph_index,
+ FT_UInt glyph_index,
FT_Int32 load_flags );
FT_LOCAL( void )
--- a/src/type42/t42parse.c
+++ b/src/type42/t42parse.c
@@ -93,10 +93,6 @@
};
-#define T42_KEYWORD_COUNT \
- ( sizeof ( t42_keywords ) / sizeof ( t42_keywords[0] ) )
-
-
#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
#define T1_Done_Table( p ) \
do \
@@ -114,17 +110,15 @@
#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root )
-#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
-#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+#define T1_ToInt( p ) \
+ (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToBytes( p, b, m, n, d ) \
+ (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
-#define T1_ToCoordArray( p, m, c ) \
- (p)->root.funcs.to_coord_array( &(p)->root, m, c )
#define T1_ToFixedArray( p, m, f, t ) \
(p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
#define T1_ToToken( p, t ) \
(p)->root.funcs.to_token( &(p)->root, t )
-#define T1_ToTokenArray( p, t, m, c ) \
- (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
#define T1_Load_Field( p, f, o, m, pf ) \
(p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
@@ -195,9 +189,9 @@
}
/* Now check font format; we must see `%!PS-TrueTypeFont' */
- if (size <= 17 ||
- ( ft_strncmp( (const char*)parser->base_dict,
- "%!PS-TrueTypeFont", 17) ) )
+ if ( size <= 17 ||
+ ( ft_strncmp( (const char*)parser->base_dict,
+ "%!PS-TrueTypeFont", 17 ) ) )
error = T42_Err_Unknown_File_Format;
else
{
@@ -229,23 +223,11 @@
static int
- t42_is_alpha( FT_Byte c )
- {
- /* Note: we must accept "+" as a valid character, as it is used in */
- /* embedded type1 fonts in PDF documents. */
- /* */
- return ( ft_isalnum( c ) ||
- c == '.' ||
- c == '_' ||
- c == '-' ||
- c == '+' );
- }
-
-
- static int
t42_is_space( FT_Byte c )
{
- return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' );
+ return ( c == ' ' || c == '\t' ||
+ c == '\r' || c == '\n' || c == '\f' ||
+ c == '\0' );
}
@@ -288,8 +270,8 @@
matrix->yy = temp[3];
/* note that the offsets must be expressed in integer font units */
- offset->x = temp[4] >> 16;
- offset->y = temp[5] >> 16;
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
}
@@ -297,49 +279,53 @@
t42_parse_encoding( T42_Face face,
T42_Loader loader )
{
- T42_Parser parser = &loader->parser;
- FT_Byte* cur = parser->root.cursor;
- FT_Byte* limit = parser->root.limit;
+ T42_Parser parser = &loader->parser;
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
PSAux_Service psaux = (PSAux_Service)face->psaux;
- /* skip whitespace */
- while ( t42_is_space( *cur ) )
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+
+ if ( cur >= limit )
{
- cur++;
- if ( cur >= limit )
- {
- FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
- parser->root.error = T42_Err_Invalid_File_Format;
- return;
- }
+ FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
+ parser->root.error = T42_Err_Invalid_File_Format;
+ return;
}
- /* if we have a number, then the encoding is an array, */
- /* and we must load it now */
- if ( ft_isdigit( *cur ) )
+ /* if we have a number or `[', the encoding is an array, */
+ /* and we must load it now */
+ if ( ft_isdigit( *cur ) || *cur == '[' )
{
- T1_Encoding encode = &face->type1.encoding;
- FT_Int count, n;
- PS_Table char_table = &loader->encoding_table;
- FT_Memory memory = parser->root.memory;
+ T1_Encoding encode = &face->type1.encoding;
+ FT_UInt count, n;
+ PS_Table char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
FT_Error error;
+ FT_Bool only_immediates = 0;
- if ( encode->char_index )
- /* with synthetic fonts, it's possible we get here twice */
- return;
+ /* read the number of entries in the encoding; should be 256 */
+ if ( *cur == '[' )
+ {
+ count = 256;
+ only_immediates = 1;
+ parser->root.cursor++;
+ }
+ else
+ count = (FT_UInt)T1_ToInt( parser );
- /* read the number of entries in the encoding, should be 256 */
- count = (FT_Int)T1_ToInt( parser );
- if ( parser->root.error )
+ T1_Skip_Spaces( parser );
+ if ( parser->root.cursor >= limit )
return;
/* we use a T1_Table to store our charnames */
loader->num_chars = encode->num_chars = count;
- if ( FT_NEW_ARRAY( encode->char_index, count ) ||
- FT_NEW_ARRAY( encode->char_name, count ) ||
+ if ( FT_NEW_ARRAY( encode->char_index, count ) ||
+ FT_NEW_ARRAY( encode->char_name, count ) ||
FT_SET_ERROR( psaux->ps_table_funcs->init(
char_table, count, memory ) ) )
{
@@ -356,86 +342,97 @@
T1_Add_Table( char_table, n, notdef, 8 );
}
- /* Now, we will need to read a record of the form */
- /* ... charcode /charname ... for each entry in our table */
+ /* Now we need to read records of the form */
/* */
+ /* ... charcode /charname ... */
+ /* */
+ /* for each entry in our table. */
+ /* */
/* We simply look for a number followed by an immediate */
/* name. Note that this ignores correctly the sequence */
- /* that is often seen in type1 fonts: */
+ /* that is often seen in type42 fonts: */
/* */
/* 0 1 255 { 1 index exch /.notdef put } for dup */
/* */
/* used to clean the encoding array before anything else. */
/* */
- /* We stop when we encounter a `def'. */
+ /* Alternatively, if the array is directly given as */
+ /* */
+ /* /Encoding [ ... ] */
+ /* */
+ /* we only read immediates. */
- cur = parser->root.cursor;
- limit = parser->root.limit;
- n = 0;
+ n = 0;
- for ( ; cur < limit; )
+ while ( parser->root.cursor < limit )
{
- FT_Byte c;
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
-
- c = *cur;
-
- /* we stop when we encounter a `def' */
- if ( c == 'd' && cur + 3 < limit )
+ /* we stop when we encounter `def' or `]' */
+ if ( *cur == 'd' && cur + 3 < limit )
{
- if ( cur[1] == 'e' &&
- cur[2] == 'f' &&
- t42_is_space( cur[-1] ) &&
- t42_is_space( cur[3] ) )
+ if ( cur[1] == 'e' &&
+ cur[2] == 'f' &&
+ t42_is_space( cur[3] ) )
{
FT_TRACE6(( "encoding end\n" ));
+ cur += 3;
break;
}
}
+ if ( *cur == ']' )
+ {
+ FT_TRACE6(( "encoding end\n" ));
+ cur++;
+ break;
+ }
- /* otherwise, we must find a number before anything else */
- if ( ft_isdigit( c ) )
+ /* check whether we've found an entry */
+ if ( ft_isdigit( *cur ) || only_immediates )
{
FT_Int charcode;
- parser->root.cursor = cur;
- charcode = (FT_Int)T1_ToInt( parser );
- cur = parser->root.cursor;
+ if ( only_immediates )
+ charcode = n;
+ else
+ {
+ charcode = (FT_Int)T1_ToInt( parser );
+ T1_Skip_Spaces( parser );
+ }
- /* skip whitespace */
- while ( cur < limit && t42_is_space( *cur ) )
- cur++;
+ cur = parser->root.cursor;
- if ( cur < limit && *cur == '/' )
+ if ( *cur == '/' && cur + 2 < limit && n < count )
{
- /* bingo, we have an immediate name -- it must be a */
- /* character name */
- FT_Byte* cur2 = cur + 1;
FT_PtrDist len;
- while ( cur2 < limit && t42_is_alpha( *cur2 ) )
- cur2++;
+ cur++;
- len = cur2 - cur - 1;
+ parser->root.cursor = cur;
+ T1_Skip_PS_Token( parser );
+ len = parser->root.cursor - cur;
+
parser->root.error = T1_Add_Table( char_table, charcode,
- cur + 1, len + 1 );
+ cur, len + 1 );
char_table->elements[charcode][len] = '\0';
if ( parser->root.error )
return;
- cur = cur2;
+ n++;
}
}
else
- cur++;
+ T1_Skip_PS_Token( parser );
}
face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
parser->root.cursor = cur;
}
+
/* Otherwise, we should have either `StandardEncoding', */
/* `ExpertEncoding', or `ISOLatin1Encoding' */
else
@@ -452,7 +449,8 @@
ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
- else {
+ else
+ {
FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
parser->root.error = T42_Err_Invalid_File_Format;
}
@@ -460,36 +458,15 @@
}
- static FT_UInt
- t42_hexval( FT_Byte v )
+ typedef enum
{
- FT_UInt d;
+ BEFORE_START,
+ BEFORE_TABLE_DIR,
+ OTHER_TABLES
- d = (FT_UInt)( v - 'A' );
- if ( d < 6 )
- {
- d += 10;
- goto Exit;
- }
+ } T42_Load_Status;
- d = (FT_UInt)( v - 'a' );
- if ( d < 6 )
- {
- d += 10;
- goto Exit;
- }
- d = (FT_UInt)( v - '0' );
- if ( d < 10 )
- goto Exit;
-
- d = 0;
-
- Exit:
- return d;
- }
-
-
static void
t42_parse_sfnts( T42_Face face,
T42_Loader loader )
@@ -496,154 +473,176 @@
{
T42_Parser parser = &loader->parser;
FT_Memory memory = parser->root.memory;
- FT_Byte* cur = parser->root.cursor;
+ FT_Byte* cur;
FT_Byte* limit = parser->root.limit;
FT_Error error;
- FT_Int num_tables = 0, status;
- FT_ULong count, ttf_size = 0, string_size = 0;
- FT_Bool in_string = 0;
- FT_Byte v = 0;
+ FT_Int num_tables = 0;
+ FT_ULong count, ttf_size = 0;
+ FT_Long n, string_size, old_string_size, real_size;
+ FT_Byte* string_buf = NULL;
+ FT_Bool alloc = 0;
- /* The format is `/sfnts [ <...> <...> ... ] def' */
+ T42_Load_Status status;
- while ( t42_is_space( *cur ) )
- cur++;
- if (*cur++ == '[')
+ /* The format is */
+ /* */
+ /* /sfnts [ <hexstring> <hexstring> ... ] def */
+ /* */
+ /* or */
+ /* */
+ /* /sfnts [ */
+ /* <num_bin_bytes> RD <binary data> */
+ /* <num_bin_bytes> RD <binary data> */
+ /* ... */
+ /* ] def */
+ /* */
+ /* with exactly one space after the `RD' token. */
+
+ T1_Skip_Spaces( parser );
+
+ if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
{
- status = 0;
- count = 0;
- }
- else
- {
FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
error = T42_Err_Invalid_File_Format;
goto Fail;
}
- while ( cur < limit - 2 )
+ T1_Skip_Spaces( parser );
+ status = BEFORE_START;
+ old_string_size = 0;
+ count = 0;
+
+ while ( parser->root.cursor < limit )
{
- while ( t42_is_space( *cur ) )
- cur++;
+ cur = parser->root.cursor;
- switch ( *cur )
+ if ( *cur == ']' )
{
- case ']':
- parser->root.cursor = cur++;
- return;
+ parser->root.cursor++;
+ goto Exit;
+ }
- case '<':
- in_string = 1;
- string_size = 0;
- cur++;
- continue;
+ else if ( *cur == '<' )
+ {
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ goto Exit;
- case '>':
- if ( !in_string )
- {
- FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" ));
- error = T42_Err_Invalid_File_Format;
+ /* don't include delimiters */
+ string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
+ if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
goto Fail;
- }
- /* A string can have, as a last byte, */
- /* a zero byte for padding. If so, ignore it */
- if ( ( v == 0 ) && ( string_size % 2 == 1 ) )
- count--;
- in_string = 0;
- cur++;
- continue;
+ alloc = 1;
- case '%':
- if ( !in_string )
- {
- /* Comment found; skip till end of line */
- while ( *cur != '\n' )
- cur++;
- continue;
- }
- else
- {
- FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" ));
- error = T42_Err_Invalid_File_Format;
- goto Fail;
- }
+ parser->root.cursor = cur;
+ (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
+ old_string_size = string_size;
+ string_size = real_size;
+ }
- default:
- if ( !ft_isxdigit( *cur ) || !ft_isxdigit( *(cur + 1) ) )
+ else if ( ft_isdigit( *cur ) )
+ {
+ string_size = T1_ToInt( parser );
+
+ T1_Skip_PS_Token( parser ); /* `RD' */
+
+ string_buf = parser->root.cursor + 1; /* one space after `RD' */
+
+ parser->root.cursor += string_size + 1;
+ if ( parser->root.cursor >= limit )
{
- FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" ));
+ FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
error = T42_Err_Invalid_File_Format;
goto Fail;
}
-
- v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) );
- cur += 2;
- string_size++;
}
- switch ( status )
+ /* A string can have a trailing zero byte for padding. Ignore it. */
+ if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) )
+ string_size--;
+
+ for ( n = 0; n < string_size; n++ )
{
- case 0: /* The '[' was read, so load offset table, 12 bytes */
- if ( count < 12 )
+ switch ( status )
{
- face->ttf_data[count++] = v;
- continue;
- }
- else
- {
- num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
- status = 1;
- ttf_size = 12 + 16 * num_tables;
+ case BEFORE_START:
+ /* load offset table, 12 bytes */
+ if ( count < 12 )
+ {
+ face->ttf_data[count++] = string_buf[n];
+ continue;
+ }
+ else
+ {
+ num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+ status = BEFORE_TABLE_DIR;
+ ttf_size = 12 + 16 * num_tables;
- if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
- goto Fail;
- }
- /* No break, fall-through */
+ if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
+ goto Fail;
+ }
+ /* fall through */
- case 1: /* The offset table is read; read now the table directory */
- if ( count < ttf_size )
- {
- face->ttf_data[count++] = v;
- continue;
- }
- else
- {
- int i;
- FT_ULong len;
+ case BEFORE_TABLE_DIR:
+ /* the offset table is read; read the table directory */
+ if ( count < ttf_size )
+ {
+ face->ttf_data[count++] = string_buf[n];
+ continue;
+ }
+ else
+ {
+ int i;
+ FT_ULong len;
- for ( i = 0; i < num_tables; i++ )
- {
- FT_Byte* p = face->ttf_data + 12 + 16*i + 12;
+ for ( i = 0; i < num_tables; i++ )
+ {
+ FT_Byte* p = face->ttf_data + 12 + 16 * i + 12;
- len = FT_PEEK_ULONG( p );
- /* Pad to a 4-byte boundary length */
- ttf_size += ( len + 3 ) & ~3;
- }
+ len = FT_PEEK_ULONG( p );
- status = 2;
- face->ttf_size = ttf_size;
+ /* Pad to a 4-byte boundary length */
+ ttf_size += ( len + 3 ) & ~3;
+ }
- if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
- ttf_size + 1 ) )
- goto Fail;
- }
- /* No break, fall-through */
+ status = OTHER_TABLES;
+ face->ttf_size = ttf_size;
- case 2: /* We are reading normal tables; just swallow them */
- face->ttf_data[count++] = v;
+ if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
+ ttf_size + 1 ) )
+ goto Fail;
+ }
+ /* fall through */
+ case OTHER_TABLES:
+ /* all other tables are just copied */
+ if ( count >= ttf_size )
+ {
+ FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+ face->ttf_data[count++] = string_buf[n];
+ }
}
+
+ T1_Skip_Spaces( parser );
}
- /* If control reaches this point, the format was not valid */
+ /* if control reaches this point, the format was not valid */
error = T42_Err_Invalid_File_Format;
Fail:
parser->root.error = error;
+
+ Exit:
+ if ( alloc )
+ FT_FREE( string_buf );
}
@@ -651,23 +650,76 @@
t42_parse_charstrings( T42_Face face,
T42_Loader loader )
{
- T42_Parser parser = &loader->parser;
- PS_Table code_table = &loader->charstrings;
- PS_Table name_table = &loader->glyph_names;
- FT_Memory memory = parser->root.memory;
+ T42_Parser parser = &loader->parser;
+ PS_Table code_table = &loader->charstrings;
+ PS_Table name_table = &loader->glyph_names;
+ PS_Table swap_table = &loader->swap_table;
+ FT_Memory memory = parser->root.memory;
FT_Error error;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
FT_Byte* cur;
- FT_Byte* limit = parser->root.limit;
- FT_Int n;
+ FT_Byte* limit = parser->root.limit;
+ FT_UInt n;
+ FT_UInt notdef_index = 0;
+ FT_Byte notdef_found = 0;
- loader->num_glyphs = (FT_Int)T1_ToInt( parser );
- if ( parser->root.error )
- return;
+ T1_Skip_Spaces( parser );
+ if ( parser->root.cursor >= limit )
+ {
+ FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ if ( ft_isdigit( *parser->root.cursor ) )
+ {
+ loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+ }
+ else if ( *parser->root.cursor == '<' )
+ {
+ /* We have `<< ... >>'. Count the number of `/' in the dictionary */
+ /* to get its size. */
+ FT_UInt count = 0;
+
+
+ T1_Skip_PS_Token( parser );
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+
+ while ( parser->root.cursor < limit )
+ {
+ if ( *parser->root.cursor == '/' )
+ count++;
+ else if ( *parser->root.cursor == '>' )
+ {
+ loader->num_glyphs = count;
+ parser->root.cursor = cur; /* rewind */
+ break;
+ }
+ T1_Skip_PS_Token( parser );
+ T1_Skip_Spaces( parser );
+ }
+ }
+ else
+ {
+ FT_ERROR(( "t42_parse_charstrings: invalid token!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ if ( parser->root.cursor >= limit )
+ {
+ FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
/* initialize tables */
error = psaux->ps_table_funcs->init( code_table,
@@ -682,15 +734,20 @@
if ( error )
goto Fail;
+ /* Initialize table for swapping index notdef_index and */
+ /* index 0 names and codes (if necessary). */
+
+ error = psaux->ps_table_funcs->init( swap_table, 4, memory );
+ if ( error )
+ goto Fail;
+
n = 0;
for (;;)
{
- /* the format is simple: */
- /* `/glyphname' + index + def */
- /* */
- /* note that we stop when we find an `end' */
- /* */
+ /* The format is simple: */
+ /* `/glyphname' + index [+ def] */
+
T1_Skip_Spaces( parser );
cur = parser->root.cursor;
@@ -697,26 +754,34 @@
if ( cur >= limit )
break;
- /* we stop when we find an `end' keyword */
- if ( *cur == 'e' &&
- cur + 3 < limit &&
- cur[1] == 'n' &&
- cur[2] == 'd' )
+ /* We stop when we find an `end' keyword or '>' */
+ if ( *cur == 'e' &&
+ cur + 3 < limit &&
+ cur[1] == 'n' &&
+ cur[2] == 'd' &&
+ t42_is_space( cur[3] ) )
break;
+ if ( *cur == '>' )
+ break;
- if ( *cur != '/' )
- T1_Skip_PS_Token( parser );
- else
+ T1_Skip_PS_Token( parser );
+
+ if ( *cur == '/' )
{
- FT_Byte* cur2 = cur + 1;
- FT_Int len;
+ FT_PtrDist len;
- while ( cur2 < limit && t42_is_alpha( *cur2 ) )
- cur2++;
- len = (FT_Int)( cur2 - cur - 1 );
+ if ( cur + 1 >= limit )
+ {
+ FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
- error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+ cur++; /* skip `/' */
+ len = parser->root.cursor - cur;
+
+ error = T1_Add_Table( name_table, n, cur, len + 1 );
if ( error )
goto Fail;
@@ -723,17 +788,29 @@
/* add a trailing zero to the name table */
name_table->elements[n][len] = '\0';
- parser->root.cursor = cur2;
+ /* record index of /.notdef */
+ if ( *cur == '.' &&
+ ft_strcmp( ".notdef",
+ (const char*)(name_table->elements[n]) ) == 0 )
+ {
+ notdef_index = n;
+ notdef_found = 1;
+ }
+
T1_Skip_Spaces( parser );
- cur2 = cur = parser->root.cursor;
- if ( cur >= limit )
- break;
+ cur = parser->root.cursor;
- while ( cur2 < limit && t42_is_alpha( *cur2 ) )
- cur2++;
- len = (FT_Int)( cur2 - cur );
+ (void)T1_ToInt( parser );
+ if ( parser->root.cursor >= limit )
+ {
+ FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+ len = parser->root.cursor - cur;
+
error = T1_Add_Table( code_table, n, cur, len + 1 );
if ( error )
goto Fail;
@@ -746,15 +823,79 @@
}
}
- /* Index 0 must be a .notdef element */
- if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) )
+ loader->num_glyphs = n;
+
+ if ( !notdef_found )
{
- FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" ));
+ FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" ));
error = T42_Err_Invalid_File_Format;
goto Fail;
}
- loader->num_glyphs = n;
+ /* if /.notdef does not occupy index 0, do our magic. */
+ if ( ft_strcmp( (const char*)".notdef",
+ (const char*)name_table->elements[0] ) )
+ {
+ /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
+ /* name and code entries to swap_table. Then place notdef_index */
+ /* name and code entries into swap_table. Then swap name and code */
+ /* entries at indices notdef_index and 0 using values stored in */
+ /* swap_table. */
+
+ /* Index 0 name */
+ error = T1_Add_Table( swap_table, 0,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index 0 code */
+ error = T1_Add_Table( swap_table, 1,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index name */
+ error = T1_Add_Table( swap_table, 2,
+ name_table->elements[notdef_index],
+ name_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index code */
+ error = T1_Add_Table( swap_table, 3,
+ code_table->elements[notdef_index],
+ code_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, notdef_index,
+ swap_table->elements[0],
+ swap_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, notdef_index,
+ swap_table->elements[1],
+ swap_table->lengths [1] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, 0,
+ swap_table->elements[2],
+ swap_table->lengths [2] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, 0,
+ swap_table->elements[3],
+ swap_table->lengths [3] );
+ if ( error )
+ goto Fail;
+
+ }
+
return;
Fail:
@@ -774,14 +915,16 @@
/* if the keyword has a dedicated callback, call it */
- if ( field->type == T1_FIELD_TYPE_CALLBACK ) {
+ if ( field->type == T1_FIELD_TYPE_CALLBACK )
+ {
field->reader( (FT_Face)face, loader );
error = loader->parser.root.error;
goto Exit;
}
- /* now, the keyword is either a simple field, or a table of fields; */
- /* we are now going to take care of it */
+ /* now the keyword is either a simple field or a table of fields; */
+ /* we are now going to take care of it */
+
switch ( field->location )
{
case T1_FIELD_LOCATION_FONT_INFO:
@@ -818,28 +961,27 @@
FT_Long size )
{
T42_Parser parser = &loader->parser;
- FT_Byte* cur = base;
- FT_Byte* limit = cur + size;
- FT_UInt n_keywords = (FT_UInt)( sizeof ( t42_keywords ) /
- sizeof ( t42_keywords[0] ) );
+ FT_Byte* limit;
+ int n_keywords = sizeof ( t42_keywords ) /
+ sizeof ( t42_keywords[0] );
- FT_Byte keyword_flags[T42_KEYWORD_COUNT];
- {
- FT_UInt n;
-
-
- for ( n = 0; n < T42_KEYWORD_COUNT; n++ )
- keyword_flags[n] = 0;
- }
-
parser->root.cursor = base;
parser->root.limit = base + size;
- parser->root.error = 0;
+ parser->root.error = T42_Err_Ok;
- for ( ; cur < limit; cur++ )
+ limit = parser->root.limit;
+
+ T1_Skip_Spaces( parser );
+
+ while ( parser->root.cursor < limit )
{
- /* look for `FontDirectory', which causes problems on some fonts */
+ FT_Byte* cur;
+
+
+ cur = parser->root.cursor;
+
+ /* look for `FontDirectory' which causes problems for some fonts */
if ( *cur == 'F' && cur + 25 < limit &&
ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
{
@@ -847,14 +989,22 @@
/* skip the `FontDirectory' keyword */
- cur += 13;
- cur2 = cur;
+ T1_Skip_PS_Token( parser );
+ T1_Skip_Spaces ( parser );
+ cur = cur2 = parser->root.cursor;
- /* lookup the `known' keyword */
- while ( cur < limit && *cur != 'k' &&
- ft_strncmp( (char*)cur, "known", 5 ) )
- cur++;
+ /* look up the `known' keyword */
+ while ( cur < limit )
+ {
+ if ( *cur == 'k' && cur + 5 < limit &&
+ ft_strncmp( (char*)cur, "known", 5 ) == 0 )
+ break;
+ T1_Skip_PS_Token( parser );
+ T1_Skip_Spaces ( parser );
+ cur = parser->root.cursor;
+ }
+
if ( cur < limit )
{
T1_TokenRec token;
@@ -861,34 +1011,37 @@
/* skip the `known' keyword and the token following it */
- cur += 5;
- loader->parser.root.cursor = cur;
- T1_ToToken( &loader->parser, &token );
+ T1_Skip_PS_Token( parser );
+ T1_ToToken( parser, &token );
/* if the last token was an array, skip it! */
if ( token.type == T1_TOKEN_TYPE_ARRAY )
cur2 = parser->root.cursor;
}
- cur = cur2;
+ parser->root.cursor = cur2;
}
+
/* look for immediates */
else if ( *cur == '/' && cur + 2 < limit )
{
- FT_Byte* cur2;
- FT_UInt i, len;
+ FT_PtrDist len;
cur++;
- cur2 = cur;
- while ( cur2 < limit && t42_is_alpha( *cur2 ) )
- cur2++;
- len = (FT_UInt)( cur2 - cur );
- if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */
+ parser->root.cursor = cur;
+ T1_Skip_PS_Token( parser );
+
+ len = parser->root.cursor - cur;
+
+ if ( len > 0 && len < 22 && parser->root.cursor < limit )
{
- /* now, compare the immediate name to the keyword table */
+ int i;
- /* Loop through all known keywords */
+
+ /* now compare the immediate name to the keyword table */
+
+ /* loop through all known keywords */
for ( i = 0; i < n_keywords; i++ )
{
T1_Field keyword = (T1_Field)&t42_keywords[i];
@@ -898,32 +1051,27 @@
if ( !name )
continue;
- if ( ( len == ft_strlen( (const char *)name ) ) &&
- ( ft_memcmp( cur, name, len ) == 0 ) )
+ if ( cur[0] == name[0] &&
+ len == ft_strlen( (const char *)name ) &&
+ ft_memcmp( cur, name, len ) == 0 )
{
/* we found it -- run the parsing callback! */
- parser->root.cursor = cur2;
- T1_Skip_Spaces( parser );
-
- /* only record the first instance of each field/keyword */
- /* to deal with synthetic fonts correctly */
- if ( keyword_flags[i] == 0 )
- {
- parser->root.error = t42_load_keyword(face,
- loader,
- keyword );
- if ( parser->root.error )
- return parser->root.error;
- }
- keyword_flags[i] = 1;
-
- cur = parser->root.cursor;
+ parser->root.error = t42_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
break;
}
}
}
}
+ else
+ T1_Skip_PS_Token( parser );
+
+ T1_Skip_Spaces( parser );
}
+
return parser->root.error;
}
@@ -955,6 +1103,7 @@
T1_Release_Table( &loader->encoding_table );
T1_Release_Table( &loader->charstrings );
T1_Release_Table( &loader->glyph_names );
+ T1_Release_Table( &loader->swap_table );
/* finalize parser */
t42_parser_done( parser );
--- a/src/type42/t42parse.h
+++ b/src/type42/t42parse.h
@@ -33,7 +33,7 @@
FT_Byte* base_dict;
FT_Long base_len;
- FT_Byte in_memory;
+ FT_Bool in_memory;
} T42_ParserRec, *T42_Parser;
@@ -42,13 +42,14 @@
{
T42_ParserRec parser; /* parser used to read the stream */
- FT_Int num_chars; /* number of characters in encoding */
+ FT_UInt num_chars; /* number of characters in encoding */
PS_TableRec encoding_table; /* PS_Table used to store the */
/* encoding character names */
- FT_Int num_glyphs;
+ FT_UInt num_glyphs;
PS_TableRec glyph_names;
PS_TableRec charstrings;
+ PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */
} T42_LoaderRec, *T42_Loader;