[FREETYPE] Update to v2.6.1. CORE-10378
[reactos.git] / reactos / lib / 3rdparty / freetype / src / type42 / t42parse.c
1 /***************************************************************************/
2 /* */
3 /* t42parse.c */
4 /* */
5 /* Type 42 font parser (body). */
6 /* */
7 /* Copyright 2002-2015 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 /***************************************************************************/
17
18
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
24
25
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
34
35
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 );
42
43 static void
44 t42_parse_charstrings( T42_Face face,
45 T42_Loader loader );
46
47 static void
48 t42_parse_sfnts( T42_Face face,
49 T42_Loader loader );
50
51
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[] =
56 {
57
58 #undef FT_STRUCTURE
59 #define FT_STRUCTURE T1_FontInfo
60 #undef T1CODE
61 #define T1CODE T1_FIELD_LOCATION_FONT_INFO
62
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 )
72
73 #undef FT_STRUCTURE
74 #define FT_STRUCTURE PS_FontExtraRec
75 #undef T1CODE
76 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
77
78 T1_FIELD_NUM ( "FSType", fs_type, 0 )
79
80 #undef FT_STRUCTURE
81 #define FT_STRUCTURE T1_FontRec
82 #undef T1CODE
83 #define T1CODE T1_FIELD_LOCATION_FONT_DICT
84
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 )
89
90 #undef FT_STRUCTURE
91 #define FT_STRUCTURE FT_BBox
92 #undef T1CODE
93 #define T1CODE T1_FIELD_LOCATION_BBOX
94
95 T1_FIELD_BBOX("FontBBox", xMin, 0 )
96
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 )
101
102 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
103 };
104
105
106 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
107 #define T1_Release_Table( p ) \
108 do \
109 { \
110 if ( (p)->funcs.release ) \
111 (p)->funcs.release( p ); \
112 } while ( 0 )
113
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 )
116
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 )
121
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 )
126
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 )
131
132
133 /********************* Parsing Functions ******************/
134
135 FT_LOCAL_DEF( FT_Error )
136 t42_parser_init( T42_Parser parser,
137 FT_Stream stream,
138 FT_Memory memory,
139 PSAux_Service psaux )
140 {
141 FT_Error error = FT_Err_Ok;
142 FT_Long size;
143
144
145 psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory );
146
147 parser->stream = stream;
148 parser->base_len = 0;
149 parser->base_dict = NULL;
150 parser->in_memory = 0;
151
152 /*******************************************************************/
153 /* */
154 /* Here a short summary of what is going on: */
155 /* */
156 /* When creating a new Type 42 parser, we try to locate and load */
157 /* the base dictionary, loading the whole font into memory. */
158 /* */
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. */
162 /* */
163 /* parser->in_memory is set if we have a memory stream. */
164 /* */
165
166 if ( FT_STREAM_SEEK( 0L ) ||
167 FT_FRAME_ENTER( 17 ) )
168 goto Exit;
169
170 if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 )
171 {
172 FT_TRACE2(( " not a Type42 font\n" ));
173 error = FT_THROW( Unknown_File_Format );
174 }
175
176 FT_FRAME_EXIT();
177
178 if ( error || FT_STREAM_SEEK( 0 ) )
179 goto Exit;
180
181 size = (FT_Long)stream->size;
182
183 /* now, try to load `size' bytes of the `base' dictionary we */
184 /* found previously */
185
186 /* if it is a memory-based resource, set up pointers */
187 if ( !stream->read )
188 {
189 parser->base_dict = (FT_Byte*)stream->base + stream->pos;
190 parser->base_len = size;
191 parser->in_memory = 1;
192
193 /* check that the `size' field is valid */
194 if ( FT_STREAM_SKIP( size ) )
195 goto Exit;
196 }
197 else
198 {
199 /* read segment in memory */
200 if ( FT_ALLOC( parser->base_dict, size ) ||
201 FT_STREAM_READ( parser->base_dict, size ) )
202 goto Exit;
203
204 parser->base_len = size;
205 }
206
207 parser->root.base = parser->base_dict;
208 parser->root.cursor = parser->base_dict;
209 parser->root.limit = parser->root.cursor + parser->base_len;
210
211 Exit:
212 if ( error && !parser->in_memory )
213 FT_FREE( parser->base_dict );
214
215 return error;
216 }
217
218
219 FT_LOCAL_DEF( void )
220 t42_parser_done( T42_Parser parser )
221 {
222 FT_Memory memory = parser->root.memory;
223
224
225 /* free the base dictionary only when we have a disk stream */
226 if ( !parser->in_memory )
227 FT_FREE( parser->base_dict );
228
229 parser->root.funcs.done( &parser->root );
230 }
231
232
233 static int
234 t42_is_space( FT_Byte c )
235 {
236 return ( c == ' ' || c == '\t' ||
237 c == '\r' || c == '\n' || c == '\f' ||
238 c == '\0' );
239 }
240
241
242 static void
243 t42_parse_font_matrix( T42_Face face,
244 T42_Loader loader )
245 {
246 T42_Parser parser = &loader->parser;
247 FT_Matrix* matrix = &face->type1.font_matrix;
248 FT_Vector* offset = &face->type1.font_offset;
249 FT_Fixed temp[6];
250 FT_Fixed temp_scale;
251 FT_Int result;
252
253
254 result = T1_ToFixedArray( parser, 6, temp, 0 );
255
256 if ( result < 6 )
257 {
258 parser->root.error = FT_THROW( Invalid_File_Format );
259 return;
260 }
261
262 temp_scale = FT_ABS( temp[3] );
263
264 if ( temp_scale == 0 )
265 {
266 FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
267 parser->root.error = FT_THROW( Invalid_File_Format );
268 return;
269 }
270
271 /* atypical case */
272 if ( temp_scale != 0x10000L )
273 {
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;
280 }
281
282 matrix->xx = temp[0];
283 matrix->yx = temp[1];
284 matrix->xy = temp[2];
285 matrix->yy = temp[3];
286
287 /* note that the offsets must be expressed in integer font units */
288 offset->x = temp[4] >> 16;
289 offset->y = temp[5] >> 16;
290 }
291
292
293 static void
294 t42_parse_encoding( T42_Face face,
295 T42_Loader loader )
296 {
297 T42_Parser parser = &loader->parser;
298 FT_Byte* cur;
299 FT_Byte* limit = parser->root.limit;
300
301 PSAux_Service psaux = (PSAux_Service)face->psaux;
302
303
304 T1_Skip_Spaces( parser );
305 cur = parser->root.cursor;
306 if ( cur >= limit )
307 {
308 FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
309 parser->root.error = FT_THROW( Invalid_File_Format );
310 return;
311 }
312
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 == '[' )
316 {
317 T1_Encoding encode = &face->type1.encoding;
318 FT_Int count, n;
319 PS_Table char_table = &loader->encoding_table;
320 FT_Memory memory = parser->root.memory;
321 FT_Error error;
322 FT_Bool only_immediates = 0;
323
324
325 /* read the number of entries in the encoding; should be 256 */
326 if ( *cur == '[' )
327 {
328 count = 256;
329 only_immediates = 1;
330 parser->root.cursor++;
331 }
332 else
333 count = (FT_Int)T1_ToInt( parser );
334
335 /* only composite fonts (which we don't support) */
336 /* can have larger values */
337 if ( count > 256 )
338 {
339 FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" ));
340 parser->root.error = FT_THROW( Invalid_File_Format );
341 return;
342 }
343
344 T1_Skip_Spaces( parser );
345 if ( parser->root.cursor >= limit )
346 return;
347
348 /* PostScript happily allows overwriting of encoding arrays */
349 if ( encode->char_index )
350 {
351 FT_FREE( encode->char_index );
352 FT_FREE( encode->char_name );
353 T1_Release_Table( char_table );
354 }
355
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 ) ) )
362 {
363 parser->root.error = error;
364 return;
365 }
366
367 /* We need to `zero' out encoding_table.elements */
368 for ( n = 0; n < count; n++ )
369 {
370 char* notdef = (char *)".notdef";
371
372
373 (void)T1_Add_Table( char_table, n, notdef, 8 );
374 }
375
376 /* Now we need to read records of the form */
377 /* */
378 /* ... charcode /charname ... */
379 /* */
380 /* for each entry in our table. */
381 /* */
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: */
385 /* */
386 /* 0 1 255 { 1 index exch /.notdef put } for dup */
387 /* */
388 /* used to clean the encoding array before anything else. */
389 /* */
390 /* Alternatively, if the array is directly given as */
391 /* */
392 /* /Encoding [ ... ] */
393 /* */
394 /* we only read immediates. */
395
396 n = 0;
397 T1_Skip_Spaces( parser );
398
399 while ( parser->root.cursor < limit )
400 {
401 cur = parser->root.cursor;
402
403 /* we stop when we encounter `def' or `]' */
404 if ( *cur == 'd' && cur + 3 < limit )
405 {
406 if ( cur[1] == 'e' &&
407 cur[2] == 'f' &&
408 t42_is_space( cur[3] ) )
409 {
410 FT_TRACE6(( "encoding end\n" ));
411 cur += 3;
412 break;
413 }
414 }
415 if ( *cur == ']' )
416 {
417 FT_TRACE6(( "encoding end\n" ));
418 cur++;
419 break;
420 }
421
422 /* check whether we have found an entry */
423 if ( ft_isdigit( *cur ) || only_immediates )
424 {
425 FT_Int charcode;
426
427
428 if ( only_immediates )
429 charcode = n;
430 else
431 {
432 charcode = (FT_Int)T1_ToInt( parser );
433 T1_Skip_Spaces( parser );
434
435 /* protect against invalid charcode */
436 if ( cur == parser->root.cursor )
437 {
438 parser->root.error = FT_THROW( Unknown_File_Format );
439 return;
440 }
441 }
442
443 cur = parser->root.cursor;
444
445 if ( cur + 2 < limit && *cur == '/' && n < count )
446 {
447 FT_UInt len;
448
449
450 cur++;
451
452 parser->root.cursor = cur;
453 T1_Skip_PS_Token( parser );
454 if ( parser->root.cursor >= limit )
455 return;
456 if ( parser->root.error )
457 return;
458
459 len = (FT_UInt)( parser->root.cursor - cur );
460
461 parser->root.error = T1_Add_Table( char_table, charcode,
462 cur, len + 1 );
463 if ( parser->root.error )
464 return;
465 char_table->elements[charcode][len] = '\0';
466
467 n++;
468 }
469 else if ( only_immediates )
470 {
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. */
474 /* */
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 );
480 return;
481 }
482 }
483 else
484 {
485 T1_Skip_PS_Token( parser );
486 if ( parser->root.error )
487 return;
488 }
489
490 T1_Skip_Spaces( parser );
491 }
492
493 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
494 parser->root.cursor = cur;
495 }
496
497 /* Otherwise, we should have either `StandardEncoding', */
498 /* `ExpertEncoding', or `ISOLatin1Encoding' */
499 else
500 {
501 if ( cur + 17 < limit &&
502 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
503 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
504
505 else if ( cur + 15 < limit &&
506 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
507 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
508
509 else if ( cur + 18 < limit &&
510 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
511 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
512
513 else
514 parser->root.error = FT_ERR( Ignore );
515 }
516 }
517
518
519 typedef enum T42_Load_Status_
520 {
521 BEFORE_START,
522 BEFORE_TABLE_DIR,
523 OTHER_TABLES
524
525 } T42_Load_Status;
526
527
528 static void
529 t42_parse_sfnts( T42_Face face,
530 T42_Loader loader )
531 {
532 T42_Parser parser = &loader->parser;
533 FT_Memory memory = parser->root.memory;
534 FT_Byte* cur;
535 FT_Byte* limit = parser->root.limit;
536 FT_Error error;
537 FT_Int num_tables = 0;
538 FT_Long count;
539
540 FT_ULong n, string_size, old_string_size, real_size;
541 FT_Byte* string_buf = NULL;
542 FT_Bool allocated = 0;
543
544 T42_Load_Status status;
545
546
547 /* The format is */
548 /* */
549 /* /sfnts [ <hexstring> <hexstring> ... ] def */
550 /* */
551 /* or */
552 /* */
553 /* /sfnts [ */
554 /* <num_bin_bytes> RD <binary data> */
555 /* <num_bin_bytes> RD <binary data> */
556 /* ... */
557 /* ] def */
558 /* */
559 /* with exactly one space after the `RD' token. */
560
561 T1_Skip_Spaces( parser );
562
563 if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
564 {
565 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
566 error = FT_THROW( Invalid_File_Format );
567 goto Fail;
568 }
569
570 T1_Skip_Spaces( parser );
571 status = BEFORE_START;
572 string_size = 0;
573 old_string_size = 0;
574 count = 0;
575
576 while ( parser->root.cursor < limit )
577 {
578 cur = parser->root.cursor;
579
580 if ( *cur == ']' )
581 {
582 parser->root.cursor++;
583 goto Exit;
584 }
585
586 else if ( *cur == '<' )
587 {
588 T1_Skip_PS_Token( parser );
589 if ( parser->root.error )
590 goto Exit;
591
592 /* don't include delimiters */
593 string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
594 if ( !string_size )
595 {
596 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
597 error = FT_THROW( Invalid_File_Format );
598 goto Fail;
599 }
600 if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
601 goto Fail;
602
603 allocated = 1;
604
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;
609 }
610
611 else if ( ft_isdigit( *cur ) )
612 {
613 FT_Long tmp;
614
615
616 if ( allocated )
617 {
618 FT_ERROR(( "t42_parse_sfnts: "
619 "can't handle mixed binary and hex strings\n" ));
620 error = FT_THROW( Invalid_File_Format );
621 goto Fail;
622 }
623
624 tmp = T1_ToInt( parser );
625 if ( tmp < 0 )
626 {
627 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
628 error = FT_THROW( Invalid_File_Format );
629 goto Fail;
630 }
631 else
632 string_size = (FT_ULong)tmp;
633
634 T1_Skip_PS_Token( parser ); /* `RD' */
635 if ( parser->root.error )
636 return;
637
638 string_buf = parser->root.cursor + 1; /* one space after `RD' */
639
640 if ( (FT_ULong)( limit - parser->root.cursor ) < string_size )
641 {
642 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
643 error = FT_THROW( Invalid_File_Format );
644 goto Fail;
645 }
646 else
647 parser->root.cursor += string_size + 1;
648 }
649
650 if ( !string_buf )
651 {
652 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
653 error = FT_THROW( Invalid_File_Format );
654 goto Fail;
655 }
656
657 /* A string can have a trailing zero (odd) byte for padding. */
658 /* Ignore it. */
659 if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
660 string_size--;
661
662 if ( !string_size )
663 {
664 FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
665 error = FT_THROW( Invalid_File_Format );
666 goto Fail;
667 }
668
669 for ( n = 0; n < string_size; n++ )
670 {
671 switch ( status )
672 {
673 case BEFORE_START:
674 /* load offset table, 12 bytes */
675 if ( count < 12 )
676 {
677 face->ttf_data[count++] = string_buf[n];
678 continue;
679 }
680 else
681 {
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;
685
686 if ( (FT_Long)( limit - parser->root.cursor ) < face->ttf_size )
687 {
688 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
689 error = FT_THROW( Invalid_File_Format );
690 goto Fail;
691 }
692
693 if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) )
694 goto Fail;
695 }
696 /* fall through */
697
698 case BEFORE_TABLE_DIR:
699 /* the offset table is read; read the table directory */
700 if ( count < face->ttf_size )
701 {
702 face->ttf_data[count++] = string_buf[n];
703 continue;
704 }
705 else
706 {
707 int i;
708 FT_ULong len;
709
710
711 for ( i = 0; i < num_tables; i++ )
712 {
713 FT_Byte* p = face->ttf_data + 12 + 16 * i + 12;
714
715
716 len = FT_PEEK_ULONG( p );
717
718 /* Pad to a 4-byte boundary length */
719 face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U );
720 }
721
722 status = OTHER_TABLES;
723
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 ) )
727 goto Fail;
728 }
729 /* fall through */
730
731 case OTHER_TABLES:
732 /* all other tables are just copied */
733 if ( count >= face->ttf_size )
734 {
735 FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
736 error = FT_THROW( Invalid_File_Format );
737 goto Fail;
738 }
739 face->ttf_data[count++] = string_buf[n];
740 }
741 }
742
743 T1_Skip_Spaces( parser );
744 }
745
746 /* if control reaches this point, the format was not valid */
747 error = FT_THROW( Invalid_File_Format );
748
749 Fail:
750 parser->root.error = error;
751
752 Exit:
753 if ( allocated )
754 FT_FREE( string_buf );
755 }
756
757
758 static void
759 t42_parse_charstrings( T42_Face face,
760 T42_Loader loader )
761 {
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;
767 FT_Error error;
768
769 PSAux_Service psaux = (PSAux_Service)face->psaux;
770
771 FT_Byte* cur;
772 FT_Byte* limit = parser->root.limit;
773 FT_Int n;
774 FT_Int notdef_index = 0;
775 FT_Byte notdef_found = 0;
776
777
778 T1_Skip_Spaces( parser );
779
780 if ( parser->root.cursor >= limit )
781 {
782 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
783 error = FT_THROW( Invalid_File_Format );
784 goto Fail;
785 }
786
787 if ( ft_isdigit( *parser->root.cursor ) )
788 {
789 loader->num_glyphs = T1_ToInt( parser );
790 if ( parser->root.error )
791 return;
792 if ( loader->num_glyphs < 0 )
793 {
794 FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" ));
795 error = FT_THROW( Invalid_File_Format );
796 goto Fail;
797 }
798 }
799 else if ( *parser->root.cursor == '<' )
800 {
801 /* We have `<< ... >>'. Count the number of `/' in the dictionary */
802 /* to get its size. */
803 FT_Int count = 0;
804
805
806 T1_Skip_PS_Token( parser );
807 if ( parser->root.error )
808 return;
809 T1_Skip_Spaces( parser );
810 cur = parser->root.cursor;
811
812 while ( parser->root.cursor < limit )
813 {
814 if ( *parser->root.cursor == '/' )
815 count++;
816 else if ( *parser->root.cursor == '>' )
817 {
818 loader->num_glyphs = count;
819 parser->root.cursor = cur; /* rewind */
820 break;
821 }
822 T1_Skip_PS_Token( parser );
823 if ( parser->root.error )
824 return;
825 T1_Skip_Spaces( parser );
826 }
827 }
828 else
829 {
830 FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
831 error = FT_THROW( Invalid_File_Format );
832 goto Fail;
833 }
834
835 if ( parser->root.cursor >= limit )
836 {
837 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
838 error = FT_THROW( Invalid_File_Format );
839 goto Fail;
840 }
841
842 /* initialize tables */
843
844 /* contrary to Type1, we disallow multiple CharStrings arrays */
845 if ( swap_table->init )
846 {
847 FT_ERROR(( "t42_parse_charstrings:"
848 " only one CharStrings array allowed\n" ));
849 error = FT_THROW( Invalid_File_Format );
850 goto Fail;
851 }
852
853 error = psaux->ps_table_funcs->init( code_table,
854 loader->num_glyphs,
855 memory );
856 if ( error )
857 goto Fail;
858
859 error = psaux->ps_table_funcs->init( name_table,
860 loader->num_glyphs,
861 memory );
862 if ( error )
863 goto Fail;
864
865 /* Initialize table for swapping index notdef_index and */
866 /* index 0 names and codes (if necessary). */
867
868 error = psaux->ps_table_funcs->init( swap_table, 4, memory );
869 if ( error )
870 goto Fail;
871
872 n = 0;
873
874 for (;;)
875 {
876 /* The format is simple: */
877 /* `/glyphname' + index [+ def] */
878
879 T1_Skip_Spaces( parser );
880
881 cur = parser->root.cursor;
882 if ( cur >= limit )
883 break;
884
885 /* We stop when we find an `end' keyword or '>' */
886 if ( *cur == 'e' &&
887 cur + 3 < limit &&
888 cur[1] == 'n' &&
889 cur[2] == 'd' &&
890 t42_is_space( cur[3] ) )
891 break;
892 if ( *cur == '>' )
893 break;
894
895 T1_Skip_PS_Token( parser );
896 if ( parser->root.cursor >= limit )
897 {
898 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
899 error = FT_THROW( Invalid_File_Format );
900 goto Fail;
901 }
902 if ( parser->root.error )
903 return;
904
905 if ( *cur == '/' )
906 {
907 FT_UInt len;
908
909
910 if ( cur + 2 >= limit )
911 {
912 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
913 error = FT_THROW( Invalid_File_Format );
914 goto Fail;
915 }
916
917 cur++; /* skip `/' */
918 len = (FT_UInt)( parser->root.cursor - cur );
919
920 error = T1_Add_Table( name_table, n, cur, len + 1 );
921 if ( error )
922 goto Fail;
923
924 /* add a trailing zero to the name table */
925 name_table->elements[n][len] = '\0';
926
927 /* record index of /.notdef */
928 if ( *cur == '.' &&
929 ft_strcmp( ".notdef",
930 (const char*)(name_table->elements[n]) ) == 0 )
931 {
932 notdef_index = n;
933 notdef_found = 1;
934 }
935
936 T1_Skip_Spaces( parser );
937
938 cur = parser->root.cursor;
939
940 (void)T1_ToInt( parser );
941 if ( parser->root.cursor >= limit )
942 {
943 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
944 error = FT_THROW( Invalid_File_Format );
945 goto Fail;
946 }
947
948 len = (FT_UInt)( parser->root.cursor - cur );
949
950 error = T1_Add_Table( code_table, n, cur, len + 1 );
951 if ( error )
952 goto Fail;
953
954 code_table->elements[n][len] = '\0';
955
956 n++;
957 if ( n >= loader->num_glyphs )
958 break;
959 }
960 }
961
962 loader->num_glyphs = n;
963
964 if ( !notdef_found )
965 {
966 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
967 error = FT_THROW( Invalid_File_Format );
968 goto Fail;
969 }
970
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] ) )
974 {
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 */
979 /* swap_table. */
980
981 /* Index 0 name */
982 error = T1_Add_Table( swap_table, 0,
983 name_table->elements[0],
984 name_table->lengths [0] );
985 if ( error )
986 goto Fail;
987
988 /* Index 0 code */
989 error = T1_Add_Table( swap_table, 1,
990 code_table->elements[0],
991 code_table->lengths [0] );
992 if ( error )
993 goto Fail;
994
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] );
999 if ( error )
1000 goto Fail;
1001
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] );
1006 if ( error )
1007 goto Fail;
1008
1009 error = T1_Add_Table( name_table, notdef_index,
1010 swap_table->elements[0],
1011 swap_table->lengths [0] );
1012 if ( error )
1013 goto Fail;
1014
1015 error = T1_Add_Table( code_table, notdef_index,
1016 swap_table->elements[1],
1017 swap_table->lengths [1] );
1018 if ( error )
1019 goto Fail;
1020
1021 error = T1_Add_Table( name_table, 0,
1022 swap_table->elements[2],
1023 swap_table->lengths [2] );
1024 if ( error )
1025 goto Fail;
1026
1027 error = T1_Add_Table( code_table, 0,
1028 swap_table->elements[3],
1029 swap_table->lengths [3] );
1030 if ( error )
1031 goto Fail;
1032
1033 }
1034
1035 return;
1036
1037 Fail:
1038 parser->root.error = error;
1039 }
1040
1041
1042 static FT_Error
1043 t42_load_keyword( T42_Face face,
1044 T42_Loader loader,
1045 T1_Field field )
1046 {
1047 FT_Error error;
1048 void* dummy_object;
1049 void** objects;
1050 FT_UInt max_objects = 0;
1051
1052
1053 /* if the keyword has a dedicated callback, call it */
1054 if ( field->type == T1_FIELD_TYPE_CALLBACK )
1055 {
1056 field->reader( (FT_Face)face, loader );
1057 error = loader->parser.root.error;
1058 goto Exit;
1059 }
1060
1061 /* now the keyword is either a simple field or a table of fields; */
1062 /* we are now going to take care of it */
1063
1064 switch ( field->location )
1065 {
1066 case T1_FIELD_LOCATION_FONT_INFO:
1067 dummy_object = &face->type1.font_info;
1068 break;
1069
1070 case T1_FIELD_LOCATION_FONT_EXTRA:
1071 dummy_object = &face->type1.font_extra;
1072 break;
1073
1074 case T1_FIELD_LOCATION_BBOX:
1075 dummy_object = &face->type1.font_bbox;
1076 break;
1077
1078 default:
1079 dummy_object = &face->type1;
1080 }
1081
1082 objects = &dummy_object;
1083
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 );
1088 else
1089 error = T1_Load_Field( &loader->parser, field,
1090 objects, max_objects, 0 );
1091
1092 Exit:
1093 return error;
1094 }
1095
1096
1097 FT_LOCAL_DEF( FT_Error )
1098 t42_parse_dict( T42_Face face,
1099 T42_Loader loader,
1100 FT_Byte* base,
1101 FT_Long size )
1102 {
1103 T42_Parser parser = &loader->parser;
1104 FT_Byte* limit;
1105 FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1106 sizeof ( t42_keywords[0] ) );
1107
1108
1109 parser->root.cursor = base;
1110 parser->root.limit = base + size;
1111 parser->root.error = FT_Err_Ok;
1112
1113 limit = parser->root.limit;
1114
1115 T1_Skip_Spaces( parser );
1116
1117 while ( parser->root.cursor < limit )
1118 {
1119 FT_Byte* cur;
1120
1121
1122 cur = parser->root.cursor;
1123
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 )
1127 {
1128 FT_Byte* cur2;
1129
1130
1131 /* skip the `FontDirectory' keyword */
1132 T1_Skip_PS_Token( parser );
1133 T1_Skip_Spaces ( parser );
1134 cur = cur2 = parser->root.cursor;
1135
1136 /* look up the `known' keyword */
1137 while ( cur < limit )
1138 {
1139 if ( *cur == 'k' && cur + 5 < limit &&
1140 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1141 break;
1142
1143 T1_Skip_PS_Token( parser );
1144 if ( parser->root.error )
1145 goto Exit;
1146 T1_Skip_Spaces ( parser );
1147 cur = parser->root.cursor;
1148 }
1149
1150 if ( cur < limit )
1151 {
1152 T1_TokenRec token;
1153
1154
1155 /* skip the `known' keyword and the token following it */
1156 T1_Skip_PS_Token( parser );
1157 T1_ToToken( parser, &token );
1158
1159 /* if the last token was an array, skip it! */
1160 if ( token.type == T1_TOKEN_TYPE_ARRAY )
1161 cur2 = parser->root.cursor;
1162 }
1163 parser->root.cursor = cur2;
1164 }
1165
1166 /* look for immediates */
1167 else if ( *cur == '/' && cur + 2 < limit )
1168 {
1169 FT_UInt len;
1170
1171
1172 cur++;
1173
1174 parser->root.cursor = cur;
1175 T1_Skip_PS_Token( parser );
1176 if ( parser->root.error )
1177 goto Exit;
1178
1179 len = (FT_UInt)( parser->root.cursor - cur );
1180
1181 if ( len > 0 && len < 22 && parser->root.cursor < limit )
1182 {
1183 int i;
1184
1185
1186 /* now compare the immediate name to the keyword table */
1187
1188 /* loop through all known keywords */
1189 for ( i = 0; i < n_keywords; i++ )
1190 {
1191 T1_Field keyword = (T1_Field)&t42_keywords[i];
1192 FT_Byte *name = (FT_Byte*)keyword->ident;
1193
1194
1195 if ( !name )
1196 continue;
1197
1198 if ( cur[0] == name[0] &&
1199 len == ft_strlen( (const char *)name ) &&
1200 ft_memcmp( cur, name, len ) == 0 )
1201 {
1202 /* we found it -- run the parsing callback! */
1203 parser->root.error = t42_load_keyword( face,
1204 loader,
1205 keyword );
1206 if ( parser->root.error )
1207 return parser->root.error;
1208 break;
1209 }
1210 }
1211 }
1212 }
1213 else
1214 {
1215 T1_Skip_PS_Token( parser );
1216 if ( parser->root.error )
1217 goto Exit;
1218 }
1219
1220 T1_Skip_Spaces( parser );
1221 }
1222
1223 Exit:
1224 return parser->root.error;
1225 }
1226
1227
1228 FT_LOCAL_DEF( void )
1229 t42_loader_init( T42_Loader loader,
1230 T42_Face face )
1231 {
1232 FT_UNUSED( face );
1233
1234 FT_MEM_ZERO( loader, sizeof ( *loader ) );
1235 loader->num_glyphs = 0;
1236 loader->num_chars = 0;
1237
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;
1242 }
1243
1244
1245 FT_LOCAL_DEF( void )
1246 t42_loader_done( T42_Loader loader )
1247 {
1248 T42_Parser parser = &loader->parser;
1249
1250
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 );
1256
1257 /* finalize parser */
1258 t42_parser_done( parser );
1259 }
1260
1261
1262 /* END */