xref: /aosp_15_r20/external/freetype/src/type42/t42parse.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * t42parse.c
4  *
5  *   Type 42 font parser (body).
6  *
7  * Copyright (C) 2002-2023 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 <freetype/internal/ftdebug.h>
22 #include <freetype/internal/ftstream.h>
23 #include <freetype/internal/psaux.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  t42
34 
35 
36   static void
37   t42_parse_font_matrix( FT_Face  face,
38                          void*    loader_ );
39   static void
40   t42_parse_encoding( FT_Face  face,
41                       void*    loader_ );
42 
43   static void
44   t42_parse_charstrings( FT_Face  face,
45                          void*    loader_ );
46 
47   static void
48   t42_parse_sfnts( FT_Face  face,
49                    void*    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_QALLOC( 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     if ( parser->root.funcs.done )
230       parser->root.funcs.done( &parser->root );
231   }
232 
233 
234   static int
t42_is_space(FT_Byte c)235   t42_is_space( FT_Byte  c )
236   {
237     return ( c == ' '  || c == '\t'              ||
238              c == '\r' || c == '\n' || c == '\f' ||
239              c == '\0'                           );
240   }
241 
242 
243   static void
t42_parse_font_matrix(FT_Face face,void * loader_)244   t42_parse_font_matrix( FT_Face  face,     /* T42_Face */
245                          void*    loader_ )
246   {
247     T42_Face    t42face = (T42_Face)face;
248     T42_Loader  loader  = (T42_Loader)loader_;
249     T42_Parser  parser  = &loader->parser;
250     FT_Matrix*  matrix  = &t42face->type1.font_matrix;
251     FT_Vector*  offset  = &t42face->type1.font_offset;
252     FT_Fixed    temp[6];
253     FT_Fixed    temp_scale;
254     FT_Int      result;
255 
256 
257     result = T1_ToFixedArray( parser, 6, temp, 0 );
258 
259     if ( result < 6 )
260     {
261       parser->root.error = FT_THROW( Invalid_File_Format );
262       return;
263     }
264 
265     temp_scale = FT_ABS( temp[3] );
266 
267     if ( temp_scale == 0 )
268     {
269       FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
270       parser->root.error = FT_THROW( Invalid_File_Format );
271       return;
272     }
273 
274     /* atypical case */
275     if ( temp_scale != 0x10000L )
276     {
277       temp[0] = FT_DivFix( temp[0], temp_scale );
278       temp[1] = FT_DivFix( temp[1], temp_scale );
279       temp[2] = FT_DivFix( temp[2], temp_scale );
280       temp[4] = FT_DivFix( temp[4], temp_scale );
281       temp[5] = FT_DivFix( temp[5], temp_scale );
282       temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
283     }
284 
285     matrix->xx = temp[0];
286     matrix->yx = temp[1];
287     matrix->xy = temp[2];
288     matrix->yy = temp[3];
289 
290     if ( !FT_Matrix_Check( matrix ) )
291     {
292       FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
293       parser->root.error = FT_THROW( Invalid_File_Format );
294       return;
295     }
296 
297     /* note that the offsets must be expressed in integer font units */
298     offset->x = temp[4] >> 16;
299     offset->y = temp[5] >> 16;
300   }
301 
302 
303   static void
t42_parse_encoding(FT_Face face,void * loader_)304   t42_parse_encoding( FT_Face  face,
305                       void*    loader_ )
306   {
307     T42_Face    t42face = (T42_Face)face;
308     T42_Loader  loader  = (T42_Loader)loader_;
309     T42_Parser  parser  = &loader->parser;
310     FT_Byte*    cur;
311     FT_Byte*    limit   = parser->root.limit;
312 
313     PSAux_Service  psaux  = (PSAux_Service)t42face->psaux;
314 
315 
316     T1_Skip_Spaces( parser );
317     cur = parser->root.cursor;
318     if ( cur >= limit )
319     {
320       FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
321       parser->root.error = FT_THROW( Invalid_File_Format );
322       return;
323     }
324 
325     /* if we have a number or `[', the encoding is an array, */
326     /* and we must load it now                               */
327     if ( ft_isdigit( *cur ) || *cur == '[' )
328     {
329       T1_Encoding  encode          = &t42face->type1.encoding;
330       FT_Int       count, n;
331       PS_Table     char_table      = &loader->encoding_table;
332       FT_Memory    memory          = parser->root.memory;
333       FT_Error     error;
334       FT_Bool      only_immediates = 0;
335 
336 
337       /* read the number of entries in the encoding; should be 256 */
338       if ( *cur == '[' )
339       {
340         count           = 256;
341         only_immediates = 1;
342         parser->root.cursor++;
343       }
344       else
345         count = (FT_Int)T1_ToInt( parser );
346 
347       /* only composite fonts (which we don't support) */
348       /* can have larger values                        */
349       if ( count > 256 )
350       {
351         FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" ));
352         parser->root.error = FT_THROW( Invalid_File_Format );
353         return;
354       }
355 
356       T1_Skip_Spaces( parser );
357       if ( parser->root.cursor >= limit )
358         return;
359 
360       /* PostScript happily allows overwriting of encoding arrays */
361       if ( encode->char_index )
362       {
363         FT_FREE( encode->char_index );
364         FT_FREE( encode->char_name );
365         T1_Release_Table( char_table );
366       }
367 
368       /* we use a T1_Table to store our charnames */
369       loader->num_chars = encode->num_chars = count;
370       if ( FT_QNEW_ARRAY( encode->char_index, count )    ||
371            FT_QNEW_ARRAY( encode->char_name,  count )    ||
372            FT_SET_ERROR( psaux->ps_table_funcs->init(
373                            char_table, count, memory ) ) )
374       {
375         parser->root.error = error;
376         return;
377       }
378 
379       /* We need to `zero' out encoding_table.elements */
380       for ( n = 0; n < count; n++ )
381         (void)T1_Add_Table( char_table, n, ".notdef", 8 );
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       t42face->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         t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
511 
512       else if ( cur + 15 < limit                                          &&
513                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
514         t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
515 
516       else if ( cur + 18 < limit                                             &&
517                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
518         t42face->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(FT_Face face,void * loader_)536   t42_parse_sfnts( FT_Face  face,
537                    void*    loader_ )
538   {
539     T42_Face    t42face = (T42_Face)face;
540     T42_Loader  loader  = (T42_Loader)loader_;
541     T42_Parser  parser = &loader->parser;
542     FT_Memory   memory = parser->root.memory;
543     FT_Byte*    cur;
544     FT_Byte*    limit  = parser->root.limit;
545     FT_Error    error;
546     FT_Int      num_tables = 0;
547     FT_Long     ttf_count;
548     FT_Long     ttf_reserved;
549 
550     FT_ULong    n, string_size, old_string_size, real_size;
551     FT_Byte*    string_buf = NULL;
552     FT_Bool     allocated  = 0;
553 
554     T42_Load_Status  status;
555 
556     /** There should only be one sfnts array, but free any previous. */
557     FT_FREE( t42face->ttf_data );
558     t42face->ttf_size = 0;
559 
560     /* The format is                                */
561     /*                                              */
562     /*   /sfnts [ <hexstring> <hexstring> ... ] def */
563     /*                                              */
564     /* or                                           */
565     /*                                              */
566     /*   /sfnts [                                   */
567     /*      <num_bin_bytes> RD <binary data>        */
568     /*      <num_bin_bytes> RD <binary data>        */
569     /*      ...                                     */
570     /*   ] def                                      */
571     /*                                              */
572     /* with exactly one space after the `RD' token. */
573 
574     T1_Skip_Spaces( parser );
575 
576     if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
577     {
578       FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
579       error = FT_THROW( Invalid_File_Format );
580       goto Fail;
581     }
582 
583     T1_Skip_Spaces( parser );
584     status          = BEFORE_START;
585     string_size     = 0;
586     old_string_size = 0;
587     ttf_count       = 0;
588     ttf_reserved    = 12;
589     if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) )
590       goto Fail;
591 
592     FT_TRACE2(( "\n" ));
593     FT_TRACE2(( "t42_parse_sfnts:\n" ));
594 
595     while ( parser->root.cursor < limit )
596     {
597       FT_ULong  size;
598 
599 
600       cur = parser->root.cursor;
601 
602       if ( *cur == ']' )
603       {
604         parser->root.cursor++;
605         t42face->ttf_size = ttf_count;
606         goto Exit;
607       }
608 
609       else if ( *cur == '<' )
610       {
611         if ( string_buf && !allocated )
612         {
613           FT_ERROR(( "t42_parse_sfnts: "
614                      "can't handle mixed binary and hex strings\n" ));
615           error = FT_THROW( Invalid_File_Format );
616           goto Fail;
617         }
618 
619         T1_Skip_PS_Token( parser );
620         if ( parser->root.error )
621           goto Exit;
622 
623         /* don't include delimiters */
624         string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
625         if ( !string_size )
626         {
627           FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
628           error = FT_THROW( Invalid_File_Format );
629           goto Fail;
630         }
631         if ( FT_QREALLOC( string_buf, old_string_size, string_size ) )
632           goto Fail;
633 
634         allocated = 1;
635 
636         parser->root.cursor = cur;
637         (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
638         old_string_size = string_size;
639         string_size     = real_size;
640       }
641 
642       else if ( ft_isdigit( *cur ) )
643       {
644         FT_Long  tmp;
645 
646 
647         if ( allocated )
648         {
649           FT_ERROR(( "t42_parse_sfnts: "
650                      "can't handle mixed binary and hex strings\n" ));
651           error = FT_THROW( Invalid_File_Format );
652           goto Fail;
653         }
654 
655         tmp = T1_ToInt( parser );
656         if ( tmp < 0 )
657         {
658           FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
659           error = FT_THROW( Invalid_File_Format );
660           goto Fail;
661         }
662         else
663           string_size = (FT_ULong)tmp;
664 
665         T1_Skip_PS_Token( parser );             /* `RD' */
666         if ( parser->root.error )
667           return;
668 
669         string_buf = parser->root.cursor + 1;   /* one space after `RD' */
670 
671         if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size )
672         {
673           FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
674           error = FT_THROW( Invalid_File_Format );
675           goto Fail;
676         }
677         else
678           parser->root.cursor += string_size + 1;
679       }
680 
681       if ( !string_buf )
682       {
683         FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
684         error = FT_THROW( Invalid_File_Format );
685         goto Fail;
686       }
687 
688       /* A string can have a trailing zero (odd) byte for padding. */
689       /* Ignore it.                                                */
690       if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
691         string_size--;
692 
693       if ( !string_size )
694       {
695         FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
696         error = FT_THROW( Invalid_File_Format );
697         goto Fail;
698       }
699 
700       FT_TRACE2(( "  PS string size %5lu bytes, offset 0x%08lx (%lu)\n",
701                   string_size, ttf_count, ttf_count ));
702 
703       /* The whole TTF is now loaded into `string_buf'.  We are */
704       /* checking its contents while copying it to `ttf_data'.  */
705 
706       size = (FT_ULong)( limit - parser->root.cursor );
707 
708       for ( n = 0; n < string_size; n++ )
709       {
710         switch ( status )
711         {
712         case BEFORE_START:
713           /* load offset table, 12 bytes */
714           if ( ttf_count < 12 )
715           {
716             t42face->ttf_data[ttf_count++] = string_buf[n];
717             continue;
718           }
719           else
720           {
721             FT_Long ttf_reserved_prev = ttf_reserved;
722 
723 
724             num_tables   = 16 * t42face->ttf_data[4] + t42face->ttf_data[5];
725             status       = BEFORE_TABLE_DIR;
726             ttf_reserved = 12 + 16 * num_tables;
727 
728             FT_TRACE2(( "  SFNT directory contains %d tables\n",
729                         num_tables ));
730 
731             if ( (FT_Long)size < ttf_reserved )
732             {
733               FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
734               error = FT_THROW( Invalid_File_Format );
735               goto Fail;
736             }
737 
738             if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
739                               ttf_reserved ) )
740               goto Fail;
741           }
742           FALL_THROUGH;
743 
744         case BEFORE_TABLE_DIR:
745           /* the offset table is read; read the table directory */
746           if ( ttf_count < ttf_reserved )
747           {
748             t42face->ttf_data[ttf_count++] = string_buf[n];
749             continue;
750           }
751           else
752           {
753             int       i;
754             FT_ULong  len;
755             FT_Long ttf_reserved_prev = ttf_reserved;
756 
757 
758             FT_TRACE2(( "\n" ));
759             FT_TRACE2(( "  table    length\n" ));
760             FT_TRACE2(( "  ------------------------------\n" ));
761 
762             for ( i = 0; i < num_tables; i++ )
763             {
764               FT_Byte*  p = t42face->ttf_data + 12 + 16 * i + 12;
765 
766 
767               len = FT_PEEK_ULONG( p );
768               FT_TRACE2(( "   %4i  0x%08lx (%lu)\n", i, len, len ));
769 
770               if ( len > size                               ||
771                    ttf_reserved > (FT_Long)( size - len ) )
772               {
773                 FT_ERROR(( "t42_parse_sfnts:"
774                            " invalid data in sfnts array\n" ));
775                 error = FT_THROW( Invalid_File_Format );
776                 goto Fail;
777               }
778 
779               /* Pad to a 4-byte boundary length */
780               ttf_reserved += (FT_Long)( ( len + 3 ) & ~3U );
781             }
782             ttf_reserved += 1;
783 
784             status = OTHER_TABLES;
785 
786             FT_TRACE2(( "\n" ));
787             FT_TRACE2(( "  allocating %ld bytes\n", ttf_reserved ));
788             FT_TRACE2(( "\n" ));
789 
790             if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
791                               ttf_reserved ) )
792               goto Fail;
793           }
794           FALL_THROUGH;
795 
796         case OTHER_TABLES:
797           /* all other tables are just copied */
798           if ( ttf_count >= ttf_reserved )
799           {
800             FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
801             error = FT_THROW( Invalid_File_Format );
802             goto Fail;
803           }
804           t42face->ttf_data[ttf_count++] = string_buf[n];
805         }
806       }
807 
808       T1_Skip_Spaces( parser );
809     }
810 
811     /* if control reaches this point, the format was not valid */
812     error = FT_THROW( Invalid_File_Format );
813 
814   Fail:
815     parser->root.error = error;
816 
817   Exit:
818     if ( parser->root.error )
819     {
820       FT_FREE( t42face->ttf_data );
821       t42face->ttf_size = 0;
822     }
823     if ( allocated )
824       FT_FREE( string_buf );
825   }
826 
827 
828   static void
t42_parse_charstrings(FT_Face face,void * loader_)829   t42_parse_charstrings( FT_Face  face,     /* T42_Face */
830                          void*    loader_ )
831   {
832     T42_Face       t42face      = (T42_Face)face;
833     T42_Loader     loader       = (T42_Loader)loader_;
834     T42_Parser     parser       = &loader->parser;
835     PS_Table       code_table   = &loader->charstrings;
836     PS_Table       name_table   = &loader->glyph_names;
837     PS_Table       swap_table   = &loader->swap_table;
838     FT_Memory      memory       = parser->root.memory;
839     FT_Error       error;
840 
841     PSAux_Service  psaux        = (PSAux_Service)t42face->psaux;
842 
843     FT_Byte*       cur;
844     FT_Byte*       limit        = parser->root.limit;
845     FT_Int         n;
846     FT_Int         notdef_index = 0;
847     FT_Byte        notdef_found = 0;
848 
849 
850     T1_Skip_Spaces( parser );
851 
852     if ( parser->root.cursor >= limit )
853     {
854       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
855       error = FT_THROW( Invalid_File_Format );
856       goto Fail;
857     }
858 
859     if ( ft_isdigit( *parser->root.cursor ) )
860     {
861       loader->num_glyphs = T1_ToInt( parser );
862       if ( parser->root.error )
863         return;
864       if ( loader->num_glyphs < 0 )
865       {
866         FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" ));
867         error = FT_THROW( Invalid_File_Format );
868         goto Fail;
869       }
870 
871       /* we certainly need more than 4 bytes per glyph */
872       if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 )
873       {
874         FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs"
875                     " (from %d to %zu)\n",
876                     loader->num_glyphs,
877                     ( limit - parser->root.cursor ) >> 2 ));
878         loader->num_glyphs = ( limit - parser->root.cursor ) >> 2;
879       }
880 
881     }
882     else if ( *parser->root.cursor == '<' )
883     {
884       /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
885       /* to get its size.                                                */
886       FT_Int  count = 0;
887 
888 
889       T1_Skip_PS_Token( parser );
890       if ( parser->root.error )
891         return;
892       T1_Skip_Spaces( parser );
893       cur = parser->root.cursor;
894 
895       while ( parser->root.cursor < limit )
896       {
897         if ( *parser->root.cursor == '/' )
898           count++;
899         else if ( *parser->root.cursor == '>' )
900         {
901           loader->num_glyphs  = count;
902           parser->root.cursor = cur;        /* rewind */
903           break;
904         }
905         T1_Skip_PS_Token( parser );
906         if ( parser->root.error )
907           return;
908         T1_Skip_Spaces( parser );
909       }
910     }
911     else
912     {
913       FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
914       error = FT_THROW( Invalid_File_Format );
915       goto Fail;
916     }
917 
918     if ( parser->root.cursor >= limit )
919     {
920       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
921       error = FT_THROW( Invalid_File_Format );
922       goto Fail;
923     }
924 
925     /* initialize tables */
926 
927     /* contrary to Type1, we disallow multiple CharStrings arrays */
928     if ( swap_table->init )
929     {
930       FT_ERROR(( "t42_parse_charstrings:"
931                  " only one CharStrings array allowed\n" ));
932       error = FT_THROW( Invalid_File_Format );
933       goto Fail;
934     }
935 
936     error = psaux->ps_table_funcs->init( code_table,
937                                          loader->num_glyphs,
938                                          memory );
939     if ( error )
940       goto Fail;
941 
942     error = psaux->ps_table_funcs->init( name_table,
943                                          loader->num_glyphs,
944                                          memory );
945     if ( error )
946       goto Fail;
947 
948     /* Initialize table for swapping index notdef_index and */
949     /* index 0 names and codes (if necessary).              */
950 
951     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
952     if ( error )
953       goto Fail;
954 
955     n = 0;
956 
957     for (;;)
958     {
959       /* We support two formats.                     */
960       /*                                             */
961       /*   `/glyphname' + index [+ `def']            */
962       /*   `(glyphname)' [+ `cvn'] + index [+ `def'] */
963       /*                                             */
964       /* The latter format gets created by the       */
965       /* LilyPond typesetting program.               */
966 
967       T1_Skip_Spaces( parser );
968 
969       cur = parser->root.cursor;
970       if ( cur >= limit )
971         break;
972 
973       /* We stop when we find an `end' keyword or '>' */
974       if ( *cur   == 'e'          &&
975            cur + 3 < limit        &&
976            cur[1] == 'n'          &&
977            cur[2] == 'd'          &&
978            t42_is_space( cur[3] ) )
979         break;
980       if ( *cur == '>' )
981         break;
982 
983       T1_Skip_PS_Token( parser );
984       if ( parser->root.cursor >= limit )
985       {
986         FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
987         error = FT_THROW( Invalid_File_Format );
988         goto Fail;
989       }
990       if ( parser->root.error )
991         return;
992 
993       if ( *cur == '/' || *cur == '(' )
994       {
995         FT_UInt  len;
996         FT_Bool  have_literal = FT_BOOL( *cur == '(' );
997 
998 
999         if ( cur + ( have_literal ? 3 : 2 ) >= limit )
1000         {
1001           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
1002           error = FT_THROW( Invalid_File_Format );
1003           goto Fail;
1004         }
1005 
1006         cur++;                              /* skip `/' */
1007         len = (FT_UInt)( parser->root.cursor - cur );
1008         if ( have_literal )
1009           len--;
1010 
1011         error = T1_Add_Table( name_table, n, cur, len + 1 );
1012         if ( error )
1013           goto Fail;
1014 
1015         /* add a trailing zero to the name table */
1016         name_table->elements[n][len] = '\0';
1017 
1018         /* record index of /.notdef */
1019         if ( *cur == '.'                                                &&
1020              ft_strcmp( ".notdef",
1021                         (const char*)( name_table->elements[n] ) ) == 0 )
1022         {
1023           notdef_index = n;
1024           notdef_found = 1;
1025         }
1026 
1027         T1_Skip_Spaces( parser );
1028 
1029         if ( have_literal )
1030           T1_Skip_PS_Token( parser );
1031 
1032         cur = parser->root.cursor;
1033 
1034         (void)T1_ToInt( parser );
1035         if ( parser->root.cursor >= limit )
1036         {
1037           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
1038           error = FT_THROW( Invalid_File_Format );
1039           goto Fail;
1040         }
1041 
1042         len = (FT_UInt)( parser->root.cursor - cur );
1043 
1044         error = T1_Add_Table( code_table, n, cur, len + 1 );
1045         if ( error )
1046           goto Fail;
1047 
1048         code_table->elements[n][len] = '\0';
1049 
1050         n++;
1051         if ( n >= loader->num_glyphs )
1052           break;
1053       }
1054     }
1055 
1056     loader->num_glyphs = n;
1057 
1058     if ( !notdef_found )
1059     {
1060       FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
1061       error = FT_THROW( Invalid_File_Format );
1062       goto Fail;
1063     }
1064 
1065     /* if /.notdef does not occupy index 0, do our magic. */
1066     if ( ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
1067     {
1068       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
1069       /* name and code entries to swap_table.  Then place notdef_index   */
1070       /* name and code entries into swap_table.  Then swap name and code */
1071       /* entries at indices notdef_index and 0 using values stored in    */
1072       /* swap_table.                                                     */
1073 
1074       /* Index 0 name */
1075       error = T1_Add_Table( swap_table, 0,
1076                             name_table->elements[0],
1077                             name_table->lengths [0] );
1078       if ( error )
1079         goto Fail;
1080 
1081       /* Index 0 code */
1082       error = T1_Add_Table( swap_table, 1,
1083                             code_table->elements[0],
1084                             code_table->lengths [0] );
1085       if ( error )
1086         goto Fail;
1087 
1088       /* Index notdef_index name */
1089       error = T1_Add_Table( swap_table, 2,
1090                             name_table->elements[notdef_index],
1091                             name_table->lengths [notdef_index] );
1092       if ( error )
1093         goto Fail;
1094 
1095       /* Index notdef_index code */
1096       error = T1_Add_Table( swap_table, 3,
1097                             code_table->elements[notdef_index],
1098                             code_table->lengths [notdef_index] );
1099       if ( error )
1100         goto Fail;
1101 
1102       error = T1_Add_Table( name_table, notdef_index,
1103                             swap_table->elements[0],
1104                             swap_table->lengths [0] );
1105       if ( error )
1106         goto Fail;
1107 
1108       error = T1_Add_Table( code_table, notdef_index,
1109                             swap_table->elements[1],
1110                             swap_table->lengths [1] );
1111       if ( error )
1112         goto Fail;
1113 
1114       error = T1_Add_Table( name_table, 0,
1115                             swap_table->elements[2],
1116                             swap_table->lengths [2] );
1117       if ( error )
1118         goto Fail;
1119 
1120       error = T1_Add_Table( code_table, 0,
1121                             swap_table->elements[3],
1122                             swap_table->lengths [3] );
1123       if ( error )
1124         goto Fail;
1125 
1126     }
1127 
1128     return;
1129 
1130   Fail:
1131     parser->root.error = error;
1132   }
1133 
1134 
1135   static FT_Error
t42_load_keyword(T42_Face face,T42_Loader loader,T1_Field field)1136   t42_load_keyword( T42_Face    face,
1137                     T42_Loader  loader,
1138                     T1_Field    field )
1139   {
1140     FT_Error  error;
1141     void*     dummy_object;
1142     void**    objects;
1143     FT_UInt   max_objects = 0;
1144 
1145 
1146     /* if the keyword has a dedicated callback, call it */
1147     if ( field->type == T1_FIELD_TYPE_CALLBACK )
1148     {
1149       field->reader( (FT_Face)face, loader );
1150       error = loader->parser.root.error;
1151       goto Exit;
1152     }
1153 
1154     /* now the keyword is either a simple field or a table of fields; */
1155     /* we are now going to take care of it                            */
1156 
1157     switch ( field->location )
1158     {
1159     case T1_FIELD_LOCATION_FONT_INFO:
1160       dummy_object = &face->type1.font_info;
1161       break;
1162 
1163     case T1_FIELD_LOCATION_FONT_EXTRA:
1164       dummy_object = &face->type1.font_extra;
1165       break;
1166 
1167     case T1_FIELD_LOCATION_BBOX:
1168       dummy_object = &face->type1.font_bbox;
1169       break;
1170 
1171     default:
1172       dummy_object = &face->type1;
1173     }
1174 
1175     objects = &dummy_object;
1176 
1177     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1178          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1179       error = T1_Load_Field_Table( &loader->parser, field,
1180                                    objects, max_objects, 0 );
1181     else
1182       error = T1_Load_Field( &loader->parser, field,
1183                              objects, max_objects, 0 );
1184 
1185    Exit:
1186     return error;
1187   }
1188 
1189 
1190   FT_LOCAL_DEF( FT_Error )
t42_parse_dict(T42_Face face,T42_Loader loader,FT_Byte * base,FT_Long size)1191   t42_parse_dict( T42_Face    face,
1192                   T42_Loader  loader,
1193                   FT_Byte*    base,
1194                   FT_Long     size )
1195   {
1196     T42_Parser  parser     = &loader->parser;
1197     FT_Byte*    limit;
1198     FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1199                                          sizeof ( t42_keywords[0] ) );
1200 
1201 
1202     parser->root.cursor = base;
1203     parser->root.limit  = base + size;
1204     parser->root.error  = FT_Err_Ok;
1205 
1206     limit = parser->root.limit;
1207 
1208     T1_Skip_Spaces( parser );
1209 
1210     while ( parser->root.cursor < limit )
1211     {
1212       FT_Byte*  cur;
1213 
1214 
1215       cur = parser->root.cursor;
1216 
1217       /* look for `FontDirectory' which causes problems for some fonts */
1218       if ( *cur == 'F' && cur + 25 < limit                    &&
1219            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1220       {
1221         FT_Byte*  cur2;
1222 
1223 
1224         /* skip the `FontDirectory' keyword */
1225         T1_Skip_PS_Token( parser );
1226         T1_Skip_Spaces  ( parser );
1227         cur = cur2 = parser->root.cursor;
1228 
1229         /* look up the `known' keyword */
1230         while ( cur < limit )
1231         {
1232           if ( *cur == 'k' && cur + 5 < limit             &&
1233                 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1234             break;
1235 
1236           T1_Skip_PS_Token( parser );
1237           if ( parser->root.error )
1238             goto Exit;
1239           T1_Skip_Spaces  ( parser );
1240           cur = parser->root.cursor;
1241         }
1242 
1243         if ( cur < limit )
1244         {
1245           T1_TokenRec  token;
1246 
1247 
1248           /* skip the `known' keyword and the token following it */
1249           T1_Skip_PS_Token( parser );
1250           T1_ToToken( parser, &token );
1251 
1252           /* if the last token was an array, skip it! */
1253           if ( token.type == T1_TOKEN_TYPE_ARRAY )
1254             cur2 = parser->root.cursor;
1255         }
1256         parser->root.cursor = cur2;
1257       }
1258 
1259       /* look for immediates */
1260       else if ( *cur == '/' && cur + 2 < limit )
1261       {
1262         FT_UInt  len;
1263 
1264 
1265         cur++;
1266 
1267         parser->root.cursor = cur;
1268         T1_Skip_PS_Token( parser );
1269         if ( parser->root.error )
1270           goto Exit;
1271 
1272         len = (FT_UInt)( parser->root.cursor - cur );
1273 
1274         if ( len > 0 && len < 22 && parser->root.cursor < limit )
1275         {
1276           int  i;
1277 
1278 
1279           /* now compare the immediate name to the keyword table */
1280 
1281           /* loop through all known keywords */
1282           for ( i = 0; i < n_keywords; i++ )
1283           {
1284             T1_Field  keyword = (T1_Field)&t42_keywords[i];
1285             FT_Byte   *name   = (FT_Byte*)keyword->ident;
1286 
1287 
1288             if ( !name )
1289               continue;
1290 
1291             if ( cur[0] == name[0]                      &&
1292                  len == ft_strlen( (const char *)name ) &&
1293                  ft_memcmp( cur, name, len ) == 0       )
1294             {
1295               /* we found it -- run the parsing callback! */
1296               parser->root.error = t42_load_keyword( face,
1297                                                      loader,
1298                                                      keyword );
1299               if ( parser->root.error )
1300                 return parser->root.error;
1301               break;
1302             }
1303           }
1304         }
1305       }
1306       else
1307       {
1308         T1_Skip_PS_Token( parser );
1309         if ( parser->root.error )
1310           goto Exit;
1311       }
1312 
1313       T1_Skip_Spaces( parser );
1314     }
1315 
1316   Exit:
1317     return parser->root.error;
1318   }
1319 
1320 
1321   FT_LOCAL_DEF( void )
t42_loader_init(T42_Loader loader,T42_Face face)1322   t42_loader_init( T42_Loader  loader,
1323                    T42_Face    face )
1324   {
1325     FT_UNUSED( face );
1326 
1327     FT_ZERO( loader );
1328     loader->num_glyphs = 0;
1329     loader->num_chars  = 0;
1330 
1331     /* initialize the tables -- simply set their `init' field to 0 */
1332     loader->encoding_table.init = 0;
1333     loader->charstrings.init    = 0;
1334     loader->glyph_names.init    = 0;
1335   }
1336 
1337 
1338   FT_LOCAL_DEF( void )
t42_loader_done(T42_Loader loader)1339   t42_loader_done( T42_Loader  loader )
1340   {
1341     T42_Parser  parser = &loader->parser;
1342 
1343 
1344     /* finalize tables */
1345     T1_Release_Table( &loader->encoding_table );
1346     T1_Release_Table( &loader->charstrings );
1347     T1_Release_Table( &loader->glyph_names );
1348     T1_Release_Table( &loader->swap_table );
1349 
1350     /* finalize parser */
1351     t42_parser_done( parser );
1352   }
1353 
1354 
1355 /* END */
1356