1 /***************************************************************************/
5 /* Type 42 font parser (body). */
7 /* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_INTERNAL_STREAM_H
23 #include FT_INTERNAL_POSTSCRIPT_AUX_H
26 /*************************************************************************/
28 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
29 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
30 /* messages during execution. */
33 #define FT_COMPONENT trace_t42
37 t42_parse_font_matrix( T42_Face face
,
40 t42_parse_encoding( T42_Face face
,
44 t42_parse_charstrings( T42_Face face
,
48 t42_parse_sfnts( T42_Face face
,
52 /* as Type42 fonts have no Private dict, */
53 /* we set the last argument of T1_FIELD_XXX to 0 */
55 T1_FieldRec t42_keywords
[] = {
58 #define FT_STRUCTURE T1_FontInfo
60 #define T1CODE T1_FIELD_LOCATION_FONT_INFO
62 T1_FIELD_STRING( "version", version
, 0 )
63 T1_FIELD_STRING( "Notice", notice
, 0 )
64 T1_FIELD_STRING( "FullName", full_name
, 0 )
65 T1_FIELD_STRING( "FamilyName", family_name
, 0 )
66 T1_FIELD_STRING( "Weight", weight
, 0 )
67 T1_FIELD_NUM ( "ItalicAngle", italic_angle
, 0 )
68 T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch
, 0 )
69 T1_FIELD_NUM ( "UnderlinePosition", underline_position
, 0 )
70 T1_FIELD_NUM ( "UnderlineThickness", underline_thickness
, 0 )
73 #define FT_STRUCTURE PS_FontExtraRec
75 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
77 T1_FIELD_NUM ( "FSType", fs_type
, 0 )
80 #define FT_STRUCTURE T1_FontRec
82 #define T1CODE T1_FIELD_LOCATION_FONT_DICT
84 T1_FIELD_KEY ( "FontName", font_name
, 0 )
85 T1_FIELD_NUM ( "PaintType", paint_type
, 0 )
86 T1_FIELD_NUM ( "FontType", font_type
, 0 )
87 T1_FIELD_FIXED( "StrokeWidth", stroke_width
, 0 )
90 #define FT_STRUCTURE FT_BBox
92 #define T1CODE T1_FIELD_LOCATION_BBOX
94 T1_FIELD_BBOX("FontBBox", xMin
, 0 )
96 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix
, 0 )
97 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding
, 0 )
98 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings
, 0 )
99 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts
, 0 )
101 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
105 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
106 #define T1_Done_Table( p ) \
109 if ( (p)->funcs.done ) \
110 (p)->funcs.done( p ); \
112 #define T1_Release_Table( p ) \
115 if ( (p)->funcs.release ) \
116 (p)->funcs.release( p ); \
119 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
120 #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root )
122 #define T1_ToInt( p ) \
123 (p)->root.funcs.to_int( &(p)->root )
124 #define T1_ToBytes( p, b, m, n, d ) \
125 (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
127 #define T1_ToFixedArray( p, m, f, t ) \
128 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
129 #define T1_ToToken( p, t ) \
130 (p)->root.funcs.to_token( &(p)->root, t )
132 #define T1_Load_Field( p, f, o, m, pf ) \
133 (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
134 #define T1_Load_Field_Table( p, f, o, m, pf ) \
135 (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
138 /********************* Parsing Functions ******************/
140 FT_LOCAL_DEF( FT_Error
)
141 t42_parser_init( T42_Parser parser
,
144 PSAux_Service psaux
)
146 FT_Error error
= T42_Err_Ok
;
150 psaux
->ps_parser_funcs
->init( &parser
->root
, 0, 0, memory
);
152 parser
->stream
= stream
;
153 parser
->base_len
= 0;
154 parser
->base_dict
= 0;
155 parser
->in_memory
= 0;
157 /*******************************************************************/
159 /* Here a short summary of what is going on: */
161 /* When creating a new Type 42 parser, we try to locate and load */
162 /* the base dictionary, loading the whole font into memory. */
164 /* When `loading' the base dictionary, we only set up pointers */
165 /* in the case of a memory-based stream. Otherwise, we allocate */
166 /* and load the base dictionary in it. */
168 /* parser->in_memory is set if we have a memory stream. */
171 if ( FT_STREAM_SEEK( 0L ) ||
172 FT_FRAME_ENTER( 17 ) )
175 if ( ft_memcmp( stream
->cursor
, "%!PS-TrueTypeFont", 17 ) != 0 )
177 FT_TRACE2(( "not a Type42 font\n" ));
178 error
= T42_Err_Unknown_File_Format
;
183 if ( error
|| FT_STREAM_SEEK( 0 ) )
188 /* now, try to load `size' bytes of the `base' dictionary we */
189 /* found previously */
191 /* if it is a memory-based resource, set up pointers */
194 parser
->base_dict
= (FT_Byte
*)stream
->base
+ stream
->pos
;
195 parser
->base_len
= size
;
196 parser
->in_memory
= 1;
198 /* check that the `size' field is valid */
199 if ( FT_STREAM_SKIP( size
) )
204 /* read segment in memory */
205 if ( FT_ALLOC( parser
->base_dict
, size
) ||
206 FT_STREAM_READ( parser
->base_dict
, size
) )
209 parser
->base_len
= size
;
212 parser
->root
.base
= parser
->base_dict
;
213 parser
->root
.cursor
= parser
->base_dict
;
214 parser
->root
.limit
= parser
->root
.cursor
+ parser
->base_len
;
217 if ( error
&& !parser
->in_memory
)
218 FT_FREE( parser
->base_dict
);
225 t42_parser_done( T42_Parser parser
)
227 FT_Memory memory
= parser
->root
.memory
;
230 /* free the base dictionary only when we have a disk stream */
231 if ( !parser
->in_memory
)
232 FT_FREE( parser
->base_dict
);
234 parser
->root
.funcs
.done( &parser
->root
);
239 t42_is_space( FT_Byte c
)
241 return ( c
== ' ' || c
== '\t' ||
242 c
== '\r' || c
== '\n' || c
== '\f' ||
248 t42_parse_font_matrix( T42_Face face
,
251 T42_Parser parser
= &loader
->parser
;
252 FT_Matrix
* matrix
= &face
->type1
.font_matrix
;
253 FT_Vector
* offset
= &face
->type1
.font_offset
;
254 FT_Face root
= (FT_Face
)&face
->root
;
259 (void)T1_ToFixedArray( parser
, 6, temp
, 3 );
261 temp_scale
= FT_ABS( temp
[3] );
263 /* Set Units per EM based on FontMatrix values. We set the value to */
264 /* 1000 / temp_scale, because temp_scale was already multiplied by */
265 /* 1000 (in t1_tofixed, from psobjs.c). */
267 root
->units_per_EM
= (FT_UShort
)( FT_DivFix( 1000 * 0x10000L
,
268 temp_scale
) >> 16 );
270 /* we need to scale the values by 1.0/temp_scale */
271 if ( temp_scale
!= 0x10000L
) {
272 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
273 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
274 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
275 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
276 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
280 matrix
->xx
= temp
[0];
281 matrix
->yx
= temp
[1];
282 matrix
->xy
= temp
[2];
283 matrix
->yy
= temp
[3];
285 /* note that the offsets must be expressed in integer font units */
286 offset
->x
= temp
[4] >> 16;
287 offset
->y
= temp
[5] >> 16;
292 t42_parse_encoding( T42_Face face
,
295 T42_Parser parser
= &loader
->parser
;
297 FT_Byte
* limit
= parser
->root
.limit
;
299 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
302 T1_Skip_Spaces( parser
);
303 cur
= parser
->root
.cursor
;
306 FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
307 parser
->root
.error
= T42_Err_Invalid_File_Format
;
311 /* if we have a number or `[', the encoding is an array, */
312 /* and we must load it now */
313 if ( ft_isdigit( *cur
) || *cur
== '[' )
315 T1_Encoding encode
= &face
->type1
.encoding
;
317 PS_Table char_table
= &loader
->encoding_table
;
318 FT_Memory memory
= parser
->root
.memory
;
320 FT_Bool only_immediates
= 0;
323 /* read the number of entries in the encoding; should be 256 */
328 parser
->root
.cursor
++;
331 count
= (FT_UInt
)T1_ToInt( parser
);
333 T1_Skip_Spaces( parser
);
334 if ( parser
->root
.cursor
>= limit
)
337 /* we use a T1_Table to store our charnames */
338 loader
->num_chars
= encode
->num_chars
= count
;
339 if ( FT_NEW_ARRAY( encode
->char_index
, count
) ||
340 FT_NEW_ARRAY( encode
->char_name
, count
) ||
341 FT_SET_ERROR( psaux
->ps_table_funcs
->init(
342 char_table
, count
, memory
) ) )
344 parser
->root
.error
= error
;
348 /* We need to `zero' out encoding_table.elements */
349 for ( n
= 0; n
< count
; n
++ )
351 char* notdef
= (char *)".notdef";
354 T1_Add_Table( char_table
, n
, notdef
, 8 );
357 /* Now we need to read records of the form */
359 /* ... charcode /charname ... */
361 /* for each entry in our table. */
363 /* We simply look for a number followed by an immediate */
364 /* name. Note that this ignores correctly the sequence */
365 /* that is often seen in type42 fonts: */
367 /* 0 1 255 { 1 index exch /.notdef put } for dup */
369 /* used to clean the encoding array before anything else. */
371 /* Alternatively, if the array is directly given as */
373 /* /Encoding [ ... ] */
375 /* we only read immediates. */
378 T1_Skip_Spaces( parser
);
380 while ( parser
->root
.cursor
< limit
)
382 cur
= parser
->root
.cursor
;
384 /* we stop when we encounter `def' or `]' */
385 if ( *cur
== 'd' && cur
+ 3 < limit
)
387 if ( cur
[1] == 'e' &&
389 t42_is_space( cur
[3] ) )
391 FT_TRACE6(( "encoding end\n" ));
398 FT_TRACE6(( "encoding end\n" ));
403 /* check whether we have found an entry */
404 if ( ft_isdigit( *cur
) || only_immediates
)
409 if ( only_immediates
)
413 charcode
= (FT_Int
)T1_ToInt( parser
);
414 T1_Skip_Spaces( parser
);
417 cur
= parser
->root
.cursor
;
419 if ( *cur
== '/' && cur
+ 2 < limit
&& n
< count
)
426 parser
->root
.cursor
= cur
;
427 T1_Skip_PS_Token( parser
);
428 if ( parser
->root
.error
)
431 len
= parser
->root
.cursor
- cur
;
433 parser
->root
.error
= T1_Add_Table( char_table
, charcode
,
435 if ( parser
->root
.error
)
437 char_table
->elements
[charcode
][len
] = '\0';
444 T1_Skip_PS_Token( parser
);
445 if ( parser
->root
.error
)
449 T1_Skip_Spaces( parser
);
452 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ARRAY
;
453 parser
->root
.cursor
= cur
;
456 /* Otherwise, we should have either `StandardEncoding', */
457 /* `ExpertEncoding', or `ISOLatin1Encoding' */
460 if ( cur
+ 17 < limit
&&
461 ft_strncmp( (const char*)cur
, "StandardEncoding", 16 ) == 0 )
462 face
->type1
.encoding_type
= T1_ENCODING_TYPE_STANDARD
;
464 else if ( cur
+ 15 < limit
&&
465 ft_strncmp( (const char*)cur
, "ExpertEncoding", 14 ) == 0 )
466 face
->type1
.encoding_type
= T1_ENCODING_TYPE_EXPERT
;
468 else if ( cur
+ 18 < limit
&&
469 ft_strncmp( (const char*)cur
, "ISOLatin1Encoding", 17 ) == 0 )
470 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ISOLATIN1
;
474 FT_ERROR(( "t42_parse_encoding: invalid token\n" ));
475 parser
->root
.error
= T42_Err_Invalid_File_Format
;
481 typedef enum T42_Load_Status_
491 t42_parse_sfnts( T42_Face face
,
494 T42_Parser parser
= &loader
->parser
;
495 FT_Memory memory
= parser
->root
.memory
;
497 FT_Byte
* limit
= parser
->root
.limit
;
499 FT_Int num_tables
= 0;
500 FT_ULong count
, ttf_size
= 0;
502 FT_Long n
, string_size
, old_string_size
, real_size
;
503 FT_Byte
* string_buf
= NULL
;
504 FT_Bool allocated
= 0;
506 T42_Load_Status status
;
511 /* /sfnts [ <hexstring> <hexstring> ... ] def */
516 /* <num_bin_bytes> RD <binary data> */
517 /* <num_bin_bytes> RD <binary data> */
521 /* with exactly one space after the `RD' token. */
523 T1_Skip_Spaces( parser
);
525 if ( parser
->root
.cursor
>= limit
|| *parser
->root
.cursor
++ != '[' )
527 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
528 error
= T42_Err_Invalid_File_Format
;
532 T1_Skip_Spaces( parser
);
533 status
= BEFORE_START
;
538 while ( parser
->root
.cursor
< limit
)
540 cur
= parser
->root
.cursor
;
544 parser
->root
.cursor
++;
548 else if ( *cur
== '<' )
550 T1_Skip_PS_Token( parser
);
551 if ( parser
->root
.error
)
554 /* don't include delimiters */
555 string_size
= (FT_Long
)( ( parser
->root
.cursor
- cur
- 2 + 1 ) / 2 );
556 if ( FT_REALLOC( string_buf
, old_string_size
, string_size
) )
561 parser
->root
.cursor
= cur
;
562 (void)T1_ToBytes( parser
, string_buf
, string_size
, &real_size
, 1 );
563 old_string_size
= string_size
;
564 string_size
= real_size
;
567 else if ( ft_isdigit( *cur
) )
571 FT_ERROR(( "t42_parse_sfnts: "
572 "can't handle mixed binary and hex strings\n" ));
573 error
= T42_Err_Invalid_File_Format
;
577 string_size
= T1_ToInt( parser
);
579 T1_Skip_PS_Token( parser
); /* `RD' */
580 if ( parser
->root
.error
)
583 string_buf
= parser
->root
.cursor
+ 1; /* one space after `RD' */
585 parser
->root
.cursor
+= string_size
+ 1;
586 if ( parser
->root
.cursor
>= limit
)
588 FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
589 error
= T42_Err_Invalid_File_Format
;
596 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
597 error
= T42_Err_Invalid_File_Format
;
601 /* A string can have a trailing zero byte for padding. Ignore it. */
602 if ( string_buf
[string_size
- 1] == 0 && ( string_size
% 2 == 1 ) )
607 FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
608 error
= T42_Err_Invalid_File_Format
;
612 for ( n
= 0; n
< string_size
; n
++ )
617 /* load offset table, 12 bytes */
620 face
->ttf_data
[count
++] = string_buf
[n
];
625 num_tables
= 16 * face
->ttf_data
[4] + face
->ttf_data
[5];
626 status
= BEFORE_TABLE_DIR
;
627 ttf_size
= 12 + 16 * num_tables
;
629 if ( FT_REALLOC( face
->ttf_data
, 12, ttf_size
) )
634 case BEFORE_TABLE_DIR
:
635 /* the offset table is read; read the table directory */
636 if ( count
< ttf_size
)
638 face
->ttf_data
[count
++] = string_buf
[n
];
647 for ( i
= 0; i
< num_tables
; i
++ )
649 FT_Byte
* p
= face
->ttf_data
+ 12 + 16 * i
+ 12;
652 len
= FT_PEEK_ULONG( p
);
654 /* Pad to a 4-byte boundary length */
655 ttf_size
+= ( len
+ 3 ) & ~3;
658 status
= OTHER_TABLES
;
659 face
->ttf_size
= ttf_size
;
661 /* there are no more than 256 tables, so no size check here */
662 if ( FT_REALLOC( face
->ttf_data
, 12 + 16 * num_tables
,
669 /* all other tables are just copied */
670 if ( count
>= ttf_size
)
672 FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
673 error
= T42_Err_Invalid_File_Format
;
676 face
->ttf_data
[count
++] = string_buf
[n
];
680 T1_Skip_Spaces( parser
);
683 /* if control reaches this point, the format was not valid */
684 error
= T42_Err_Invalid_File_Format
;
687 parser
->root
.error
= error
;
691 FT_FREE( string_buf
);
696 t42_parse_charstrings( T42_Face face
,
699 T42_Parser parser
= &loader
->parser
;
700 PS_Table code_table
= &loader
->charstrings
;
701 PS_Table name_table
= &loader
->glyph_names
;
702 PS_Table swap_table
= &loader
->swap_table
;
703 FT_Memory memory
= parser
->root
.memory
;
706 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
709 FT_Byte
* limit
= parser
->root
.limit
;
711 FT_UInt notdef_index
= 0;
712 FT_Byte notdef_found
= 0;
715 T1_Skip_Spaces( parser
);
717 if ( parser
->root
.cursor
>= limit
)
719 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
720 error
= T42_Err_Invalid_File_Format
;
724 if ( ft_isdigit( *parser
->root
.cursor
) )
726 loader
->num_glyphs
= (FT_UInt
)T1_ToInt( parser
);
727 if ( parser
->root
.error
)
730 else if ( *parser
->root
.cursor
== '<' )
732 /* We have `<< ... >>'. Count the number of `/' in the dictionary */
733 /* to get its size. */
737 T1_Skip_PS_Token( parser
);
738 if ( parser
->root
.error
)
740 T1_Skip_Spaces( parser
);
741 cur
= parser
->root
.cursor
;
743 while ( parser
->root
.cursor
< limit
)
745 if ( *parser
->root
.cursor
== '/' )
747 else if ( *parser
->root
.cursor
== '>' )
749 loader
->num_glyphs
= count
;
750 parser
->root
.cursor
= cur
; /* rewind */
753 T1_Skip_PS_Token( parser
);
754 if ( parser
->root
.error
)
756 T1_Skip_Spaces( parser
);
761 FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
762 error
= T42_Err_Invalid_File_Format
;
766 if ( parser
->root
.cursor
>= limit
)
768 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
769 error
= T42_Err_Invalid_File_Format
;
773 /* initialize tables */
775 error
= psaux
->ps_table_funcs
->init( code_table
,
781 error
= psaux
->ps_table_funcs
->init( name_table
,
787 /* Initialize table for swapping index notdef_index and */
788 /* index 0 names and codes (if necessary). */
790 error
= psaux
->ps_table_funcs
->init( swap_table
, 4, memory
);
798 /* The format is simple: */
799 /* `/glyphname' + index [+ def] */
801 T1_Skip_Spaces( parser
);
803 cur
= parser
->root
.cursor
;
807 /* We stop when we find an `end' keyword or '>' */
812 t42_is_space( cur
[3] ) )
817 T1_Skip_PS_Token( parser
);
818 if ( parser
->root
.error
)
826 if ( cur
+ 1 >= limit
)
828 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
829 error
= T42_Err_Invalid_File_Format
;
833 cur
++; /* skip `/' */
834 len
= parser
->root
.cursor
- cur
;
836 error
= T1_Add_Table( name_table
, n
, cur
, len
+ 1 );
840 /* add a trailing zero to the name table */
841 name_table
->elements
[n
][len
] = '\0';
843 /* record index of /.notdef */
845 ft_strcmp( ".notdef",
846 (const char*)(name_table
->elements
[n
]) ) == 0 )
852 T1_Skip_Spaces( parser
);
854 cur
= parser
->root
.cursor
;
856 (void)T1_ToInt( parser
);
857 if ( parser
->root
.cursor
>= limit
)
859 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
860 error
= T42_Err_Invalid_File_Format
;
864 len
= parser
->root
.cursor
- cur
;
866 error
= T1_Add_Table( code_table
, n
, cur
, len
+ 1 );
870 code_table
->elements
[n
][len
] = '\0';
873 if ( n
>= loader
->num_glyphs
)
878 loader
->num_glyphs
= n
;
882 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
883 error
= T42_Err_Invalid_File_Format
;
887 /* if /.notdef does not occupy index 0, do our magic. */
888 if ( ft_strcmp( (const char*)".notdef",
889 (const char*)name_table
->elements
[0] ) )
891 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
892 /* name and code entries to swap_table. Then place notdef_index */
893 /* name and code entries into swap_table. Then swap name and code */
894 /* entries at indices notdef_index and 0 using values stored in */
898 error
= T1_Add_Table( swap_table
, 0,
899 name_table
->elements
[0],
900 name_table
->lengths
[0] );
905 error
= T1_Add_Table( swap_table
, 1,
906 code_table
->elements
[0],
907 code_table
->lengths
[0] );
911 /* Index notdef_index name */
912 error
= T1_Add_Table( swap_table
, 2,
913 name_table
->elements
[notdef_index
],
914 name_table
->lengths
[notdef_index
] );
918 /* Index notdef_index code */
919 error
= T1_Add_Table( swap_table
, 3,
920 code_table
->elements
[notdef_index
],
921 code_table
->lengths
[notdef_index
] );
925 error
= T1_Add_Table( name_table
, notdef_index
,
926 swap_table
->elements
[0],
927 swap_table
->lengths
[0] );
931 error
= T1_Add_Table( code_table
, notdef_index
,
932 swap_table
->elements
[1],
933 swap_table
->lengths
[1] );
937 error
= T1_Add_Table( name_table
, 0,
938 swap_table
->elements
[2],
939 swap_table
->lengths
[2] );
943 error
= T1_Add_Table( code_table
, 0,
944 swap_table
->elements
[3],
945 swap_table
->lengths
[3] );
954 parser
->root
.error
= error
;
959 t42_load_keyword( T42_Face face
,
966 FT_UInt max_objects
= 0;
969 /* if the keyword has a dedicated callback, call it */
970 if ( field
->type
== T1_FIELD_TYPE_CALLBACK
)
972 field
->reader( (FT_Face
)face
, loader
);
973 error
= loader
->parser
.root
.error
;
977 /* now the keyword is either a simple field or a table of fields; */
978 /* we are now going to take care of it */
980 switch ( field
->location
)
982 case T1_FIELD_LOCATION_FONT_INFO
:
983 dummy_object
= &face
->type1
.font_info
;
986 case T1_FIELD_LOCATION_FONT_EXTRA
:
987 dummy_object
= &face
->type1
.font_extra
;
990 case T1_FIELD_LOCATION_BBOX
:
991 dummy_object
= &face
->type1
.font_bbox
;
995 dummy_object
= &face
->type1
;
998 objects
= &dummy_object
;
1000 if ( field
->type
== T1_FIELD_TYPE_INTEGER_ARRAY
||
1001 field
->type
== T1_FIELD_TYPE_FIXED_ARRAY
)
1002 error
= T1_Load_Field_Table( &loader
->parser
, field
,
1003 objects
, max_objects
, 0 );
1005 error
= T1_Load_Field( &loader
->parser
, field
,
1006 objects
, max_objects
, 0 );
1013 FT_LOCAL_DEF( FT_Error
)
1014 t42_parse_dict( T42_Face face
,
1019 T42_Parser parser
= &loader
->parser
;
1021 FT_Int n_keywords
= (FT_Int
)( sizeof ( t42_keywords
) /
1022 sizeof ( t42_keywords
[0] ) );
1025 parser
->root
.cursor
= base
;
1026 parser
->root
.limit
= base
+ size
;
1027 parser
->root
.error
= T42_Err_Ok
;
1029 limit
= parser
->root
.limit
;
1031 T1_Skip_Spaces( parser
);
1033 while ( parser
->root
.cursor
< limit
)
1038 cur
= parser
->root
.cursor
;
1040 /* look for `FontDirectory' which causes problems for some fonts */
1041 if ( *cur
== 'F' && cur
+ 25 < limit
&&
1042 ft_strncmp( (char*)cur
, "FontDirectory", 13 ) == 0 )
1047 /* skip the `FontDirectory' keyword */
1048 T1_Skip_PS_Token( parser
);
1049 T1_Skip_Spaces ( parser
);
1050 cur
= cur2
= parser
->root
.cursor
;
1052 /* look up the `known' keyword */
1053 while ( cur
< limit
)
1055 if ( *cur
== 'k' && cur
+ 5 < limit
&&
1056 ft_strncmp( (char*)cur
, "known", 5 ) == 0 )
1059 T1_Skip_PS_Token( parser
);
1060 if ( parser
->root
.error
)
1062 T1_Skip_Spaces ( parser
);
1063 cur
= parser
->root
.cursor
;
1071 /* skip the `known' keyword and the token following it */
1072 T1_Skip_PS_Token( parser
);
1073 T1_ToToken( parser
, &token
);
1075 /* if the last token was an array, skip it! */
1076 if ( token
.type
== T1_TOKEN_TYPE_ARRAY
)
1077 cur2
= parser
->root
.cursor
;
1079 parser
->root
.cursor
= cur2
;
1082 /* look for immediates */
1083 else if ( *cur
== '/' && cur
+ 2 < limit
)
1090 parser
->root
.cursor
= cur
;
1091 T1_Skip_PS_Token( parser
);
1092 if ( parser
->root
.error
)
1095 len
= parser
->root
.cursor
- cur
;
1097 if ( len
> 0 && len
< 22 && parser
->root
.cursor
< limit
)
1102 /* now compare the immediate name to the keyword table */
1104 /* loop through all known keywords */
1105 for ( i
= 0; i
< n_keywords
; i
++ )
1107 T1_Field keyword
= (T1_Field
)&t42_keywords
[i
];
1108 FT_Byte
*name
= (FT_Byte
*)keyword
->ident
;
1114 if ( cur
[0] == name
[0] &&
1115 len
== (FT_PtrDist
)ft_strlen( (const char *)name
) &&
1116 ft_memcmp( cur
, name
, len
) == 0 )
1118 /* we found it -- run the parsing callback! */
1119 parser
->root
.error
= t42_load_keyword( face
,
1122 if ( parser
->root
.error
)
1123 return parser
->root
.error
;
1131 T1_Skip_PS_Token( parser
);
1132 if ( parser
->root
.error
)
1136 T1_Skip_Spaces( parser
);
1140 return parser
->root
.error
;
1144 FT_LOCAL_DEF( void )
1145 t42_loader_init( T42_Loader loader
,
1150 FT_MEM_ZERO( loader
, sizeof ( *loader
) );
1151 loader
->num_glyphs
= 0;
1152 loader
->num_chars
= 0;
1154 /* initialize the tables -- simply set their `init' field to 0 */
1155 loader
->encoding_table
.init
= 0;
1156 loader
->charstrings
.init
= 0;
1157 loader
->glyph_names
.init
= 0;
1161 FT_LOCAL_DEF( void )
1162 t42_loader_done( T42_Loader loader
)
1164 T42_Parser parser
= &loader
->parser
;
1167 /* finalize tables */
1168 T1_Release_Table( &loader
->encoding_table
);
1169 T1_Release_Table( &loader
->charstrings
);
1170 T1_Release_Table( &loader
->glyph_names
);
1171 T1_Release_Table( &loader
->swap_table
);
1173 /* finalize parser */
1174 t42_parser_done( parser
);