1 /***************************************************************************/
5 /* Type 42 font parser (body). */
7 /* Copyright 2002-2015 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
[] =
59 #define FT_STRUCTURE T1_FontInfo
61 #define T1CODE T1_FIELD_LOCATION_FONT_INFO
63 T1_FIELD_STRING( "version", version
, 0 )
64 T1_FIELD_STRING( "Notice", notice
, 0 )
65 T1_FIELD_STRING( "FullName", full_name
, 0 )
66 T1_FIELD_STRING( "FamilyName", family_name
, 0 )
67 T1_FIELD_STRING( "Weight", weight
, 0 )
68 T1_FIELD_NUM ( "ItalicAngle", italic_angle
, 0 )
69 T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch
, 0 )
70 T1_FIELD_NUM ( "UnderlinePosition", underline_position
, 0 )
71 T1_FIELD_NUM ( "UnderlineThickness", underline_thickness
, 0 )
74 #define FT_STRUCTURE PS_FontExtraRec
76 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
78 T1_FIELD_NUM ( "FSType", fs_type
, 0 )
81 #define FT_STRUCTURE T1_FontRec
83 #define T1CODE T1_FIELD_LOCATION_FONT_DICT
85 T1_FIELD_KEY ( "FontName", font_name
, 0 )
86 T1_FIELD_NUM ( "PaintType", paint_type
, 0 )
87 T1_FIELD_NUM ( "FontType", font_type
, 0 )
88 T1_FIELD_FIXED( "StrokeWidth", stroke_width
, 0 )
91 #define FT_STRUCTURE FT_BBox
93 #define T1CODE T1_FIELD_LOCATION_BBOX
95 T1_FIELD_BBOX("FontBBox", xMin
, 0 )
97 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix
, 0 )
98 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding
, 0 )
99 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings
, 0 )
100 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts
, 0 )
102 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
106 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
107 #define T1_Release_Table( p ) \
110 if ( (p)->funcs.release ) \
111 (p)->funcs.release( p ); \
114 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
115 #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root )
117 #define T1_ToInt( p ) \
118 (p)->root.funcs.to_int( &(p)->root )
119 #define T1_ToBytes( p, b, m, n, d ) \
120 (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
122 #define T1_ToFixedArray( p, m, f, t ) \
123 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
124 #define T1_ToToken( p, t ) \
125 (p)->root.funcs.to_token( &(p)->root, t )
127 #define T1_Load_Field( p, f, o, m, pf ) \
128 (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
129 #define T1_Load_Field_Table( p, f, o, m, pf ) \
130 (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
133 /********************* Parsing Functions ******************/
135 FT_LOCAL_DEF( FT_Error
)
136 t42_parser_init( T42_Parser parser
,
139 PSAux_Service psaux
)
141 FT_Error error
= FT_Err_Ok
;
145 psaux
->ps_parser_funcs
->init( &parser
->root
, NULL
, NULL
, memory
);
147 parser
->stream
= stream
;
148 parser
->base_len
= 0;
149 parser
->base_dict
= NULL
;
150 parser
->in_memory
= 0;
152 /*******************************************************************/
154 /* Here a short summary of what is going on: */
156 /* When creating a new Type 42 parser, we try to locate and load */
157 /* the base dictionary, loading the whole font into memory. */
159 /* When `loading' the base dictionary, we only set up pointers */
160 /* in the case of a memory-based stream. Otherwise, we allocate */
161 /* and load the base dictionary in it. */
163 /* parser->in_memory is set if we have a memory stream. */
166 if ( FT_STREAM_SEEK( 0L ) ||
167 FT_FRAME_ENTER( 17 ) )
170 if ( ft_memcmp( stream
->cursor
, "%!PS-TrueTypeFont", 17 ) != 0 )
172 FT_TRACE2(( " not a Type42 font\n" ));
173 error
= FT_THROW( Unknown_File_Format
);
178 if ( error
|| FT_STREAM_SEEK( 0 ) )
181 size
= (FT_Long
)stream
->size
;
183 /* now, try to load `size' bytes of the `base' dictionary we */
184 /* found previously */
186 /* if it is a memory-based resource, set up pointers */
189 parser
->base_dict
= (FT_Byte
*)stream
->base
+ stream
->pos
;
190 parser
->base_len
= size
;
191 parser
->in_memory
= 1;
193 /* check that the `size' field is valid */
194 if ( FT_STREAM_SKIP( size
) )
199 /* read segment in memory */
200 if ( FT_ALLOC( parser
->base_dict
, size
) ||
201 FT_STREAM_READ( parser
->base_dict
, size
) )
204 parser
->base_len
= size
;
207 parser
->root
.base
= parser
->base_dict
;
208 parser
->root
.cursor
= parser
->base_dict
;
209 parser
->root
.limit
= parser
->root
.cursor
+ parser
->base_len
;
212 if ( error
&& !parser
->in_memory
)
213 FT_FREE( parser
->base_dict
);
220 t42_parser_done( T42_Parser parser
)
222 FT_Memory memory
= parser
->root
.memory
;
225 /* free the base dictionary only when we have a disk stream */
226 if ( !parser
->in_memory
)
227 FT_FREE( parser
->base_dict
);
229 parser
->root
.funcs
.done( &parser
->root
);
234 t42_is_space( FT_Byte c
)
236 return ( c
== ' ' || c
== '\t' ||
237 c
== '\r' || c
== '\n' || c
== '\f' ||
243 t42_parse_font_matrix( T42_Face face
,
246 T42_Parser parser
= &loader
->parser
;
247 FT_Matrix
* matrix
= &face
->type1
.font_matrix
;
248 FT_Vector
* offset
= &face
->type1
.font_offset
;
254 result
= T1_ToFixedArray( parser
, 6, temp
, 0 );
258 parser
->root
.error
= FT_THROW( Invalid_File_Format
);
262 temp_scale
= FT_ABS( temp
[3] );
264 if ( temp_scale
== 0 )
266 FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
267 parser
->root
.error
= FT_THROW( Invalid_File_Format
);
272 if ( temp_scale
!= 0x10000L
)
274 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
275 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
276 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
277 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
278 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
279 temp
[3] = temp
[3] < 0 ? -0x10000L
: 0x10000L
;
282 matrix
->xx
= temp
[0];
283 matrix
->yx
= temp
[1];
284 matrix
->xy
= temp
[2];
285 matrix
->yy
= temp
[3];
287 /* note that the offsets must be expressed in integer font units */
288 offset
->x
= temp
[4] >> 16;
289 offset
->y
= temp
[5] >> 16;
294 t42_parse_encoding( T42_Face face
,
297 T42_Parser parser
= &loader
->parser
;
299 FT_Byte
* limit
= parser
->root
.limit
;
301 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
304 T1_Skip_Spaces( parser
);
305 cur
= parser
->root
.cursor
;
308 FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
309 parser
->root
.error
= FT_THROW( Invalid_File_Format
);
313 /* if we have a number or `[', the encoding is an array, */
314 /* and we must load it now */
315 if ( ft_isdigit( *cur
) || *cur
== '[' )
317 T1_Encoding encode
= &face
->type1
.encoding
;
319 PS_Table char_table
= &loader
->encoding_table
;
320 FT_Memory memory
= parser
->root
.memory
;
322 FT_Bool only_immediates
= 0;
325 /* read the number of entries in the encoding; should be 256 */
330 parser
->root
.cursor
++;
333 count
= (FT_Int
)T1_ToInt( parser
);
335 /* only composite fonts (which we don't support) */
336 /* can have larger values */
339 FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" ));
340 parser
->root
.error
= FT_THROW( Invalid_File_Format
);
344 T1_Skip_Spaces( parser
);
345 if ( parser
->root
.cursor
>= limit
)
348 /* PostScript happily allows overwriting of encoding arrays */
349 if ( encode
->char_index
)
351 FT_FREE( encode
->char_index
);
352 FT_FREE( encode
->char_name
);
353 T1_Release_Table( char_table
);
356 /* we use a T1_Table to store our charnames */
357 loader
->num_chars
= encode
->num_chars
= count
;
358 if ( FT_NEW_ARRAY( encode
->char_index
, count
) ||
359 FT_NEW_ARRAY( encode
->char_name
, count
) ||
360 FT_SET_ERROR( psaux
->ps_table_funcs
->init(
361 char_table
, count
, memory
) ) )
363 parser
->root
.error
= error
;
367 /* We need to `zero' out encoding_table.elements */
368 for ( n
= 0; n
< count
; n
++ )
370 char* notdef
= (char *)".notdef";
373 (void)T1_Add_Table( char_table
, n
, notdef
, 8 );
376 /* Now we need to read records of the form */
378 /* ... charcode /charname ... */
380 /* for each entry in our table. */
382 /* We simply look for a number followed by an immediate */
383 /* name. Note that this ignores correctly the sequence */
384 /* that is often seen in type42 fonts: */
386 /* 0 1 255 { 1 index exch /.notdef put } for dup */
388 /* used to clean the encoding array before anything else. */
390 /* Alternatively, if the array is directly given as */
392 /* /Encoding [ ... ] */
394 /* we only read immediates. */
397 T1_Skip_Spaces( parser
);
399 while ( parser
->root
.cursor
< limit
)
401 cur
= parser
->root
.cursor
;
403 /* we stop when we encounter `def' or `]' */
404 if ( *cur
== 'd' && cur
+ 3 < limit
)
406 if ( cur
[1] == 'e' &&
408 t42_is_space( cur
[3] ) )
410 FT_TRACE6(( "encoding end\n" ));
417 FT_TRACE6(( "encoding end\n" ));
422 /* check whether we have found an entry */
423 if ( ft_isdigit( *cur
) || only_immediates
)
428 if ( only_immediates
)
432 charcode
= (FT_Int
)T1_ToInt( parser
);
433 T1_Skip_Spaces( parser
);
435 /* protect against invalid charcode */
436 if ( cur
== parser
->root
.cursor
)
438 parser
->root
.error
= FT_THROW( Unknown_File_Format
);
443 cur
= parser
->root
.cursor
;
445 if ( cur
+ 2 < limit
&& *cur
== '/' && n
< count
)
452 parser
->root
.cursor
= cur
;
453 T1_Skip_PS_Token( parser
);
454 if ( parser
->root
.cursor
>= limit
)
456 if ( parser
->root
.error
)
459 len
= (FT_UInt
)( parser
->root
.cursor
- cur
);
461 parser
->root
.error
= T1_Add_Table( char_table
, charcode
,
463 if ( parser
->root
.error
)
465 char_table
->elements
[charcode
][len
] = '\0';
469 else if ( only_immediates
)
471 /* Since the current position is not updated for */
472 /* immediates-only mode we would get an infinite loop if */
473 /* we don't do anything here. */
475 /* This encoding array is not valid according to the */
476 /* type42 specification (it might be an encoding for a CID */
477 /* type42 font, however), so we conclude that this font is */
478 /* NOT a type42 font. */
479 parser
->root
.error
= FT_THROW( Unknown_File_Format
);
485 T1_Skip_PS_Token( parser
);
486 if ( parser
->root
.error
)
490 T1_Skip_Spaces( parser
);
493 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ARRAY
;
494 parser
->root
.cursor
= cur
;
497 /* Otherwise, we should have either `StandardEncoding', */
498 /* `ExpertEncoding', or `ISOLatin1Encoding' */
501 if ( cur
+ 17 < limit
&&
502 ft_strncmp( (const char*)cur
, "StandardEncoding", 16 ) == 0 )
503 face
->type1
.encoding_type
= T1_ENCODING_TYPE_STANDARD
;
505 else if ( cur
+ 15 < limit
&&
506 ft_strncmp( (const char*)cur
, "ExpertEncoding", 14 ) == 0 )
507 face
->type1
.encoding_type
= T1_ENCODING_TYPE_EXPERT
;
509 else if ( cur
+ 18 < limit
&&
510 ft_strncmp( (const char*)cur
, "ISOLatin1Encoding", 17 ) == 0 )
511 face
->type1
.encoding_type
= T1_ENCODING_TYPE_ISOLATIN1
;
514 parser
->root
.error
= FT_ERR( Ignore
);
519 typedef enum T42_Load_Status_
529 t42_parse_sfnts( T42_Face face
,
532 T42_Parser parser
= &loader
->parser
;
533 FT_Memory memory
= parser
->root
.memory
;
535 FT_Byte
* limit
= parser
->root
.limit
;
537 FT_Int num_tables
= 0;
540 FT_ULong n
, string_size
, old_string_size
, real_size
;
541 FT_Byte
* string_buf
= NULL
;
542 FT_Bool allocated
= 0;
544 T42_Load_Status status
;
549 /* /sfnts [ <hexstring> <hexstring> ... ] def */
554 /* <num_bin_bytes> RD <binary data> */
555 /* <num_bin_bytes> RD <binary data> */
559 /* with exactly one space after the `RD' token. */
561 T1_Skip_Spaces( parser
);
563 if ( parser
->root
.cursor
>= limit
|| *parser
->root
.cursor
++ != '[' )
565 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
566 error
= FT_THROW( Invalid_File_Format
);
570 T1_Skip_Spaces( parser
);
571 status
= BEFORE_START
;
576 while ( parser
->root
.cursor
< limit
)
578 cur
= parser
->root
.cursor
;
582 parser
->root
.cursor
++;
586 else if ( *cur
== '<' )
588 T1_Skip_PS_Token( parser
);
589 if ( parser
->root
.error
)
592 /* don't include delimiters */
593 string_size
= (FT_ULong
)( ( parser
->root
.cursor
- cur
- 2 + 1 ) / 2 );
596 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
597 error
= FT_THROW( Invalid_File_Format
);
600 if ( FT_REALLOC( string_buf
, old_string_size
, string_size
) )
605 parser
->root
.cursor
= cur
;
606 (void)T1_ToBytes( parser
, string_buf
, string_size
, &real_size
, 1 );
607 old_string_size
= string_size
;
608 string_size
= real_size
;
611 else if ( ft_isdigit( *cur
) )
618 FT_ERROR(( "t42_parse_sfnts: "
619 "can't handle mixed binary and hex strings\n" ));
620 error
= FT_THROW( Invalid_File_Format
);
624 tmp
= T1_ToInt( parser
);
627 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
628 error
= FT_THROW( Invalid_File_Format
);
632 string_size
= (FT_ULong
)tmp
;
634 T1_Skip_PS_Token( parser
); /* `RD' */
635 if ( parser
->root
.error
)
638 string_buf
= parser
->root
.cursor
+ 1; /* one space after `RD' */
640 if ( (FT_ULong
)( limit
- parser
->root
.cursor
) < string_size
)
642 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
643 error
= FT_THROW( Invalid_File_Format
);
647 parser
->root
.cursor
+= string_size
+ 1;
652 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
653 error
= FT_THROW( Invalid_File_Format
);
657 /* A string can have a trailing zero (odd) byte for padding. */
659 if ( ( string_size
& 1 ) && string_buf
[string_size
- 1] == 0 )
664 FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
665 error
= FT_THROW( Invalid_File_Format
);
669 for ( n
= 0; n
< string_size
; n
++ )
674 /* load offset table, 12 bytes */
677 face
->ttf_data
[count
++] = string_buf
[n
];
682 num_tables
= 16 * face
->ttf_data
[4] + face
->ttf_data
[5];
683 status
= BEFORE_TABLE_DIR
;
684 face
->ttf_size
= 12 + 16 * num_tables
;
686 if ( (FT_Long
)( limit
- parser
->root
.cursor
) < face
->ttf_size
)
688 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
689 error
= FT_THROW( Invalid_File_Format
);
693 if ( FT_REALLOC( face
->ttf_data
, 12, face
->ttf_size
) )
698 case BEFORE_TABLE_DIR
:
699 /* the offset table is read; read the table directory */
700 if ( count
< face
->ttf_size
)
702 face
->ttf_data
[count
++] = string_buf
[n
];
711 for ( i
= 0; i
< num_tables
; i
++ )
713 FT_Byte
* p
= face
->ttf_data
+ 12 + 16 * i
+ 12;
716 len
= FT_PEEK_ULONG( p
);
718 /* Pad to a 4-byte boundary length */
719 face
->ttf_size
+= (FT_Long
)( ( len
+ 3 ) & ~3U );
722 status
= OTHER_TABLES
;
724 /* there are no more than 256 tables, so no size check here */
725 if ( FT_REALLOC( face
->ttf_data
, 12 + 16 * num_tables
,
726 face
->ttf_size
+ 1 ) )
732 /* all other tables are just copied */
733 if ( count
>= face
->ttf_size
)
735 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
736 error
= FT_THROW( Invalid_File_Format
);
739 face
->ttf_data
[count
++] = string_buf
[n
];
743 T1_Skip_Spaces( parser
);
746 /* if control reaches this point, the format was not valid */
747 error
= FT_THROW( Invalid_File_Format
);
750 parser
->root
.error
= error
;
754 FT_FREE( string_buf
);
759 t42_parse_charstrings( T42_Face face
,
762 T42_Parser parser
= &loader
->parser
;
763 PS_Table code_table
= &loader
->charstrings
;
764 PS_Table name_table
= &loader
->glyph_names
;
765 PS_Table swap_table
= &loader
->swap_table
;
766 FT_Memory memory
= parser
->root
.memory
;
769 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
772 FT_Byte
* limit
= parser
->root
.limit
;
774 FT_Int notdef_index
= 0;
775 FT_Byte notdef_found
= 0;
778 T1_Skip_Spaces( parser
);
780 if ( parser
->root
.cursor
>= limit
)
782 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
783 error
= FT_THROW( Invalid_File_Format
);
787 if ( ft_isdigit( *parser
->root
.cursor
) )
789 loader
->num_glyphs
= T1_ToInt( parser
);
790 if ( parser
->root
.error
)
792 if ( loader
->num_glyphs
< 0 )
794 FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" ));
795 error
= FT_THROW( Invalid_File_Format
);
799 else if ( *parser
->root
.cursor
== '<' )
801 /* We have `<< ... >>'. Count the number of `/' in the dictionary */
802 /* to get its size. */
806 T1_Skip_PS_Token( parser
);
807 if ( parser
->root
.error
)
809 T1_Skip_Spaces( parser
);
810 cur
= parser
->root
.cursor
;
812 while ( parser
->root
.cursor
< limit
)
814 if ( *parser
->root
.cursor
== '/' )
816 else if ( *parser
->root
.cursor
== '>' )
818 loader
->num_glyphs
= count
;
819 parser
->root
.cursor
= cur
; /* rewind */
822 T1_Skip_PS_Token( parser
);
823 if ( parser
->root
.error
)
825 T1_Skip_Spaces( parser
);
830 FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
831 error
= FT_THROW( Invalid_File_Format
);
835 if ( parser
->root
.cursor
>= limit
)
837 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
838 error
= FT_THROW( Invalid_File_Format
);
842 /* initialize tables */
844 /* contrary to Type1, we disallow multiple CharStrings arrays */
845 if ( swap_table
->init
)
847 FT_ERROR(( "t42_parse_charstrings:"
848 " only one CharStrings array allowed\n" ));
849 error
= FT_THROW( Invalid_File_Format
);
853 error
= psaux
->ps_table_funcs
->init( code_table
,
859 error
= psaux
->ps_table_funcs
->init( name_table
,
865 /* Initialize table for swapping index notdef_index and */
866 /* index 0 names and codes (if necessary). */
868 error
= psaux
->ps_table_funcs
->init( swap_table
, 4, memory
);
876 /* The format is simple: */
877 /* `/glyphname' + index [+ def] */
879 T1_Skip_Spaces( parser
);
881 cur
= parser
->root
.cursor
;
885 /* We stop when we find an `end' keyword or '>' */
890 t42_is_space( cur
[3] ) )
895 T1_Skip_PS_Token( parser
);
896 if ( parser
->root
.cursor
>= limit
)
898 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
899 error
= FT_THROW( Invalid_File_Format
);
902 if ( parser
->root
.error
)
910 if ( cur
+ 2 >= limit
)
912 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
913 error
= FT_THROW( Invalid_File_Format
);
917 cur
++; /* skip `/' */
918 len
= (FT_UInt
)( parser
->root
.cursor
- cur
);
920 error
= T1_Add_Table( name_table
, n
, cur
, len
+ 1 );
924 /* add a trailing zero to the name table */
925 name_table
->elements
[n
][len
] = '\0';
927 /* record index of /.notdef */
929 ft_strcmp( ".notdef",
930 (const char*)(name_table
->elements
[n
]) ) == 0 )
936 T1_Skip_Spaces( parser
);
938 cur
= parser
->root
.cursor
;
940 (void)T1_ToInt( parser
);
941 if ( parser
->root
.cursor
>= limit
)
943 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
944 error
= FT_THROW( Invalid_File_Format
);
948 len
= (FT_UInt
)( parser
->root
.cursor
- cur
);
950 error
= T1_Add_Table( code_table
, n
, cur
, len
+ 1 );
954 code_table
->elements
[n
][len
] = '\0';
957 if ( n
>= loader
->num_glyphs
)
962 loader
->num_glyphs
= n
;
966 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
967 error
= FT_THROW( Invalid_File_Format
);
971 /* if /.notdef does not occupy index 0, do our magic. */
972 if ( ft_strcmp( (const char*)".notdef",
973 (const char*)name_table
->elements
[0] ) )
975 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
976 /* name and code entries to swap_table. Then place notdef_index */
977 /* name and code entries into swap_table. Then swap name and code */
978 /* entries at indices notdef_index and 0 using values stored in */
982 error
= T1_Add_Table( swap_table
, 0,
983 name_table
->elements
[0],
984 name_table
->lengths
[0] );
989 error
= T1_Add_Table( swap_table
, 1,
990 code_table
->elements
[0],
991 code_table
->lengths
[0] );
995 /* Index notdef_index name */
996 error
= T1_Add_Table( swap_table
, 2,
997 name_table
->elements
[notdef_index
],
998 name_table
->lengths
[notdef_index
] );
1002 /* Index notdef_index code */
1003 error
= T1_Add_Table( swap_table
, 3,
1004 code_table
->elements
[notdef_index
],
1005 code_table
->lengths
[notdef_index
] );
1009 error
= T1_Add_Table( name_table
, notdef_index
,
1010 swap_table
->elements
[0],
1011 swap_table
->lengths
[0] );
1015 error
= T1_Add_Table( code_table
, notdef_index
,
1016 swap_table
->elements
[1],
1017 swap_table
->lengths
[1] );
1021 error
= T1_Add_Table( name_table
, 0,
1022 swap_table
->elements
[2],
1023 swap_table
->lengths
[2] );
1027 error
= T1_Add_Table( code_table
, 0,
1028 swap_table
->elements
[3],
1029 swap_table
->lengths
[3] );
1038 parser
->root
.error
= error
;
1043 t42_load_keyword( T42_Face face
,
1050 FT_UInt max_objects
= 0;
1053 /* if the keyword has a dedicated callback, call it */
1054 if ( field
->type
== T1_FIELD_TYPE_CALLBACK
)
1056 field
->reader( (FT_Face
)face
, loader
);
1057 error
= loader
->parser
.root
.error
;
1061 /* now the keyword is either a simple field or a table of fields; */
1062 /* we are now going to take care of it */
1064 switch ( field
->location
)
1066 case T1_FIELD_LOCATION_FONT_INFO
:
1067 dummy_object
= &face
->type1
.font_info
;
1070 case T1_FIELD_LOCATION_FONT_EXTRA
:
1071 dummy_object
= &face
->type1
.font_extra
;
1074 case T1_FIELD_LOCATION_BBOX
:
1075 dummy_object
= &face
->type1
.font_bbox
;
1079 dummy_object
= &face
->type1
;
1082 objects
= &dummy_object
;
1084 if ( field
->type
== T1_FIELD_TYPE_INTEGER_ARRAY
||
1085 field
->type
== T1_FIELD_TYPE_FIXED_ARRAY
)
1086 error
= T1_Load_Field_Table( &loader
->parser
, field
,
1087 objects
, max_objects
, 0 );
1089 error
= T1_Load_Field( &loader
->parser
, field
,
1090 objects
, max_objects
, 0 );
1097 FT_LOCAL_DEF( FT_Error
)
1098 t42_parse_dict( T42_Face face
,
1103 T42_Parser parser
= &loader
->parser
;
1105 FT_Int n_keywords
= (FT_Int
)( sizeof ( t42_keywords
) /
1106 sizeof ( t42_keywords
[0] ) );
1109 parser
->root
.cursor
= base
;
1110 parser
->root
.limit
= base
+ size
;
1111 parser
->root
.error
= FT_Err_Ok
;
1113 limit
= parser
->root
.limit
;
1115 T1_Skip_Spaces( parser
);
1117 while ( parser
->root
.cursor
< limit
)
1122 cur
= parser
->root
.cursor
;
1124 /* look for `FontDirectory' which causes problems for some fonts */
1125 if ( *cur
== 'F' && cur
+ 25 < limit
&&
1126 ft_strncmp( (char*)cur
, "FontDirectory", 13 ) == 0 )
1131 /* skip the `FontDirectory' keyword */
1132 T1_Skip_PS_Token( parser
);
1133 T1_Skip_Spaces ( parser
);
1134 cur
= cur2
= parser
->root
.cursor
;
1136 /* look up the `known' keyword */
1137 while ( cur
< limit
)
1139 if ( *cur
== 'k' && cur
+ 5 < limit
&&
1140 ft_strncmp( (char*)cur
, "known", 5 ) == 0 )
1143 T1_Skip_PS_Token( parser
);
1144 if ( parser
->root
.error
)
1146 T1_Skip_Spaces ( parser
);
1147 cur
= parser
->root
.cursor
;
1155 /* skip the `known' keyword and the token following it */
1156 T1_Skip_PS_Token( parser
);
1157 T1_ToToken( parser
, &token
);
1159 /* if the last token was an array, skip it! */
1160 if ( token
.type
== T1_TOKEN_TYPE_ARRAY
)
1161 cur2
= parser
->root
.cursor
;
1163 parser
->root
.cursor
= cur2
;
1166 /* look for immediates */
1167 else if ( *cur
== '/' && cur
+ 2 < limit
)
1174 parser
->root
.cursor
= cur
;
1175 T1_Skip_PS_Token( parser
);
1176 if ( parser
->root
.error
)
1179 len
= (FT_UInt
)( parser
->root
.cursor
- cur
);
1181 if ( len
> 0 && len
< 22 && parser
->root
.cursor
< limit
)
1186 /* now compare the immediate name to the keyword table */
1188 /* loop through all known keywords */
1189 for ( i
= 0; i
< n_keywords
; i
++ )
1191 T1_Field keyword
= (T1_Field
)&t42_keywords
[i
];
1192 FT_Byte
*name
= (FT_Byte
*)keyword
->ident
;
1198 if ( cur
[0] == name
[0] &&
1199 len
== ft_strlen( (const char *)name
) &&
1200 ft_memcmp( cur
, name
, len
) == 0 )
1202 /* we found it -- run the parsing callback! */
1203 parser
->root
.error
= t42_load_keyword( face
,
1206 if ( parser
->root
.error
)
1207 return parser
->root
.error
;
1215 T1_Skip_PS_Token( parser
);
1216 if ( parser
->root
.error
)
1220 T1_Skip_Spaces( parser
);
1224 return parser
->root
.error
;
1228 FT_LOCAL_DEF( void )
1229 t42_loader_init( T42_Loader loader
,
1234 FT_MEM_ZERO( loader
, sizeof ( *loader
) );
1235 loader
->num_glyphs
= 0;
1236 loader
->num_chars
= 0;
1238 /* initialize the tables -- simply set their `init' field to 0 */
1239 loader
->encoding_table
.init
= 0;
1240 loader
->charstrings
.init
= 0;
1241 loader
->glyph_names
.init
= 0;
1245 FT_LOCAL_DEF( void )
1246 t42_loader_done( T42_Loader loader
)
1248 T42_Parser parser
= &loader
->parser
;
1251 /* finalize tables */
1252 T1_Release_Table( &loader
->encoding_table
);
1253 T1_Release_Table( &loader
->charstrings
);
1254 T1_Release_Table( &loader
->glyph_names
);
1255 T1_Release_Table( &loader
->swap_table
);
1257 /* finalize parser */
1258 t42_parser_done( parser
);