1 /***************************************************************************/
5 /* Type 42 font parser (body). */
7 /* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 by Roberto Alameda. */
9 /* This file is part of the FreeType project, and may only be used, */
10 /* modified, and distributed under the terms of the FreeType project */
11 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
12 /* this file you indicate that you have read the license and */
13 /* understand and accept it fully. */
15 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #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 T1_FontRec
75 #define T1CODE T1_FIELD_LOCATION_FONT_DICT
77 T1_FIELD_KEY ( "FontName", font_name
, 0 )
78 T1_FIELD_NUM ( "PaintType", paint_type
, 0 )
79 T1_FIELD_NUM ( "FontType", font_type
, 0 )
80 T1_FIELD_FIXED( "StrokeWidth", stroke_width
, 0 )
83 #define FT_STRUCTURE FT_BBox
85 #define T1CODE T1_FIELD_LOCATION_BBOX
87 T1_FIELD_BBOX("FontBBox", xMin
, 0 )
89 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix
, 0 )
90 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding
, 0 )
91 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings
, 0 )
92 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts
, 0 )
94 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
98 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
99 #define T1_Done_Table( p ) \
102 if ( (p)->funcs.done ) \
103 (p)->funcs.done( p ); \
105 #define T1_Release_Table( p ) \
108 if ( (p)->funcs.release ) \
109 (p)->funcs.release( p ); \
112 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
113 #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root )
115 #define T1_ToInt( p ) \
116 (p)->root.funcs.to_int( &(p)->root )
117 #define T1_ToBytes( p, b, m, n, d ) \
118 (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
120 #define T1_ToFixedArray( p, m, f, t ) \
121 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
122 #define T1_ToToken( p, t ) \
123 (p)->root.funcs.to_token( &(p)->root, t )
125 #define T1_Load_Field( p, f, o, m, pf ) \
126 (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
127 #define T1_Load_Field_Table( p, f, o, m, pf ) \
128 (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
131 /********************* Parsing Functions ******************/
133 FT_LOCAL_DEF( FT_Error
)
134 t42_parser_init( T42_Parser parser
,
137 PSAux_Service psaux
)
139 FT_Error error
= T42_Err_Ok
;
143 psaux
->ps_parser_funcs
->init( &parser
->root
, 0, 0, memory
);
145 parser
->stream
= stream
;
146 parser
->base_len
= 0;
147 parser
->base_dict
= 0;
148 parser
->in_memory
= 0;
150 /*******************************************************************/
152 /* Here a short summary of what is going on: */
154 /* When creating a new Type 42 parser, we try to locate and load */
155 /* the base dictionary, loading the whole font into memory. */
157 /* When `loading' the base dictionary, we only set up pointers */
158 /* in the case of a memory-based stream. Otherwise, we allocate */
159 /* and load the base dictionary in it. */
161 /* parser->in_memory is set if we have a memory stream. */
164 if ( FT_STREAM_SEEK( 0L ) ||
165 FT_FRAME_ENTER( 17 ) )
168 if ( ft_memcmp( stream
->cursor
, "%!PS-TrueTypeFont", 17 ) != 0 )
170 FT_TRACE2(( "not a Type42 font\n" ));
171 error
= T42_Err_Unknown_File_Format
;
176 if ( error
|| FT_STREAM_SEEK( 0 ) )
181 /* now, try to load `size' bytes of the `base' dictionary we */
182 /* found previously */
184 /* if it is a memory-based resource, set up pointers */
187 parser
->base_dict
= (FT_Byte
*)stream
->base
+ stream
->pos
;
188 parser
->base_len
= size
;
189 parser
->in_memory
= 1;
191 /* check that the `size' field is valid */
192 if ( FT_STREAM_SKIP( size
) )
197 /* read segment in memory */
198 if ( FT_ALLOC( parser
->base_dict
, size
) ||
199 FT_STREAM_READ( parser
->base_dict
, size
) )
202 parser
->base_len
= size
;
205 parser
->root
.base
= parser
->base_dict
;
206 parser
->root
.cursor
= parser
->base_dict
;
207 parser
->root
.limit
= parser
->root
.cursor
+ parser
->base_len
;
210 if ( error
&& !parser
->in_memory
)
211 FT_FREE( parser
->base_dict
);
218 t42_parser_done( T42_Parser parser
)
220 FT_Memory memory
= parser
->root
.memory
;
223 /* free the base dictionary only when we have a disk stream */
224 if ( !parser
->in_memory
)
225 FT_FREE( parser
->base_dict
);
227 parser
->root
.funcs
.done( &parser
->root
);
232 t42_is_space( FT_Byte c
)
234 return ( c
== ' ' || c
== '\t' ||
235 c
== '\r' || c
== '\n' || c
== '\f' ||
241 t42_parse_font_matrix( T42_Face face
,
244 T42_Parser parser
= &loader
->parser
;
245 FT_Matrix
* matrix
= &face
->type1
.font_matrix
;
246 FT_Vector
* offset
= &face
->type1
.font_offset
;
247 FT_Face root
= (FT_Face
)&face
->root
;
252 (void)T1_ToFixedArray( parser
, 6, temp
, 3 );
254 temp_scale
= FT_ABS( temp
[3] );
256 /* Set Units per EM based on FontMatrix values. We set the value to */
257 /* 1000 / temp_scale, because temp_scale was already multiplied by */
258 /* 1000 (in t1_tofixed, from psobjs.c). */
260 root
->units_per_EM
= (FT_UShort
)( FT_DivFix( 1000 * 0x10000L
,
261 temp_scale
) >> 16 );
263 /* we need to scale the values by 1.0/temp_scale */
264 if ( temp_scale
!= 0x10000L
) {
265 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
266 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
267 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
268 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
269 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
273 matrix
->xx
= temp
[0];
274 matrix
->yx
= temp
[1];
275 matrix
->xy
= temp
[2];
276 matrix
->yy
= temp
[3];
278 /* note that the offsets must be expressed in integer font units */
279 offset
->x
= temp
[4] >> 16;
280 offset
->y
= temp
[5] >> 16;
285 t42_parse_encoding( T42_Face face
,
288 T42_Parser parser
= &loader
->parser
;
290 FT_Byte
* limit
= parser
->root
.limit
;
292 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
295 T1_Skip_Spaces( parser
);
296 cur
= parser
->root
.cursor
;
299 FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
300 parser
->root
.error
= T42_Err_Invalid_File_Format
;
304 /* if we have a number or `[', the encoding is an array, */
305 /* and we must load it now */
306 if ( ft_isdigit( *cur
) || *cur
== '[' )
308 T1_Encoding encode
= &face
->type1
.encoding
;
310 PS_Table char_table
= &loader
->encoding_table
;
311 FT_Memory memory
= parser
->root
.memory
;
313 FT_Bool only_immediates
= 0;
316 /* read the number of entries in the encoding; should be 256 */
321 parser
->root
.cursor
++;
324 count
= (FT_UInt
)T1_ToInt( parser
);
326 T1_Skip_Spaces( parser
);
327 if ( parser
->root
.cursor
>= limit
)
330 /* we use a T1_Table to store our charnames */
331 loader
->num_chars
= encode
->num_chars
= count
;
332 if ( FT_NEW_ARRAY( encode
->char_index
, count
) ||
333 FT_NEW_ARRAY( encode
->char_name
, count
) ||
334 FT_SET_ERROR( psaux
->ps_table_funcs
->init(
335 char_table
, count
, memory
) ) )
337 parser
->root
.error
= error
;
341 /* We need to `zero' out encoding_table.elements */
342 for ( n
= 0; n
< count
; n
++ )
344 char* notdef
= (char *)".notdef";
347 T1_Add_Table( char_table
, n
, notdef
, 8 );
350 /* Now we need to read records of the form */
352 /* ... charcode /charname ... */
354 /* for each entry in our table. */
356 /* We simply look for a number followed by an immediate */
357 /* name. Note that this ignores correctly the sequence */
358 /* that is often seen in type42 fonts: */
360 /* 0 1 255 { 1 index exch /.notdef put } for dup */
362 /* used to clean the encoding array before anything else. */
364 /* Alternatively, if the array is directly given as */
366 /* /Encoding [ ... ] */
368 /* we only read immediates. */
371 T1_Skip_Spaces( parser
);
373 while ( parser
->root
.cursor
< limit
)
375 cur
= parser
->root
.cursor
;
377 /* we stop when we encounter `def' or `]' */
378 if ( *cur
== 'd' && cur
+ 3 < limit
)
380 if ( cur
[1] == 'e' &&
382 t42_is_space( cur
[3] ) )
384 FT_TRACE6(( "encoding end\n" ));
391 FT_TRACE6(( "encoding end\n" ));
396 /* check whether we have found an entry */
397 if ( ft_isdigit( *cur
) || only_immediates
)
402 if ( only_immediates
)
406 charcode
= (FT_Int
)T1_ToInt( parser
);
407 T1_Skip_Spaces( parser
);
410 cur
= parser
->root
.cursor
;
412 if ( *cur
== '/' && cur
+ 2 < limit
&& n
< count
)
419 parser
->root
.cursor
= cur
;
420 T1_Skip_PS_Token( parser
);
421 if ( parser
->root
.error
)
424 len
= parser
->root
.cursor
- cur
;
426 parser
->root
.error
= T1_Add_Table( char_table
, charcode
,
428 if ( parser
->root
.error
)
430 char_table
->elements
[charcode
][len
] = '\0';
437 T1_Skip_PS_Token( parser
);
438 if ( parser
->root
.error
)
442 T1_Skip_Spaces( parser
);
445 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ARRAY
;
446 parser
->root
.cursor
= cur
;
449 /* Otherwise, we should have either `StandardEncoding', */
450 /* `ExpertEncoding', or `ISOLatin1Encoding' */
453 if ( cur
+ 17 < limit
&&
454 ft_strncmp( (const char*)cur
, "StandardEncoding", 16 ) == 0 )
455 face
->type1
.encoding_type
= T1_ENCODING_TYPE_STANDARD
;
457 else if ( cur
+ 15 < limit
&&
458 ft_strncmp( (const char*)cur
, "ExpertEncoding", 14 ) == 0 )
459 face
->type1
.encoding_type
= T1_ENCODING_TYPE_EXPERT
;
461 else if ( cur
+ 18 < limit
&&
462 ft_strncmp( (const char*)cur
, "ISOLatin1Encoding", 17 ) == 0 )
463 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ISOLATIN1
;
467 FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
468 parser
->root
.error
= T42_Err_Invalid_File_Format
;
474 typedef enum T42_Load_Status_
484 t42_parse_sfnts( T42_Face face
,
487 T42_Parser parser
= &loader
->parser
;
488 FT_Memory memory
= parser
->root
.memory
;
490 FT_Byte
* limit
= parser
->root
.limit
;
492 FT_Int num_tables
= 0;
493 FT_ULong count
, ttf_size
= 0;
495 FT_Long n
, string_size
, old_string_size
, real_size
;
496 FT_Byte
* string_buf
= NULL
;
497 FT_Bool allocated
= 0;
499 T42_Load_Status status
;
504 /* /sfnts [ <hexstring> <hexstring> ... ] def */
509 /* <num_bin_bytes> RD <binary data> */
510 /* <num_bin_bytes> RD <binary data> */
514 /* with exactly one space after the `RD' token. */
516 T1_Skip_Spaces( parser
);
518 if ( parser
->root
.cursor
>= limit
|| *parser
->root
.cursor
++ != '[' )
520 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
521 error
= T42_Err_Invalid_File_Format
;
525 T1_Skip_Spaces( parser
);
526 status
= BEFORE_START
;
531 while ( parser
->root
.cursor
< limit
)
533 cur
= parser
->root
.cursor
;
537 parser
->root
.cursor
++;
541 else if ( *cur
== '<' )
543 T1_Skip_PS_Token( parser
);
544 if ( parser
->root
.error
)
547 /* don't include delimiters */
548 string_size
= (FT_Long
)( ( parser
->root
.cursor
- cur
- 2 + 1 ) / 2 );
549 if ( FT_REALLOC( string_buf
, old_string_size
, string_size
) )
554 parser
->root
.cursor
= cur
;
555 (void)T1_ToBytes( parser
, string_buf
, string_size
, &real_size
, 1 );
556 old_string_size
= string_size
;
557 string_size
= real_size
;
560 else if ( ft_isdigit( *cur
) )
564 FT_ERROR(( "t42_parse_sfnts: "
565 "can't handle mixed binary and hex strings!\n" ));
566 error
= T42_Err_Invalid_File_Format
;
570 string_size
= T1_ToInt( parser
);
572 T1_Skip_PS_Token( parser
); /* `RD' */
573 if ( parser
->root
.error
)
576 string_buf
= parser
->root
.cursor
+ 1; /* one space after `RD' */
578 parser
->root
.cursor
+= string_size
+ 1;
579 if ( parser
->root
.cursor
>= limit
)
581 FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
582 error
= T42_Err_Invalid_File_Format
;
589 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array!\n" ));
590 error
= T42_Err_Invalid_File_Format
;
594 /* A string can have a trailing zero byte for padding. Ignore it. */
595 if ( string_buf
[string_size
- 1] == 0 && ( string_size
% 2 == 1 ) )
600 FT_ERROR(( "t42_parse_sfnts: invalid string!\n" ));
601 error
= T42_Err_Invalid_File_Format
;
605 for ( n
= 0; n
< string_size
; n
++ )
610 /* load offset table, 12 bytes */
613 face
->ttf_data
[count
++] = string_buf
[n
];
618 num_tables
= 16 * face
->ttf_data
[4] + face
->ttf_data
[5];
619 status
= BEFORE_TABLE_DIR
;
620 ttf_size
= 12 + 16 * num_tables
;
622 if ( FT_REALLOC( face
->ttf_data
, 12, ttf_size
) )
627 case BEFORE_TABLE_DIR
:
628 /* the offset table is read; read the table directory */
629 if ( count
< ttf_size
)
631 face
->ttf_data
[count
++] = string_buf
[n
];
640 for ( i
= 0; i
< num_tables
; i
++ )
642 FT_Byte
* p
= face
->ttf_data
+ 12 + 16 * i
+ 12;
645 len
= FT_PEEK_ULONG( p
);
647 /* Pad to a 4-byte boundary length */
648 ttf_size
+= ( len
+ 3 ) & ~3;
651 status
= OTHER_TABLES
;
652 face
->ttf_size
= ttf_size
;
654 /* there are no more than 256 tables, so no size check here */
655 if ( FT_REALLOC( face
->ttf_data
, 12 + 16 * num_tables
,
662 /* all other tables are just copied */
663 if ( count
>= ttf_size
)
665 FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
666 error
= T42_Err_Invalid_File_Format
;
669 face
->ttf_data
[count
++] = string_buf
[n
];
673 T1_Skip_Spaces( parser
);
676 /* if control reaches this point, the format was not valid */
677 error
= T42_Err_Invalid_File_Format
;
680 parser
->root
.error
= error
;
684 FT_FREE( string_buf
);
689 t42_parse_charstrings( T42_Face face
,
692 T42_Parser parser
= &loader
->parser
;
693 PS_Table code_table
= &loader
->charstrings
;
694 PS_Table name_table
= &loader
->glyph_names
;
695 PS_Table swap_table
= &loader
->swap_table
;
696 FT_Memory memory
= parser
->root
.memory
;
699 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
702 FT_Byte
* limit
= parser
->root
.limit
;
704 FT_UInt notdef_index
= 0;
705 FT_Byte notdef_found
= 0;
708 T1_Skip_Spaces( parser
);
710 if ( parser
->root
.cursor
>= limit
)
712 FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
713 error
= T42_Err_Invalid_File_Format
;
717 if ( ft_isdigit( *parser
->root
.cursor
) )
719 loader
->num_glyphs
= (FT_UInt
)T1_ToInt( parser
);
720 if ( parser
->root
.error
)
723 else if ( *parser
->root
.cursor
== '<' )
725 /* We have `<< ... >>'. Count the number of `/' in the dictionary */
726 /* to get its size. */
730 T1_Skip_PS_Token( parser
);
731 if ( parser
->root
.error
)
733 T1_Skip_Spaces( parser
);
734 cur
= parser
->root
.cursor
;
736 while ( parser
->root
.cursor
< limit
)
738 if ( *parser
->root
.cursor
== '/' )
740 else if ( *parser
->root
.cursor
== '>' )
742 loader
->num_glyphs
= count
;
743 parser
->root
.cursor
= cur
; /* rewind */
746 T1_Skip_PS_Token( parser
);
747 if ( parser
->root
.error
)
749 T1_Skip_Spaces( parser
);
754 FT_ERROR(( "t42_parse_charstrings: invalid token!\n" ));
755 error
= T42_Err_Invalid_File_Format
;
759 if ( parser
->root
.cursor
>= limit
)
761 FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
762 error
= T42_Err_Invalid_File_Format
;
766 /* initialize tables */
768 error
= psaux
->ps_table_funcs
->init( code_table
,
774 error
= psaux
->ps_table_funcs
->init( name_table
,
780 /* Initialize table for swapping index notdef_index and */
781 /* index 0 names and codes (if necessary). */
783 error
= psaux
->ps_table_funcs
->init( swap_table
, 4, memory
);
791 /* The format is simple: */
792 /* `/glyphname' + index [+ def] */
794 T1_Skip_Spaces( parser
);
796 cur
= parser
->root
.cursor
;
800 /* We stop when we find an `end' keyword or '>' */
805 t42_is_space( cur
[3] ) )
810 T1_Skip_PS_Token( parser
);
811 if ( parser
->root
.error
)
819 if ( cur
+ 1 >= limit
)
821 FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
822 error
= T42_Err_Invalid_File_Format
;
826 cur
++; /* skip `/' */
827 len
= parser
->root
.cursor
- cur
;
829 error
= T1_Add_Table( name_table
, n
, cur
, len
+ 1 );
833 /* add a trailing zero to the name table */
834 name_table
->elements
[n
][len
] = '\0';
836 /* record index of /.notdef */
838 ft_strcmp( ".notdef",
839 (const char*)(name_table
->elements
[n
]) ) == 0 )
845 T1_Skip_Spaces( parser
);
847 cur
= parser
->root
.cursor
;
849 (void)T1_ToInt( parser
);
850 if ( parser
->root
.cursor
>= limit
)
852 FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
853 error
= T42_Err_Invalid_File_Format
;
857 len
= parser
->root
.cursor
- cur
;
859 error
= T1_Add_Table( code_table
, n
, cur
, len
+ 1 );
863 code_table
->elements
[n
][len
] = '\0';
866 if ( n
>= loader
->num_glyphs
)
871 loader
->num_glyphs
= n
;
875 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" ));
876 error
= T42_Err_Invalid_File_Format
;
880 /* if /.notdef does not occupy index 0, do our magic. */
881 if ( ft_strcmp( (const char*)".notdef",
882 (const char*)name_table
->elements
[0] ) )
884 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
885 /* name and code entries to swap_table. Then place notdef_index */
886 /* name and code entries into swap_table. Then swap name and code */
887 /* entries at indices notdef_index and 0 using values stored in */
891 error
= T1_Add_Table( swap_table
, 0,
892 name_table
->elements
[0],
893 name_table
->lengths
[0] );
898 error
= T1_Add_Table( swap_table
, 1,
899 code_table
->elements
[0],
900 code_table
->lengths
[0] );
904 /* Index notdef_index name */
905 error
= T1_Add_Table( swap_table
, 2,
906 name_table
->elements
[notdef_index
],
907 name_table
->lengths
[notdef_index
] );
911 /* Index notdef_index code */
912 error
= T1_Add_Table( swap_table
, 3,
913 code_table
->elements
[notdef_index
],
914 code_table
->lengths
[notdef_index
] );
918 error
= T1_Add_Table( name_table
, notdef_index
,
919 swap_table
->elements
[0],
920 swap_table
->lengths
[0] );
924 error
= T1_Add_Table( code_table
, notdef_index
,
925 swap_table
->elements
[1],
926 swap_table
->lengths
[1] );
930 error
= T1_Add_Table( name_table
, 0,
931 swap_table
->elements
[2],
932 swap_table
->lengths
[2] );
936 error
= T1_Add_Table( code_table
, 0,
937 swap_table
->elements
[3],
938 swap_table
->lengths
[3] );
947 parser
->root
.error
= error
;
952 t42_load_keyword( T42_Face face
,
959 FT_UInt max_objects
= 0;
962 /* if the keyword has a dedicated callback, call it */
963 if ( field
->type
== T1_FIELD_TYPE_CALLBACK
)
965 field
->reader( (FT_Face
)face
, loader
);
966 error
= loader
->parser
.root
.error
;
970 /* now the keyword is either a simple field or a table of fields; */
971 /* we are now going to take care of it */
973 switch ( field
->location
)
975 case T1_FIELD_LOCATION_FONT_INFO
:
976 dummy_object
= &face
->type1
.font_info
;
979 case T1_FIELD_LOCATION_BBOX
:
980 dummy_object
= &face
->type1
.font_bbox
;
984 dummy_object
= &face
->type1
;
987 objects
= &dummy_object
;
989 if ( field
->type
== T1_FIELD_TYPE_INTEGER_ARRAY
||
990 field
->type
== T1_FIELD_TYPE_FIXED_ARRAY
)
991 error
= T1_Load_Field_Table( &loader
->parser
, field
,
992 objects
, max_objects
, 0 );
994 error
= T1_Load_Field( &loader
->parser
, field
,
995 objects
, max_objects
, 0 );
1002 FT_LOCAL_DEF( FT_Error
)
1003 t42_parse_dict( T42_Face face
,
1008 T42_Parser parser
= &loader
->parser
;
1010 FT_Int n_keywords
= (FT_Int
)( sizeof ( t42_keywords
) /
1011 sizeof ( t42_keywords
[0] ) );
1014 parser
->root
.cursor
= base
;
1015 parser
->root
.limit
= base
+ size
;
1016 parser
->root
.error
= T42_Err_Ok
;
1018 limit
= parser
->root
.limit
;
1020 T1_Skip_Spaces( parser
);
1022 while ( parser
->root
.cursor
< limit
)
1027 cur
= parser
->root
.cursor
;
1029 /* look for `FontDirectory' which causes problems for some fonts */
1030 if ( *cur
== 'F' && cur
+ 25 < limit
&&
1031 ft_strncmp( (char*)cur
, "FontDirectory", 13 ) == 0 )
1036 /* skip the `FontDirectory' keyword */
1037 T1_Skip_PS_Token( parser
);
1038 T1_Skip_Spaces ( parser
);
1039 cur
= cur2
= parser
->root
.cursor
;
1041 /* look up the `known' keyword */
1042 while ( cur
< limit
)
1044 if ( *cur
== 'k' && cur
+ 5 < limit
&&
1045 ft_strncmp( (char*)cur
, "known", 5 ) == 0 )
1048 T1_Skip_PS_Token( parser
);
1049 if ( parser
->root
.error
)
1051 T1_Skip_Spaces ( parser
);
1052 cur
= parser
->root
.cursor
;
1060 /* skip the `known' keyword and the token following it */
1061 T1_Skip_PS_Token( parser
);
1062 T1_ToToken( parser
, &token
);
1064 /* if the last token was an array, skip it! */
1065 if ( token
.type
== T1_TOKEN_TYPE_ARRAY
)
1066 cur2
= parser
->root
.cursor
;
1068 parser
->root
.cursor
= cur2
;
1071 /* look for immediates */
1072 else if ( *cur
== '/' && cur
+ 2 < limit
)
1079 parser
->root
.cursor
= cur
;
1080 T1_Skip_PS_Token( parser
);
1081 if ( parser
->root
.error
)
1084 len
= parser
->root
.cursor
- cur
;
1086 if ( len
> 0 && len
< 22 && parser
->root
.cursor
< limit
)
1091 /* now compare the immediate name to the keyword table */
1093 /* loop through all known keywords */
1094 for ( i
= 0; i
< n_keywords
; i
++ )
1096 T1_Field keyword
= (T1_Field
)&t42_keywords
[i
];
1097 FT_Byte
*name
= (FT_Byte
*)keyword
->ident
;
1103 if ( cur
[0] == name
[0] &&
1104 len
== (FT_PtrDist
)ft_strlen( (const char *)name
) &&
1105 ft_memcmp( cur
, name
, len
) == 0 )
1107 /* we found it -- run the parsing callback! */
1108 parser
->root
.error
= t42_load_keyword( face
,
1111 if ( parser
->root
.error
)
1112 return parser
->root
.error
;
1120 T1_Skip_PS_Token( parser
);
1121 if ( parser
->root
.error
)
1125 T1_Skip_Spaces( parser
);
1129 return parser
->root
.error
;
1133 FT_LOCAL_DEF( void )
1134 t42_loader_init( T42_Loader loader
,
1139 FT_MEM_ZERO( loader
, sizeof ( *loader
) );
1140 loader
->num_glyphs
= 0;
1141 loader
->num_chars
= 0;
1143 /* initialize the tables -- simply set their `init' field to 0 */
1144 loader
->encoding_table
.init
= 0;
1145 loader
->charstrings
.init
= 0;
1146 loader
->glyph_names
.init
= 0;
1150 FT_LOCAL_DEF( void )
1151 t42_loader_done( T42_Loader loader
)
1153 T42_Parser parser
= &loader
->parser
;
1156 /* finalize tables */
1157 T1_Release_Table( &loader
->encoding_table
);
1158 T1_Release_Table( &loader
->charstrings
);
1159 T1_Release_Table( &loader
->glyph_names
);
1160 T1_Release_Table( &loader
->swap_table
);
1162 /* finalize parser */
1163 t42_parser_done( parser
);