1 /****************************************************************************
2  *
3  * t42parse.c
4  *
5  *   Type 42 font parser (body).
6  *
7  * Copyright 2002-2018 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 )
t42_parser_init(T42_Parser parser,FT_Stream stream,FT_Memory memory,PSAux_Service psaux)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 )
t42_parser_done(T42_Parser parser)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
t42_is_space(FT_Byte c)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
t42_parse_font_matrix(T42_Face face,T42_Loader loader)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     if ( !FT_Matrix_Check( matrix ) )
288     {
289       FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
290       parser->root.error = FT_THROW( Invalid_File_Format );
291       return;
292     }
293 
294     /* note that the offsets must be expressed in integer font units */
295     offset->x = temp[4] >> 16;
296     offset->y = temp[5] >> 16;
297   }
298 
299 
300   static void
t42_parse_encoding(T42_Face face,T42_Loader loader)301   t42_parse_encoding( T42_Face    face,
302                       T42_Loader  loader )
303   {
304     T42_Parser  parser = &loader->parser;
305     FT_Byte*    cur;
306     FT_Byte*    limit  = parser->root.limit;
307 
308     PSAux_Service  psaux  = (PSAux_Service)face->psaux;
309 
310 
311     T1_Skip_Spaces( parser );
312     cur = parser->root.cursor;
313     if ( cur >= limit )
314     {
315       FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
316       parser->root.error = FT_THROW( Invalid_File_Format );
317       return;
318     }
319 
320     /* if we have a number or `[', the encoding is an array, */
321     /* and we must load it now                               */
322     if ( ft_isdigit( *cur ) || *cur == '[' )
323     {
324       T1_Encoding  encode          = &face->type1.encoding;
325       FT_Int       count, n;
326       PS_Table     char_table      = &loader->encoding_table;
327       FT_Memory    memory          = parser->root.memory;
328       FT_Error     error;
329       FT_Bool      only_immediates = 0;
330 
331 
332       /* read the number of entries in the encoding; should be 256 */
333       if ( *cur == '[' )
334       {
335         count           = 256;
336         only_immediates = 1;
337         parser->root.cursor++;
338       }
339       else
340         count = (FT_Int)T1_ToInt( parser );
341 
342       /* only composite fonts (which we don't support) */
343       /* can have larger values                        */
344       if ( count > 256 )
345       {
346         FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" ));
347         parser->root.error = FT_THROW( Invalid_File_Format );
348         return;
349       }
350 
351       T1_Skip_Spaces( parser );
352       if ( parser->root.cursor >= limit )
353         return;
354 
355       /* PostScript happily allows overwriting of encoding arrays */
356       if ( encode->char_index )
357       {
358         FT_FREE( encode->char_index );
359         FT_FREE( encode->char_name );
360         T1_Release_Table( char_table );
361       }
362 
363       /* we use a T1_Table to store our charnames */
364       loader->num_chars = encode->num_chars = count;
365       if ( FT_NEW_ARRAY( encode->char_index, count )     ||
366            FT_NEW_ARRAY( encode->char_name,  count )     ||
367            FT_SET_ERROR( psaux->ps_table_funcs->init(
368                            char_table, count, memory ) ) )
369       {
370         parser->root.error = error;
371         return;
372       }
373 
374       /* We need to `zero' out encoding_table.elements */
375       for ( n = 0; n < count; n++ )
376       {
377         char*  notdef = (char *)".notdef";
378 
379 
380         (void)T1_Add_Table( char_table, n, notdef, 8 );
381       }
382 
383       /* Now we need to read records of the form                */
384       /*                                                        */
385       /*   ... charcode /charname ...                           */
386       /*                                                        */
387       /* for each entry in our table.                           */
388       /*                                                        */
389       /* We simply look for a number followed by an immediate   */
390       /* name.  Note that this ignores correctly the sequence   */
391       /* that is often seen in type42 fonts:                    */
392       /*                                                        */
393       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
394       /*                                                        */
395       /* used to clean the encoding array before anything else. */
396       /*                                                        */
397       /* Alternatively, if the array is directly given as       */
398       /*                                                        */
399       /*   /Encoding [ ... ]                                    */
400       /*                                                        */
401       /* we only read immediates.                               */
402 
403       n = 0;
404       T1_Skip_Spaces( parser );
405 
406       while ( parser->root.cursor < limit )
407       {
408         cur = parser->root.cursor;
409 
410         /* we stop when we encounter `def' or `]' */
411         if ( *cur == 'd' && cur + 3 < limit )
412         {
413           if ( cur[1] == 'e'          &&
414                cur[2] == 'f'          &&
415                t42_is_space( cur[3] ) )
416           {
417             FT_TRACE6(( "encoding end\n" ));
418             cur += 3;
419             break;
420           }
421         }
422         if ( *cur == ']' )
423         {
424           FT_TRACE6(( "encoding end\n" ));
425           cur++;
426           break;
427         }
428 
429         /* check whether we have found an entry */
430         if ( ft_isdigit( *cur ) || only_immediates )
431         {
432           FT_Int  charcode;
433 
434 
435           if ( only_immediates )
436             charcode = n;
437           else
438           {
439             charcode = (FT_Int)T1_ToInt( parser );
440             T1_Skip_Spaces( parser );
441 
442             /* protect against invalid charcode */
443             if ( cur == parser->root.cursor )
444             {
445               parser->root.error = FT_THROW( Unknown_File_Format );
446               return;
447             }
448           }
449 
450           cur = parser->root.cursor;
451 
452           if ( cur + 2 < limit && *cur == '/' && n < count )
453           {
454             FT_UInt  len;
455 
456 
457             cur++;
458 
459             parser->root.cursor = cur;
460             T1_Skip_PS_Token( parser );
461             if ( parser->root.cursor >= limit )
462               return;
463             if ( parser->root.error )
464               return;
465 
466             len = (FT_UInt)( parser->root.cursor - cur );
467 
468             parser->root.error = T1_Add_Table( char_table, charcode,
469                                                cur, len + 1 );
470             if ( parser->root.error )
471               return;
472             char_table->elements[charcode][len] = '\0';
473 
474             n++;
475           }
476           else if ( only_immediates )
477           {
478             /* Since the current position is not updated for           */
479             /* immediates-only mode we would get an infinite loop if   */
480             /* we don't do anything here.                              */
481             /*                                                         */
482             /* This encoding array is not valid according to the       */
483             /* type42 specification (it might be an encoding for a CID */
484             /* type42 font, however), so we conclude that this font is */
485             /* NOT a type42 font.                                      */
486             parser->root.error = FT_THROW( Unknown_File_Format );
487             return;
488           }
489         }
490         else
491         {
492           T1_Skip_PS_Token( parser );
493           if ( parser->root.error )
494             return;
495         }
496 
497         T1_Skip_Spaces( parser );
498       }
499 
500       face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
501       parser->root.cursor       = cur;
502     }
503 
504     /* Otherwise, we should have either `StandardEncoding', */
505     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
506     else
507     {
508       if ( cur + 17 < limit                                            &&
509            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
510         face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
511 
512       else if ( cur + 15 < limit                                          &&
513                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
514         face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
515 
516       else if ( cur + 18 < limit                                             &&
517                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
518         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
519 
520       else
521         parser->root.error = FT_ERR( Ignore );
522     }
523   }
524 
525 
526   typedef enum  T42_Load_Status_
527   {
528     BEFORE_START,
529     BEFORE_TABLE_DIR,
530     OTHER_TABLES
531 
532   } T42_Load_Status;
533 
534 
535   static void
t42_parse_sfnts(T42_Face face,T42_Loader loader)536   t42_parse_sfnts( T42_Face    face,
537                    T42_Loader  loader )
538   {
539     T42_Parser  parser = &loader->parser;
540     FT_Memory   memory = parser->root.memory;
541     FT_Byte*    cur;
542     FT_Byte*    limit  = parser->root.limit;
543     FT_Error    error;
544     FT_Int      num_tables = 0;
545     FT_Long     count;
546 
547     FT_ULong    n, string_size, old_string_size, real_size;
548     FT_Byte*    string_buf = NULL;
549     FT_Bool     allocated  = 0;
550 
551     T42_Load_Status  status;
552 
553 
554     /* The format is                                */
555     /*                                              */
556     /*   /sfnts [ <hexstring> <hexstring> ... ] def */
557     /*                                              */
558     /* or                                           */
559     /*                                              */
560     /*   /sfnts [                                   */
561     /*      <num_bin_bytes> RD <binary data>        */
562     /*      <num_bin_bytes> RD <binary data>        */
563     /*      ...                                     */
564     /*   ] def                                      */
565     /*                                              */
566     /* with exactly one space after the `RD' token. */
567 
568     T1_Skip_Spaces( parser );
569 
570     if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
571     {
572       FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
573       error = FT_THROW( Invalid_File_Format );
574       goto Fail;
575     }
576 
577     T1_Skip_Spaces( parser );
578     status          = BEFORE_START;
579     string_size     = 0;
580     old_string_size = 0;
581     count           = 0;
582 
583     while ( parser->root.cursor < limit )
584     {
585       FT_ULong  size;
586 
587 
588       cur = parser->root.cursor;
589 
590       if ( *cur == ']' )
591       {
592         parser->root.cursor++;
593         goto Exit;
594       }
595 
596       else if ( *cur == '<' )
597       {
598         T1_Skip_PS_Token( parser );
599         if ( parser->root.error )
600           goto Exit;
601 
602         /* don't include delimiters */
603         string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
604         if ( !string_size )
605         {
606           FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
607           error = FT_THROW( Invalid_File_Format );
608           goto Fail;
609         }
610         if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
611           goto Fail;
612 
613         allocated = 1;
614 
615         parser->root.cursor = cur;
616         (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
617         old_string_size = string_size;
618         string_size     = real_size;
619       }
620 
621       else if ( ft_isdigit( *cur ) )
622       {
623         FT_Long  tmp;
624 
625 
626         if ( allocated )
627         {
628           FT_ERROR(( "t42_parse_sfnts: "
629                      "can't handle mixed binary and hex strings\n" ));
630           error = FT_THROW( Invalid_File_Format );
631           goto Fail;
632         }
633 
634         tmp = T1_ToInt( parser );
635         if ( tmp < 0 )
636         {
637           FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
638           error = FT_THROW( Invalid_File_Format );
639           goto Fail;
640         }
641         else
642           string_size = (FT_ULong)tmp;
643 
644         T1_Skip_PS_Token( parser );             /* `RD' */
645         if ( parser->root.error )
646           return;
647 
648         string_buf = parser->root.cursor + 1;   /* one space after `RD' */
649 
650         if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size )
651         {
652           FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
653           error = FT_THROW( Invalid_File_Format );
654           goto Fail;
655         }
656         else
657           parser->root.cursor += string_size + 1;
658       }
659 
660       if ( !string_buf )
661       {
662         FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
663         error = FT_THROW( Invalid_File_Format );
664         goto Fail;
665       }
666 
667       /* A string can have a trailing zero (odd) byte for padding. */
668       /* Ignore it.                                                */
669       if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
670         string_size--;
671 
672       if ( !string_size )
673       {
674         FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
675         error = FT_THROW( Invalid_File_Format );
676         goto Fail;
677       }
678 
679       /* The whole TTF is now loaded into `string_buf'.  We are */
680       /* checking its contents while copying it to `ttf_data'.  */
681 
682       size = (FT_ULong)( limit - parser->root.cursor );
683 
684       for ( n = 0; n < string_size; n++ )
685       {
686         switch ( status )
687         {
688         case BEFORE_START:
689           /* load offset table, 12 bytes */
690           if ( count < 12 )
691           {
692             face->ttf_data[count++] = string_buf[n];
693             continue;
694           }
695           else
696           {
697             num_tables     = 16 * face->ttf_data[4] + face->ttf_data[5];
698             status         = BEFORE_TABLE_DIR;
699             face->ttf_size = 12 + 16 * num_tables;
700 
701             if ( (FT_Long)size < face->ttf_size )
702             {
703               FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
704               error = FT_THROW( Invalid_File_Format );
705               goto Fail;
706             }
707 
708             if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) )
709               goto Fail;
710           }
711           /* fall through */
712 
713         case BEFORE_TABLE_DIR:
714           /* the offset table is read; read the table directory */
715           if ( count < face->ttf_size )
716           {
717             face->ttf_data[count++] = string_buf[n];
718             continue;
719           }
720           else
721           {
722             int       i;
723             FT_ULong  len;
724 
725 
726             for ( i = 0; i < num_tables; i++ )
727             {
728               FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
729 
730 
731               len = FT_PEEK_ULONG( p );
732               if ( len > size                               ||
733                    face->ttf_size > (FT_Long)( size - len ) )
734               {
735                 FT_ERROR(( "t42_parse_sfnts:"
736                            " invalid data in sfnts array\n" ));
737                 error = FT_THROW( Invalid_File_Format );
738                 goto Fail;
739               }
740 
741               /* Pad to a 4-byte boundary length */
742               face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U );
743             }
744 
745             status = OTHER_TABLES;
746 
747             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
748                              face->ttf_size + 1 ) )
749               goto Fail;
750           }
751           /* fall through */
752 
753         case OTHER_TABLES:
754           /* all other tables are just copied */
755           if ( count >= face->ttf_size )
756           {
757             FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
758             error = FT_THROW( Invalid_File_Format );
759             goto Fail;
760           }
761           face->ttf_data[count++] = string_buf[n];
762         }
763       }
764 
765       T1_Skip_Spaces( parser );
766     }
767 
768     /* if control reaches this point, the format was not valid */
769     error = FT_THROW( Invalid_File_Format );
770 
771   Fail:
772     parser->root.error = error;
773 
774   Exit:
775     if ( allocated )
776       FT_FREE( string_buf );
777   }
778 
779 
780   static void
t42_parse_charstrings(T42_Face face,T42_Loader loader)781   t42_parse_charstrings( T42_Face    face,
782                          T42_Loader  loader )
783   {
784     T42_Parser     parser       = &loader->parser;
785     PS_Table       code_table   = &loader->charstrings;
786     PS_Table       name_table   = &loader->glyph_names;
787     PS_Table       swap_table   = &loader->swap_table;
788     FT_Memory      memory       = parser->root.memory;
789     FT_Error       error;
790 
791     PSAux_Service  psaux        = (PSAux_Service)face->psaux;
792 
793     FT_Byte*       cur;
794     FT_Byte*       limit        = parser->root.limit;
795     FT_Int         n;
796     FT_Int         notdef_index = 0;
797     FT_Byte        notdef_found = 0;
798 
799 
800     T1_Skip_Spaces( parser );
801 
802     if ( parser->root.cursor >= limit )
803     {
804       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
805       error = FT_THROW( Invalid_File_Format );
806       goto Fail;
807     }
808 
809     if ( ft_isdigit( *parser->root.cursor ) )
810     {
811       loader->num_glyphs = T1_ToInt( parser );
812       if ( parser->root.error )
813         return;
814       if ( loader->num_glyphs < 0 )
815       {
816         FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" ));
817         error = FT_THROW( Invalid_File_Format );
818         goto Fail;
819       }
820 
821       /* we certainly need more than 4 bytes per glyph */
822       if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 )
823       {
824         FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs"
825                     " (from %d to %d)\n",
826                     loader->num_glyphs,
827                     ( limit - parser->root.cursor ) >> 2 ));
828         loader->num_glyphs = ( limit - parser->root.cursor ) >> 2;
829       }
830 
831     }
832     else if ( *parser->root.cursor == '<' )
833     {
834       /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
835       /* to get its size.                                                */
836       FT_Int  count = 0;
837 
838 
839       T1_Skip_PS_Token( parser );
840       if ( parser->root.error )
841         return;
842       T1_Skip_Spaces( parser );
843       cur = parser->root.cursor;
844 
845       while ( parser->root.cursor < limit )
846       {
847         if ( *parser->root.cursor == '/' )
848           count++;
849         else if ( *parser->root.cursor == '>' )
850         {
851           loader->num_glyphs  = count;
852           parser->root.cursor = cur;        /* rewind */
853           break;
854         }
855         T1_Skip_PS_Token( parser );
856         if ( parser->root.error )
857           return;
858         T1_Skip_Spaces( parser );
859       }
860     }
861     else
862     {
863       FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
864       error = FT_THROW( Invalid_File_Format );
865       goto Fail;
866     }
867 
868     if ( parser->root.cursor >= limit )
869     {
870       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
871       error = FT_THROW( Invalid_File_Format );
872       goto Fail;
873     }
874 
875     /* initialize tables */
876 
877     /* contrary to Type1, we disallow multiple CharStrings arrays */
878     if ( swap_table->init )
879     {
880       FT_ERROR(( "t42_parse_charstrings:"
881                  " only one CharStrings array allowed\n" ));
882       error = FT_THROW( Invalid_File_Format );
883       goto Fail;
884     }
885 
886     error = psaux->ps_table_funcs->init( code_table,
887                                          loader->num_glyphs,
888                                          memory );
889     if ( error )
890       goto Fail;
891 
892     error = psaux->ps_table_funcs->init( name_table,
893                                          loader->num_glyphs,
894                                          memory );
895     if ( error )
896       goto Fail;
897 
898     /* Initialize table for swapping index notdef_index and */
899     /* index 0 names and codes (if necessary).              */
900 
901     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
902     if ( error )
903       goto Fail;
904 
905     n = 0;
906 
907     for (;;)
908     {
909       /* We support two formats.                     */
910       /*                                             */
911       /*   `/glyphname' + index [+ `def']            */
912       /*   `(glyphname)' [+ `cvn'] + index [+ `def'] */
913       /*                                             */
914       /* The latter format gets created by the       */
915       /* LilyPond typesetting program.               */
916 
917       T1_Skip_Spaces( parser );
918 
919       cur = parser->root.cursor;
920       if ( cur >= limit )
921         break;
922 
923       /* We stop when we find an `end' keyword or '>' */
924       if ( *cur   == 'e'          &&
925            cur + 3 < limit        &&
926            cur[1] == 'n'          &&
927            cur[2] == 'd'          &&
928            t42_is_space( cur[3] ) )
929         break;
930       if ( *cur == '>' )
931         break;
932 
933       T1_Skip_PS_Token( parser );
934       if ( parser->root.cursor >= limit )
935       {
936         FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
937         error = FT_THROW( Invalid_File_Format );
938         goto Fail;
939       }
940       if ( parser->root.error )
941         return;
942 
943       if ( *cur == '/' || *cur == '(' )
944       {
945         FT_UInt  len;
946         FT_Bool  have_literal = FT_BOOL( *cur == '(' );
947 
948 
949         if ( cur + ( have_literal ? 3 : 2 ) >= limit )
950         {
951           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
952           error = FT_THROW( Invalid_File_Format );
953           goto Fail;
954         }
955 
956         cur++;                              /* skip `/' */
957         len = (FT_UInt)( parser->root.cursor - cur );
958         if ( have_literal )
959           len--;
960 
961         error = T1_Add_Table( name_table, n, cur, len + 1 );
962         if ( error )
963           goto Fail;
964 
965         /* add a trailing zero to the name table */
966         name_table->elements[n][len] = '\0';
967 
968         /* record index of /.notdef */
969         if ( *cur == '.'                                              &&
970              ft_strcmp( ".notdef",
971                         (const char*)(name_table->elements[n]) ) == 0 )
972         {
973           notdef_index = n;
974           notdef_found = 1;
975         }
976 
977         T1_Skip_Spaces( parser );
978 
979         if ( have_literal )
980           T1_Skip_PS_Token( parser );
981 
982         cur = parser->root.cursor;
983 
984         (void)T1_ToInt( parser );
985         if ( parser->root.cursor >= limit )
986         {
987           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
988           error = FT_THROW( Invalid_File_Format );
989           goto Fail;
990         }
991 
992         len = (FT_UInt)( parser->root.cursor - cur );
993 
994         error = T1_Add_Table( code_table, n, cur, len + 1 );
995         if ( error )
996           goto Fail;
997 
998         code_table->elements[n][len] = '\0';
999 
1000         n++;
1001         if ( n >= loader->num_glyphs )
1002           break;
1003       }
1004     }
1005 
1006     loader->num_glyphs = n;
1007 
1008     if ( !notdef_found )
1009     {
1010       FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
1011       error = FT_THROW( Invalid_File_Format );
1012       goto Fail;
1013     }
1014 
1015     /* if /.notdef does not occupy index 0, do our magic. */
1016     if ( ft_strcmp( (const char*)".notdef",
1017                     (const char*)name_table->elements[0] ) )
1018     {
1019       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
1020       /* name and code entries to swap_table.  Then place notdef_index   */
1021       /* name and code entries into swap_table.  Then swap name and code */
1022       /* entries at indices notdef_index and 0 using values stored in    */
1023       /* swap_table.                                                     */
1024 
1025       /* Index 0 name */
1026       error = T1_Add_Table( swap_table, 0,
1027                             name_table->elements[0],
1028                             name_table->lengths [0] );
1029       if ( error )
1030         goto Fail;
1031 
1032       /* Index 0 code */
1033       error = T1_Add_Table( swap_table, 1,
1034                             code_table->elements[0],
1035                             code_table->lengths [0] );
1036       if ( error )
1037         goto Fail;
1038 
1039       /* Index notdef_index name */
1040       error = T1_Add_Table( swap_table, 2,
1041                             name_table->elements[notdef_index],
1042                             name_table->lengths [notdef_index] );
1043       if ( error )
1044         goto Fail;
1045 
1046       /* Index notdef_index code */
1047       error = T1_Add_Table( swap_table, 3,
1048                             code_table->elements[notdef_index],
1049                             code_table->lengths [notdef_index] );
1050       if ( error )
1051         goto Fail;
1052 
1053       error = T1_Add_Table( name_table, notdef_index,
1054                             swap_table->elements[0],
1055                             swap_table->lengths [0] );
1056       if ( error )
1057         goto Fail;
1058 
1059       error = T1_Add_Table( code_table, notdef_index,
1060                             swap_table->elements[1],
1061                             swap_table->lengths [1] );
1062       if ( error )
1063         goto Fail;
1064 
1065       error = T1_Add_Table( name_table, 0,
1066                             swap_table->elements[2],
1067                             swap_table->lengths [2] );
1068       if ( error )
1069         goto Fail;
1070 
1071       error = T1_Add_Table( code_table, 0,
1072                             swap_table->elements[3],
1073                             swap_table->lengths [3] );
1074       if ( error )
1075         goto Fail;
1076 
1077     }
1078 
1079     return;
1080 
1081   Fail:
1082     parser->root.error = error;
1083   }
1084 
1085 
1086   static FT_Error
t42_load_keyword(T42_Face face,T42_Loader loader,T1_Field field)1087   t42_load_keyword( T42_Face    face,
1088                     T42_Loader  loader,
1089                     T1_Field    field )
1090   {
1091     FT_Error  error;
1092     void*     dummy_object;
1093     void**    objects;
1094     FT_UInt   max_objects = 0;
1095 
1096 
1097     /* if the keyword has a dedicated callback, call it */
1098     if ( field->type == T1_FIELD_TYPE_CALLBACK )
1099     {
1100       field->reader( (FT_Face)face, loader );
1101       error = loader->parser.root.error;
1102       goto Exit;
1103     }
1104 
1105     /* now the keyword is either a simple field or a table of fields; */
1106     /* we are now going to take care of it                            */
1107 
1108     switch ( field->location )
1109     {
1110     case T1_FIELD_LOCATION_FONT_INFO:
1111       dummy_object = &face->type1.font_info;
1112       break;
1113 
1114     case T1_FIELD_LOCATION_FONT_EXTRA:
1115       dummy_object = &face->type1.font_extra;
1116       break;
1117 
1118     case T1_FIELD_LOCATION_BBOX:
1119       dummy_object = &face->type1.font_bbox;
1120       break;
1121 
1122     default:
1123       dummy_object = &face->type1;
1124     }
1125 
1126     objects = &dummy_object;
1127 
1128     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1129          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1130       error = T1_Load_Field_Table( &loader->parser, field,
1131                                    objects, max_objects, 0 );
1132     else
1133       error = T1_Load_Field( &loader->parser, field,
1134                              objects, max_objects, 0 );
1135 
1136    Exit:
1137     return error;
1138   }
1139 
1140 
1141   FT_LOCAL_DEF( FT_Error )
t42_parse_dict(T42_Face face,T42_Loader loader,FT_Byte * base,FT_Long size)1142   t42_parse_dict( T42_Face    face,
1143                   T42_Loader  loader,
1144                   FT_Byte*    base,
1145                   FT_Long     size )
1146   {
1147     T42_Parser  parser     = &loader->parser;
1148     FT_Byte*    limit;
1149     FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1150                                          sizeof ( t42_keywords[0] ) );
1151 
1152 
1153     parser->root.cursor = base;
1154     parser->root.limit  = base + size;
1155     parser->root.error  = FT_Err_Ok;
1156 
1157     limit = parser->root.limit;
1158 
1159     T1_Skip_Spaces( parser );
1160 
1161     while ( parser->root.cursor < limit )
1162     {
1163       FT_Byte*  cur;
1164 
1165 
1166       cur = parser->root.cursor;
1167 
1168       /* look for `FontDirectory' which causes problems for some fonts */
1169       if ( *cur == 'F' && cur + 25 < limit                    &&
1170            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1171       {
1172         FT_Byte*  cur2;
1173 
1174 
1175         /* skip the `FontDirectory' keyword */
1176         T1_Skip_PS_Token( parser );
1177         T1_Skip_Spaces  ( parser );
1178         cur = cur2 = parser->root.cursor;
1179 
1180         /* look up the `known' keyword */
1181         while ( cur < limit )
1182         {
1183           if ( *cur == 'k' && cur + 5 < limit             &&
1184                 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1185             break;
1186 
1187           T1_Skip_PS_Token( parser );
1188           if ( parser->root.error )
1189             goto Exit;
1190           T1_Skip_Spaces  ( parser );
1191           cur = parser->root.cursor;
1192         }
1193 
1194         if ( cur < limit )
1195         {
1196           T1_TokenRec  token;
1197 
1198 
1199           /* skip the `known' keyword and the token following it */
1200           T1_Skip_PS_Token( parser );
1201           T1_ToToken( parser, &token );
1202 
1203           /* if the last token was an array, skip it! */
1204           if ( token.type == T1_TOKEN_TYPE_ARRAY )
1205             cur2 = parser->root.cursor;
1206         }
1207         parser->root.cursor = cur2;
1208       }
1209 
1210       /* look for immediates */
1211       else if ( *cur == '/' && cur + 2 < limit )
1212       {
1213         FT_UInt  len;
1214 
1215 
1216         cur++;
1217 
1218         parser->root.cursor = cur;
1219         T1_Skip_PS_Token( parser );
1220         if ( parser->root.error )
1221           goto Exit;
1222 
1223         len = (FT_UInt)( parser->root.cursor - cur );
1224 
1225         if ( len > 0 && len < 22 && parser->root.cursor < limit )
1226         {
1227           int  i;
1228 
1229 
1230           /* now compare the immediate name to the keyword table */
1231 
1232           /* loop through all known keywords */
1233           for ( i = 0; i < n_keywords; i++ )
1234           {
1235             T1_Field  keyword = (T1_Field)&t42_keywords[i];
1236             FT_Byte   *name   = (FT_Byte*)keyword->ident;
1237 
1238 
1239             if ( !name )
1240               continue;
1241 
1242             if ( cur[0] == name[0]                      &&
1243                  len == ft_strlen( (const char *)name ) &&
1244                  ft_memcmp( cur, name, len ) == 0       )
1245             {
1246               /* we found it -- run the parsing callback! */
1247               parser->root.error = t42_load_keyword( face,
1248                                                      loader,
1249                                                      keyword );
1250               if ( parser->root.error )
1251                 return parser->root.error;
1252               break;
1253             }
1254           }
1255         }
1256       }
1257       else
1258       {
1259         T1_Skip_PS_Token( parser );
1260         if ( parser->root.error )
1261           goto Exit;
1262       }
1263 
1264       T1_Skip_Spaces( parser );
1265     }
1266 
1267   Exit:
1268     return parser->root.error;
1269   }
1270 
1271 
1272   FT_LOCAL_DEF( void )
t42_loader_init(T42_Loader loader,T42_Face face)1273   t42_loader_init( T42_Loader  loader,
1274                    T42_Face    face )
1275   {
1276     FT_UNUSED( face );
1277 
1278     FT_ZERO( loader );
1279     loader->num_glyphs = 0;
1280     loader->num_chars  = 0;
1281 
1282     /* initialize the tables -- simply set their `init' field to 0 */
1283     loader->encoding_table.init = 0;
1284     loader->charstrings.init    = 0;
1285     loader->glyph_names.init    = 0;
1286   }
1287 
1288 
1289   FT_LOCAL_DEF( void )
t42_loader_done(T42_Loader loader)1290   t42_loader_done( T42_Loader  loader )
1291   {
1292     T42_Parser  parser = &loader->parser;
1293 
1294 
1295     /* finalize tables */
1296     T1_Release_Table( &loader->encoding_table );
1297     T1_Release_Table( &loader->charstrings );
1298     T1_Release_Table( &loader->glyph_names );
1299     T1_Release_Table( &loader->swap_table );
1300 
1301     /* finalize parser */
1302     t42_parser_done( parser );
1303   }
1304 
1305 
1306 /* END */
1307