Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / thirdparty / freetype-2.3.12 / src / type42 / t42parse.c
blob13bda64c83781708a882e0276ce19966ebac5166
1 /***************************************************************************/
2 /* */
3 /* t42parse.c */
4 /* */
5 /* Type 42 font parser (body). */
6 /* */
7 /* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
8 /* Roberto Alameda. */
9 /* */
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. */
15 /* */
16 /***************************************************************************/
19 #include "t42parse.h"
20 #include "t42error.h"
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_INTERNAL_STREAM_H
23 #include FT_INTERNAL_POSTSCRIPT_AUX_H
26 /*************************************************************************/
27 /* */
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. */
31 /* */
32 #undef FT_COMPONENT
33 #define FT_COMPONENT trace_t42
36 static void
37 t42_parse_font_matrix( T42_Face face,
38 T42_Loader loader );
39 static void
40 t42_parse_encoding( T42_Face face,
41 T42_Loader loader );
43 static void
44 t42_parse_charstrings( T42_Face face,
45 T42_Loader loader );
47 static void
48 t42_parse_sfnts( T42_Face face,
49 T42_Loader loader );
52 /* as Type42 fonts have no Private dict, */
53 /* we set the last argument of T1_FIELD_XXX to 0 */
54 static const
55 T1_FieldRec t42_keywords[] = {
57 #undef FT_STRUCTURE
58 #define FT_STRUCTURE T1_FontInfo
59 #undef T1CODE
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 )
72 #undef FT_STRUCTURE
73 #define FT_STRUCTURE PS_FontExtraRec
74 #undef T1CODE
75 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
77 T1_FIELD_NUM ( "FSType", fs_type, 0 )
79 #undef FT_STRUCTURE
80 #define FT_STRUCTURE T1_FontRec
81 #undef T1CODE
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 )
89 #undef FT_STRUCTURE
90 #define FT_STRUCTURE FT_BBox
91 #undef T1CODE
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 ) \
107 do \
109 if ( (p)->funcs.done ) \
110 (p)->funcs.done( p ); \
111 } while ( 0 )
112 #define T1_Release_Table( p ) \
113 do \
115 if ( (p)->funcs.release ) \
116 (p)->funcs.release( p ); \
117 } while ( 0 )
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,
142 FT_Stream stream,
143 FT_Memory memory,
144 PSAux_Service psaux )
146 FT_Error error = T42_Err_Ok;
147 FT_Long size;
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 /*******************************************************************/
158 /* */
159 /* Here a short summary of what is going on: */
160 /* */
161 /* When creating a new Type 42 parser, we try to locate and load */
162 /* the base dictionary, loading the whole font into memory. */
163 /* */
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. */
167 /* */
168 /* parser->in_memory is set if we have a memory stream. */
169 /* */
171 if ( FT_STREAM_SEEK( 0L ) ||
172 FT_FRAME_ENTER( 17 ) )
173 goto Exit;
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;
181 FT_FRAME_EXIT();
183 if ( error || FT_STREAM_SEEK( 0 ) )
184 goto Exit;
186 size = stream->size;
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 */
192 if ( !stream->read )
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 ) )
200 goto Exit;
202 else
204 /* read segment in memory */
205 if ( FT_ALLOC( parser->base_dict, size ) ||
206 FT_STREAM_READ( parser->base_dict, size ) )
207 goto Exit;
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;
216 Exit:
217 if ( error && !parser->in_memory )
218 FT_FREE( parser->base_dict );
220 return error;
224 FT_LOCAL_DEF( void )
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 );
238 static int
239 t42_is_space( FT_Byte c )
241 return ( c == ' ' || c == '\t' ||
242 c == '\r' || c == '\n' || c == '\f' ||
243 c == '\0' );
247 static void
248 t42_parse_font_matrix( T42_Face face,
249 T42_Loader loader )
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;
255 FT_Fixed temp[6];
256 FT_Fixed temp_scale;
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 );
277 temp[3] = 0x10000L;
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;
291 static void
292 t42_parse_encoding( T42_Face face,
293 T42_Loader loader )
295 T42_Parser parser = &loader->parser;
296 FT_Byte* cur;
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;
304 if ( cur >= limit )
306 FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
307 parser->root.error = T42_Err_Invalid_File_Format;
308 return;
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;
316 FT_UInt count, n;
317 PS_Table char_table = &loader->encoding_table;
318 FT_Memory memory = parser->root.memory;
319 FT_Error error;
320 FT_Bool only_immediates = 0;
323 /* read the number of entries in the encoding; should be 256 */
324 if ( *cur == '[' )
326 count = 256;
327 only_immediates = 1;
328 parser->root.cursor++;
330 else
331 count = (FT_UInt)T1_ToInt( parser );
333 T1_Skip_Spaces( parser );
334 if ( parser->root.cursor >= limit )
335 return;
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;
345 return;
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 */
358 /* */
359 /* ... charcode /charname ... */
360 /* */
361 /* for each entry in our table. */
362 /* */
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: */
366 /* */
367 /* 0 1 255 { 1 index exch /.notdef put } for dup */
368 /* */
369 /* used to clean the encoding array before anything else. */
370 /* */
371 /* Alternatively, if the array is directly given as */
372 /* */
373 /* /Encoding [ ... ] */
374 /* */
375 /* we only read immediates. */
377 n = 0;
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' &&
388 cur[2] == 'f' &&
389 t42_is_space( cur[3] ) )
391 FT_TRACE6(( "encoding end\n" ));
392 cur += 3;
393 break;
396 if ( *cur == ']' )
398 FT_TRACE6(( "encoding end\n" ));
399 cur++;
400 break;
403 /* check whether we have found an entry */
404 if ( ft_isdigit( *cur ) || only_immediates )
406 FT_Int charcode;
409 if ( only_immediates )
410 charcode = n;
411 else
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 )
421 FT_PtrDist len;
424 cur++;
426 parser->root.cursor = cur;
427 T1_Skip_PS_Token( parser );
428 if ( parser->root.error )
429 return;
431 len = parser->root.cursor - cur;
433 parser->root.error = T1_Add_Table( char_table, charcode,
434 cur, len + 1 );
435 if ( parser->root.error )
436 return;
437 char_table->elements[charcode][len] = '\0';
439 n++;
442 else
444 T1_Skip_PS_Token( parser );
445 if ( parser->root.error )
446 return;
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' */
458 else
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;
472 else
474 FT_ERROR(( "t42_parse_encoding: invalid token\n" ));
475 parser->root.error = T42_Err_Invalid_File_Format;
481 typedef enum T42_Load_Status_
483 BEFORE_START,
484 BEFORE_TABLE_DIR,
485 OTHER_TABLES
487 } T42_Load_Status;
490 static void
491 t42_parse_sfnts( T42_Face face,
492 T42_Loader loader )
494 T42_Parser parser = &loader->parser;
495 FT_Memory memory = parser->root.memory;
496 FT_Byte* cur;
497 FT_Byte* limit = parser->root.limit;
498 FT_Error error;
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;
509 /* The format is */
510 /* */
511 /* /sfnts [ <hexstring> <hexstring> ... ] def */
512 /* */
513 /* or */
514 /* */
515 /* /sfnts [ */
516 /* <num_bin_bytes> RD <binary data> */
517 /* <num_bin_bytes> RD <binary data> */
518 /* ... */
519 /* ] def */
520 /* */
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;
529 goto Fail;
532 T1_Skip_Spaces( parser );
533 status = BEFORE_START;
534 string_size = 0;
535 old_string_size = 0;
536 count = 0;
538 while ( parser->root.cursor < limit )
540 cur = parser->root.cursor;
542 if ( *cur == ']' )
544 parser->root.cursor++;
545 goto Exit;
548 else if ( *cur == '<' )
550 T1_Skip_PS_Token( parser );
551 if ( parser->root.error )
552 goto Exit;
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 ) )
557 goto Fail;
559 allocated = 1;
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 ) )
569 if ( allocated )
571 FT_ERROR(( "t42_parse_sfnts: "
572 "can't handle mixed binary and hex strings\n" ));
573 error = T42_Err_Invalid_File_Format;
574 goto Fail;
577 string_size = T1_ToInt( parser );
579 T1_Skip_PS_Token( parser ); /* `RD' */
580 if ( parser->root.error )
581 return;
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;
590 goto Fail;
594 if ( !string_buf )
596 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
597 error = T42_Err_Invalid_File_Format;
598 goto Fail;
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 ) )
603 string_size--;
605 if ( !string_size )
607 FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
608 error = T42_Err_Invalid_File_Format;
609 goto Fail;
612 for ( n = 0; n < string_size; n++ )
614 switch ( status )
616 case BEFORE_START:
617 /* load offset table, 12 bytes */
618 if ( count < 12 )
620 face->ttf_data[count++] = string_buf[n];
621 continue;
623 else
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 ) )
630 goto Fail;
632 /* fall through */
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];
639 continue;
641 else
643 int i;
644 FT_ULong len;
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,
663 ttf_size + 1 ) )
664 goto Fail;
666 /* fall through */
668 case OTHER_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;
674 goto Fail;
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;
686 Fail:
687 parser->root.error = error;
689 Exit:
690 if ( allocated )
691 FT_FREE( string_buf );
695 static void
696 t42_parse_charstrings( T42_Face face,
697 T42_Loader loader )
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;
704 FT_Error error;
706 PSAux_Service psaux = (PSAux_Service)face->psaux;
708 FT_Byte* cur;
709 FT_Byte* limit = parser->root.limit;
710 FT_UInt n;
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;
721 goto Fail;
724 if ( ft_isdigit( *parser->root.cursor ) )
726 loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
727 if ( parser->root.error )
728 return;
730 else if ( *parser->root.cursor == '<' )
732 /* We have `<< ... >>'. Count the number of `/' in the dictionary */
733 /* to get its size. */
734 FT_UInt count = 0;
737 T1_Skip_PS_Token( parser );
738 if ( parser->root.error )
739 return;
740 T1_Skip_Spaces( parser );
741 cur = parser->root.cursor;
743 while ( parser->root.cursor < limit )
745 if ( *parser->root.cursor == '/' )
746 count++;
747 else if ( *parser->root.cursor == '>' )
749 loader->num_glyphs = count;
750 parser->root.cursor = cur; /* rewind */
751 break;
753 T1_Skip_PS_Token( parser );
754 if ( parser->root.error )
755 return;
756 T1_Skip_Spaces( parser );
759 else
761 FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
762 error = T42_Err_Invalid_File_Format;
763 goto Fail;
766 if ( parser->root.cursor >= limit )
768 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
769 error = T42_Err_Invalid_File_Format;
770 goto Fail;
773 /* initialize tables */
775 error = psaux->ps_table_funcs->init( code_table,
776 loader->num_glyphs,
777 memory );
778 if ( error )
779 goto Fail;
781 error = psaux->ps_table_funcs->init( name_table,
782 loader->num_glyphs,
783 memory );
784 if ( error )
785 goto Fail;
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 );
791 if ( error )
792 goto Fail;
794 n = 0;
796 for (;;)
798 /* The format is simple: */
799 /* `/glyphname' + index [+ def] */
801 T1_Skip_Spaces( parser );
803 cur = parser->root.cursor;
804 if ( cur >= limit )
805 break;
807 /* We stop when we find an `end' keyword or '>' */
808 if ( *cur == 'e' &&
809 cur + 3 < limit &&
810 cur[1] == 'n' &&
811 cur[2] == 'd' &&
812 t42_is_space( cur[3] ) )
813 break;
814 if ( *cur == '>' )
815 break;
817 T1_Skip_PS_Token( parser );
818 if ( parser->root.error )
819 return;
821 if ( *cur == '/' )
823 FT_PtrDist len;
826 if ( cur + 1 >= limit )
828 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
829 error = T42_Err_Invalid_File_Format;
830 goto Fail;
833 cur++; /* skip `/' */
834 len = parser->root.cursor - cur;
836 error = T1_Add_Table( name_table, n, cur, len + 1 );
837 if ( error )
838 goto Fail;
840 /* add a trailing zero to the name table */
841 name_table->elements[n][len] = '\0';
843 /* record index of /.notdef */
844 if ( *cur == '.' &&
845 ft_strcmp( ".notdef",
846 (const char*)(name_table->elements[n]) ) == 0 )
848 notdef_index = n;
849 notdef_found = 1;
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;
861 goto Fail;
864 len = parser->root.cursor - cur;
866 error = T1_Add_Table( code_table, n, cur, len + 1 );
867 if ( error )
868 goto Fail;
870 code_table->elements[n][len] = '\0';
872 n++;
873 if ( n >= loader->num_glyphs )
874 break;
878 loader->num_glyphs = n;
880 if ( !notdef_found )
882 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
883 error = T42_Err_Invalid_File_Format;
884 goto Fail;
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 */
895 /* swap_table. */
897 /* Index 0 name */
898 error = T1_Add_Table( swap_table, 0,
899 name_table->elements[0],
900 name_table->lengths [0] );
901 if ( error )
902 goto Fail;
904 /* Index 0 code */
905 error = T1_Add_Table( swap_table, 1,
906 code_table->elements[0],
907 code_table->lengths [0] );
908 if ( error )
909 goto Fail;
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] );
915 if ( error )
916 goto Fail;
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] );
922 if ( error )
923 goto Fail;
925 error = T1_Add_Table( name_table, notdef_index,
926 swap_table->elements[0],
927 swap_table->lengths [0] );
928 if ( error )
929 goto Fail;
931 error = T1_Add_Table( code_table, notdef_index,
932 swap_table->elements[1],
933 swap_table->lengths [1] );
934 if ( error )
935 goto Fail;
937 error = T1_Add_Table( name_table, 0,
938 swap_table->elements[2],
939 swap_table->lengths [2] );
940 if ( error )
941 goto Fail;
943 error = T1_Add_Table( code_table, 0,
944 swap_table->elements[3],
945 swap_table->lengths [3] );
946 if ( error )
947 goto Fail;
951 return;
953 Fail:
954 parser->root.error = error;
958 static FT_Error
959 t42_load_keyword( T42_Face face,
960 T42_Loader loader,
961 T1_Field field )
963 FT_Error error;
964 void* dummy_object;
965 void** objects;
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;
974 goto Exit;
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;
984 break;
986 case T1_FIELD_LOCATION_FONT_EXTRA:
987 dummy_object = &face->type1.font_extra;
988 break;
990 case T1_FIELD_LOCATION_BBOX:
991 dummy_object = &face->type1.font_bbox;
992 break;
994 default:
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 );
1004 else
1005 error = T1_Load_Field( &loader->parser, field,
1006 objects, max_objects, 0 );
1008 Exit:
1009 return error;
1013 FT_LOCAL_DEF( FT_Error )
1014 t42_parse_dict( T42_Face face,
1015 T42_Loader loader,
1016 FT_Byte* base,
1017 FT_Long size )
1019 T42_Parser parser = &loader->parser;
1020 FT_Byte* limit;
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 )
1035 FT_Byte* cur;
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 )
1044 FT_Byte* cur2;
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 )
1057 break;
1059 T1_Skip_PS_Token( parser );
1060 if ( parser->root.error )
1061 goto Exit;
1062 T1_Skip_Spaces ( parser );
1063 cur = parser->root.cursor;
1066 if ( cur < limit )
1068 T1_TokenRec token;
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 )
1085 FT_PtrDist len;
1088 cur++;
1090 parser->root.cursor = cur;
1091 T1_Skip_PS_Token( parser );
1092 if ( parser->root.error )
1093 goto Exit;
1095 len = parser->root.cursor - cur;
1097 if ( len > 0 && len < 22 && parser->root.cursor < limit )
1099 int i;
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;
1111 if ( !name )
1112 continue;
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,
1120 loader,
1121 keyword );
1122 if ( parser->root.error )
1123 return parser->root.error;
1124 break;
1129 else
1131 T1_Skip_PS_Token( parser );
1132 if ( parser->root.error )
1133 goto Exit;
1136 T1_Skip_Spaces( parser );
1139 Exit:
1140 return parser->root.error;
1144 FT_LOCAL_DEF( void )
1145 t42_loader_init( T42_Loader loader,
1146 T42_Face face )
1148 FT_UNUSED( face );
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 );
1178 /* END */