summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src/type42/t42parse.c
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/3rdparty/freetype/src/type42/t42parse.c
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/3rdparty/freetype/src/type42/t42parse.c')
-rw-r--r--src/3rdparty/freetype/src/type42/t42parse.c1175
1 files changed, 1175 insertions, 0 deletions
diff --git a/src/3rdparty/freetype/src/type42/t42parse.c b/src/3rdparty/freetype/src/type42/t42parse.c
new file mode 100644
index 0000000000..b9e408c452
--- /dev/null
+++ b/src/3rdparty/freetype/src/type42/t42parse.c
@@ -0,0 +1,1175 @@
+/***************************************************************************/
+/* */
+/* t42parse.c */
+/* */
+/* Type 42 font parser (body). */
+/* */
+/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
+/* Roberto Alameda. */
+/* */
+/* 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 "t42parse.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_LIST_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+ /*************************************************************************/
+ /* */
+ /* 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_t42
+
+
+ static void
+ t42_parse_font_matrix( T42_Face face,
+ T42_Loader loader );
+ static void
+ t42_parse_encoding( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_charstrings( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_sfnts( T42_Face face,
+ T42_Loader loader );
+
+
+ /* as Type42 fonts have no Private dict, */
+ /* we set the last argument of T1_FIELD_XXX to 0 */
+ static const
+ T1_FieldRec t42_keywords[] = {
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontInfo
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_INFO
+
+ T1_FIELD_STRING( "version", version, 0 )
+ T1_FIELD_STRING( "Notice", notice, 0 )
+ T1_FIELD_STRING( "FullName", full_name, 0 )
+ T1_FIELD_STRING( "FamilyName", family_name, 0 )
+ T1_FIELD_STRING( "Weight", weight, 0 )
+ T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 )
+ T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 )
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PS_FontExtraRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
+
+ T1_FIELD_NUM ( "FSType", fs_type, 0 )
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_DICT
+
+ T1_FIELD_KEY ( "FontName", font_name, 0 )
+ T1_FIELD_NUM ( "PaintType", paint_type, 0 )
+ T1_FIELD_NUM ( "FontType", font_type, 0 )
+ T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 )
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE FT_BBox
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_BBOX
+
+ T1_FIELD_BBOX("FontBBox", xMin, 0 )
+
+ T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 )
+ T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 )
+ T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 )
+ T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 )
+
+ { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.done ) \
+ (p)->funcs.done( p ); \
+ } while ( 0 )
+#define T1_Release_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.release ) \
+ (p)->funcs.release( p ); \
+ } while ( 0 )
+
+#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_ToBytes( p, b, m, n, d ) \
+ (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
+
+#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_Load_Field( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+#define T1_Load_Field_Table( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+ /********************* Parsing Functions ******************/
+
+ FT_LOCAL_DEF( FT_Error )
+ t42_parser_init( T42_Parser parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux )
+ {
+ FT_Error error = T42_Err_Ok;
+ FT_Long size;
+
+
+ psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
+
+ parser->stream = stream;
+ parser->base_len = 0;
+ parser->base_dict = 0;
+ parser->in_memory = 0;
+
+ /*******************************************************************/
+ /* */
+ /* Here a short summary of what is going on: */
+ /* */
+ /* When creating a new Type 42 parser, we try to locate and load */
+ /* the base dictionary, loading the whole font into memory. */
+ /* */
+ /* When `loading' the base dictionary, we only set up pointers */
+ /* in the case of a memory-based stream. Otherwise, we allocate */
+ /* and load the base dictionary in it. */
+ /* */
+ /* parser->in_memory is set if we have a memory stream. */
+ /* */
+
+ if ( FT_STREAM_SEEK( 0L ) ||
+ FT_FRAME_ENTER( 17 ) )
+ goto Exit;
+
+ if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 )
+ {
+ FT_TRACE2(( "not a Type42 font\n" ));
+ error = T42_Err_Unknown_File_Format;
+ }
+
+ FT_FRAME_EXIT();
+
+ if ( error || FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ size = stream->size;
+
+ /* now, try to load `size' bytes of the `base' dictionary we */
+ /* found previously */
+
+ /* if it is a memory-based resource, set up pointers */
+ if ( !stream->read )
+ {
+ parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+ parser->base_len = size;
+ parser->in_memory = 1;
+
+ /* check that the `size' field is valid */
+ if ( FT_STREAM_SKIP( size ) )
+ goto Exit;
+ }
+ else
+ {
+ /* read segment in memory */
+ if ( FT_ALLOC( parser->base_dict, size ) ||
+ FT_STREAM_READ( parser->base_dict, size ) )
+ goto Exit;
+
+ parser->base_len = size;
+ }
+
+ parser->root.base = parser->base_dict;
+ parser->root.cursor = parser->base_dict;
+ parser->root.limit = parser->root.cursor + parser->base_len;
+
+ Exit:
+ if ( error && !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_parser_done( T42_Parser parser )
+ {
+ FT_Memory memory = parser->root.memory;
+
+
+ /* free the base dictionary only when we have a disk stream */
+ if ( !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+ static int
+ t42_is_space( FT_Byte c )
+ {
+ return ( c == ' ' || c == '\t' ||
+ c == '\r' || c == '\n' || c == '\f' ||
+ c == '\0' );
+ }
+
+
+ static void
+ t42_parse_font_matrix( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Matrix* matrix = &face->type1.font_matrix;
+ FT_Vector* offset = &face->type1.font_offset;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+ temp_scale = FT_ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* 1000 / temp_scale, because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed, from psobjs.c). */
+
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+ temp_scale ) >> 16 );
+
+ /* we need to scale the values by 1.0/temp_scale */
+ if ( temp_scale != 0x10000L ) {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ 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;
+ }
+
+
+ static void
+ t42_parse_encoding( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
+ parser->root.error = T42_Err_Invalid_File_Format;
+ return;
+ }
+
+ /* 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_UInt count, n;
+ PS_Table char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+ FT_Bool only_immediates = 0;
+
+
+ /* 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 );
+
+ 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 ) ||
+ FT_SET_ERROR( psaux->ps_table_funcs->init(
+ char_table, count, memory ) ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ /* We need to `zero' out encoding_table.elements */
+ for ( n = 0; n < count; n++ )
+ {
+ char* notdef = (char *)".notdef";
+
+
+ T1_Add_Table( char_table, n, notdef, 8 );
+ }
+
+ /* 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 type42 fonts: */
+ /* */
+ /* 0 1 255 { 1 index exch /.notdef put } for dup */
+ /* */
+ /* used to clean the encoding array before anything else. */
+ /* */
+ /* Alternatively, if the array is directly given as */
+ /* */
+ /* /Encoding [ ... ] */
+ /* */
+ /* we only read immediates. */
+
+ n = 0;
+ T1_Skip_Spaces( parser );
+
+ while ( parser->root.cursor < limit )
+ {
+ cur = parser->root.cursor;
+
+ /* we stop when we encounter `def' or `]' */
+ if ( *cur == 'd' && cur + 3 < limit )
+ {
+ 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;
+ }
+
+ /* check whether we have found an entry */
+ if ( ft_isdigit( *cur ) || only_immediates )
+ {
+ FT_Int charcode;
+
+
+ if ( only_immediates )
+ charcode = n;
+ else
+ {
+ charcode = (FT_Int)T1_ToInt( parser );
+ T1_Skip_Spaces( parser );
+ }
+
+ cur = parser->root.cursor;
+
+ if ( *cur == '/' && cur + 2 < limit && n < count )
+ {
+ FT_PtrDist len;
+
+
+ cur++;
+
+ parser->root.cursor = cur;
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ return;
+
+ len = parser->root.cursor - cur;
+
+ parser->root.error = T1_Add_Table( char_table, charcode,
+ cur, len + 1 );
+ if ( parser->root.error )
+ return;
+ char_table->elements[charcode][len] = '\0';
+
+ n++;
+ }
+ }
+ else
+ {
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ return;
+ }
+
+ T1_Skip_Spaces( parser );
+ }
+
+ face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ parser->root.cursor = cur;
+ }
+
+ /* Otherwise, we should have either `StandardEncoding', */
+ /* `ExpertEncoding', or `ISOLatin1Encoding' */
+ else
+ {
+ if ( cur + 17 < limit &&
+ ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+
+ else if ( cur + 15 < limit &&
+ ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+
+ else if ( cur + 18 < limit &&
+ ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+
+ else
+ {
+ FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
+ parser->root.error = T42_Err_Invalid_File_Format;
+ }
+ }
+ }
+
+
+ typedef enum T42_Load_Status_
+ {
+ BEFORE_START,
+ BEFORE_TABLE_DIR,
+ OTHER_TABLES
+
+ } T42_Load_Status;
+
+
+ static void
+ t42_parse_sfnts( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Memory memory = parser->root.memory;
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_Error error;
+ 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 allocated = 0;
+
+ T42_Load_Status status;
+
+
+ /* 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++ != '[' )
+ {
+ FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ T1_Skip_Spaces( parser );
+ status = BEFORE_START;
+ string_size = 0;
+ old_string_size = 0;
+ count = 0;
+
+ while ( parser->root.cursor < limit )
+ {
+ cur = parser->root.cursor;
+
+ if ( *cur == ']' )
+ {
+ parser->root.cursor++;
+ goto Exit;
+ }
+
+ else if ( *cur == '<' )
+ {
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ goto Exit;
+
+ /* 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;
+
+ allocated = 1;
+
+ parser->root.cursor = cur;
+ (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
+ old_string_size = string_size;
+ string_size = real_size;
+ }
+
+ else if ( ft_isdigit( *cur ) )
+ {
+ if ( allocated )
+ {
+ FT_ERROR(( "t42_parse_sfnts: "
+ "can't handle mixed binary and hex strings!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ string_size = T1_ToInt( parser );
+
+ T1_Skip_PS_Token( parser ); /* `RD' */
+ if ( parser->root.error )
+ return;
+
+ 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: too many binary data!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+ }
+
+ if ( !string_buf )
+ {
+ FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ /* 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--;
+
+ if ( !string_size )
+ {
+ FT_ERROR(( "t42_parse_sfnts: invalid string!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ for ( n = 0; n < string_size; n++ )
+ {
+ switch ( status )
+ {
+ 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;
+ }
+ /* fall through */
+
+ 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;
+
+
+ len = FT_PEEK_ULONG( p );
+
+ /* Pad to a 4-byte boundary length */
+ ttf_size += ( len + 3 ) & ~3;
+ }
+
+ status = OTHER_TABLES;
+ face->ttf_size = ttf_size;
+
+ /* there are no more than 256 tables, so no size check here */
+ 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 */
+ error = T42_Err_Invalid_File_Format;
+
+ Fail:
+ parser->root.error = error;
+
+ Exit:
+ if ( allocated )
+ FT_FREE( string_buf );
+ }
+
+
+ static void
+ 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;
+ PS_Table swap_table = &loader->swap_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_UInt n;
+ FT_UInt notdef_index = 0;
+ FT_Byte notdef_found = 0;
+
+
+ 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 );
+ if ( parser->root.error )
+ return;
+ 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 );
+ if ( parser->root.error )
+ return;
+ 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,
+ loader->num_glyphs,
+ memory );
+ if ( error )
+ goto Fail;
+
+ error = psaux->ps_table_funcs->init( name_table,
+ loader->num_glyphs,
+ memory );
+ 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] */
+
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ /* 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;
+
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ return;
+
+ if ( *cur == '/' )
+ {
+ FT_PtrDist len;
+
+
+ if ( cur + 1 >= limit )
+ {
+ FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ cur++; /* skip `/' */
+ len = parser->root.cursor - cur;
+
+ error = T1_Add_Table( name_table, n, cur, len + 1 );
+ if ( error )
+ goto Fail;
+
+ /* add a trailing zero to the name table */
+ name_table->elements[n][len] = '\0';
+
+ /* 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 );
+
+ cur = parser->root.cursor;
+
+ (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;
+
+ code_table->elements[n][len] = '\0';
+
+ n++;
+ if ( n >= loader->num_glyphs )
+ break;
+ }
+ }
+
+ loader->num_glyphs = n;
+
+ if ( !notdef_found )
+ {
+ FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ /* 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:
+ parser->root.error = error;
+ }
+
+
+ static FT_Error
+ t42_load_keyword( T42_Face face,
+ T42_Loader loader,
+ T1_Field field )
+ {
+ FT_Error error;
+ void* dummy_object;
+ void** objects;
+ FT_UInt max_objects = 0;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ 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 */
+
+ switch ( field->location )
+ {
+ case T1_FIELD_LOCATION_FONT_INFO:
+ dummy_object = &face->type1.font_info;
+ break;
+
+ case T1_FIELD_LOCATION_BBOX:
+ dummy_object = &face->type1.font_bbox;
+ break;
+
+ default:
+ dummy_object = &face->type1;
+ }
+
+ objects = &dummy_object;
+
+ if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+ field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+ error = T1_Load_Field_Table( &loader->parser, field,
+ objects, max_objects, 0 );
+ else
+ error = T1_Load_Field( &loader->parser, field,
+ objects, max_objects, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ t42_parse_dict( T42_Face face,
+ T42_Loader loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Byte* limit;
+ FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
+ sizeof ( t42_keywords[0] ) );
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = T42_Err_Ok;
+
+ limit = parser->root.limit;
+
+ T1_Skip_Spaces( parser );
+
+ while ( parser->root.cursor < limit )
+ {
+ 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 )
+ {
+ FT_Byte* cur2;
+
+
+ /* skip the `FontDirectory' keyword */
+ T1_Skip_PS_Token( parser );
+ T1_Skip_Spaces ( parser );
+ cur = cur2 = parser->root.cursor;
+
+ /* look up the `known' keyword */
+ while ( cur < limit )
+ {
+ if ( *cur == 'k' && cur + 5 < limit &&
+ ft_strncmp( (char*)cur, "known", 5 ) == 0 )
+ break;
+
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ goto Exit;
+ T1_Skip_Spaces ( parser );
+ cur = parser->root.cursor;
+ }
+
+ if ( cur < limit )
+ {
+ T1_TokenRec token;
+
+
+ /* skip the `known' keyword and the token following it */
+ T1_Skip_PS_Token( parser );
+ T1_ToToken( parser, &token );
+
+ /* if the last token was an array, skip it! */
+ if ( token.type == T1_TOKEN_TYPE_ARRAY )
+ cur2 = parser->root.cursor;
+ }
+ parser->root.cursor = cur2;
+ }
+
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_PtrDist len;
+
+
+ cur++;
+
+ parser->root.cursor = cur;
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ goto Exit;
+
+ len = parser->root.cursor - cur;
+
+ if ( len > 0 && len < 22 && parser->root.cursor < limit )
+ {
+ int i;
+
+
+ /* 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];
+ FT_Byte *name = (FT_Byte*)keyword->ident;
+
+
+ if ( !name )
+ continue;
+
+ if ( cur[0] == name[0] &&
+ len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
+ ft_memcmp( cur, name, len ) == 0 )
+ {
+ /* we found it -- run the parsing callback! */
+ parser->root.error = t42_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ T1_Skip_PS_Token( parser );
+ if ( parser->root.error )
+ goto Exit;
+ }
+
+ T1_Skip_Spaces( parser );
+ }
+
+ Exit:
+ return parser->root.error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_loader_init( T42_Loader loader,
+ T42_Face face )
+ {
+ FT_UNUSED( face );
+
+ FT_MEM_ZERO( loader, 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;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_loader_done( T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+
+
+ /* finalize tables */
+ 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 );
+ }
+
+
+/* END */