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