tizen 2.3.1 release
[framework/graphics/freetype.git] / src / type42 / t42parse.c
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 )
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 )
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
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
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
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;
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         (void)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
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;
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 ( !string_size )
584         {
585           FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
586           error = FT_THROW( Invalid_File_Format );
587           goto Fail;
588         }
589         if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
590           goto Fail;
591
592         allocated = 1;
593
594         parser->root.cursor = cur;
595         (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
596         old_string_size = string_size;
597         string_size = real_size;
598       }
599
600       else if ( ft_isdigit( *cur ) )
601       {
602         if ( allocated )
603         {
604           FT_ERROR(( "t42_parse_sfnts: "
605                      "can't handle mixed binary and hex strings\n" ));
606           error = FT_THROW( Invalid_File_Format );
607           goto Fail;
608         }
609
610         string_size = T1_ToInt( parser );
611         if ( string_size < 0 )
612         {
613           FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
614           error = FT_THROW( Invalid_File_Format );
615           goto Fail;
616         }
617
618         T1_Skip_PS_Token( parser );             /* `RD' */
619         if ( parser->root.error )
620           return;
621
622         string_buf = parser->root.cursor + 1;   /* one space after `RD' */
623
624         if ( limit - parser->root.cursor < string_size )
625         {
626           FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
627           error = FT_THROW( Invalid_File_Format );
628           goto Fail;
629         }
630         else
631           parser->root.cursor += string_size + 1;
632       }
633
634       if ( !string_buf )
635       {
636         FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
637         error = FT_THROW( Invalid_File_Format );
638         goto Fail;
639       }
640
641       /* A string can have a trailing zero (odd) byte for padding. */
642       /* Ignore it.                                                */
643       if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
644         string_size--;
645
646       if ( !string_size )
647       {
648         FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
649         error = FT_THROW( Invalid_File_Format );
650         goto Fail;
651       }
652
653       for ( n = 0; n < string_size; n++ )
654       {
655         switch ( status )
656         {
657         case BEFORE_START:
658           /* load offset table, 12 bytes */
659           if ( count < 12 )
660           {
661             face->ttf_data[count++] = string_buf[n];
662             continue;
663           }
664           else
665           {
666             num_tables     = 16 * face->ttf_data[4] + face->ttf_data[5];
667             status         = BEFORE_TABLE_DIR;
668             face->ttf_size = 12 + 16 * num_tables;
669
670             if ( (FT_ULong)( limit - parser->root.cursor ) < face->ttf_size )
671             {
672               FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
673               error = FT_THROW( Invalid_File_Format );
674               goto Fail;
675             }
676
677             if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) )
678               goto Fail;
679           }
680           /* fall through */
681
682         case BEFORE_TABLE_DIR:
683           /* the offset table is read; read the table directory */
684           if ( count < face->ttf_size )
685           {
686             face->ttf_data[count++] = string_buf[n];
687             continue;
688           }
689           else
690           {
691             int       i;
692             FT_ULong  len;
693
694
695             for ( i = 0; i < num_tables; i++ )
696             {
697               FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
698
699
700               len = FT_PEEK_ULONG( p );
701
702               /* Pad to a 4-byte boundary length */
703               face->ttf_size += ( len + 3 ) & ~3;
704             }
705
706             status = OTHER_TABLES;
707
708             /* there are no more than 256 tables, so no size check here */
709             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
710                              face->ttf_size + 1 ) )
711               goto Fail;
712           }
713           /* fall through */
714
715         case OTHER_TABLES:
716           /* all other tables are just copied */
717           if ( count >= face->ttf_size )
718           {
719             FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
720             error = FT_THROW( Invalid_File_Format );
721             goto Fail;
722           }
723           face->ttf_data[count++] = string_buf[n];
724         }
725       }
726
727       T1_Skip_Spaces( parser );
728     }
729
730     /* if control reaches this point, the format was not valid */
731     error = FT_THROW( Invalid_File_Format );
732
733   Fail:
734     parser->root.error = error;
735
736   Exit:
737     if ( allocated )
738       FT_FREE( string_buf );
739   }
740
741
742   static void
743   t42_parse_charstrings( T42_Face    face,
744                          T42_Loader  loader )
745   {
746     T42_Parser     parser       = &loader->parser;
747     PS_Table       code_table   = &loader->charstrings;
748     PS_Table       name_table   = &loader->glyph_names;
749     PS_Table       swap_table   = &loader->swap_table;
750     FT_Memory      memory       = parser->root.memory;
751     FT_Error       error;
752
753     PSAux_Service  psaux        = (PSAux_Service)face->psaux;
754
755     FT_Byte*       cur;
756     FT_Byte*       limit        = parser->root.limit;
757     FT_UInt        n;
758     FT_UInt        notdef_index = 0;
759     FT_Byte        notdef_found = 0;
760
761
762     T1_Skip_Spaces( parser );
763
764     if ( parser->root.cursor >= limit )
765     {
766       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
767       error = FT_THROW( Invalid_File_Format );
768       goto Fail;
769     }
770
771     if ( ft_isdigit( *parser->root.cursor ) )
772     {
773       loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
774       if ( parser->root.error )
775         return;
776     }
777     else if ( *parser->root.cursor == '<' )
778     {
779       /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
780       /* to get its size.                                                */
781       FT_UInt  count = 0;
782
783
784       T1_Skip_PS_Token( parser );
785       if ( parser->root.error )
786         return;
787       T1_Skip_Spaces( parser );
788       cur = parser->root.cursor;
789
790       while ( parser->root.cursor < limit )
791       {
792         if ( *parser->root.cursor == '/' )
793           count++;
794         else if ( *parser->root.cursor == '>' )
795         {
796           loader->num_glyphs  = count;
797           parser->root.cursor = cur;        /* rewind */
798           break;
799         }
800         T1_Skip_PS_Token( parser );
801         if ( parser->root.error )
802           return;
803         T1_Skip_Spaces( parser );
804       }
805     }
806     else
807     {
808       FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
809       error = FT_THROW( Invalid_File_Format );
810       goto Fail;
811     }
812
813     if ( parser->root.cursor >= limit )
814     {
815       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
816       error = FT_THROW( Invalid_File_Format );
817       goto Fail;
818     }
819
820     /* initialize tables */
821
822     error = psaux->ps_table_funcs->init( code_table,
823                                          loader->num_glyphs,
824                                          memory );
825     if ( error )
826       goto Fail;
827
828     error = psaux->ps_table_funcs->init( name_table,
829                                          loader->num_glyphs,
830                                          memory );
831     if ( error )
832       goto Fail;
833
834     /* Initialize table for swapping index notdef_index and */
835     /* index 0 names and codes (if necessary).              */
836
837     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
838     if ( error )
839       goto Fail;
840
841     n = 0;
842
843     for (;;)
844     {
845       /* The format is simple:                   */
846       /*   `/glyphname' + index [+ def]          */
847
848       T1_Skip_Spaces( parser );
849
850       cur = parser->root.cursor;
851       if ( cur >= limit )
852         break;
853
854       /* We stop when we find an `end' keyword or '>' */
855       if ( *cur   == 'e'          &&
856            cur + 3 < limit        &&
857            cur[1] == 'n'          &&
858            cur[2] == 'd'          &&
859            t42_is_space( cur[3] ) )
860         break;
861       if ( *cur == '>' )
862         break;
863
864       T1_Skip_PS_Token( parser );
865       if ( parser->root.cursor >= limit )
866       {
867         FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
868         error = FT_THROW( Invalid_File_Format );
869         goto Fail;
870       }
871       if ( parser->root.error )
872         return;
873
874       if ( *cur == '/' )
875       {
876         FT_PtrDist  len;
877
878
879         if ( cur + 2 >= limit )
880         {
881           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
882           error = FT_THROW( Invalid_File_Format );
883           goto Fail;
884         }
885
886         cur++;                              /* skip `/' */
887         len = parser->root.cursor - cur;
888
889         error = T1_Add_Table( name_table, n, cur, len + 1 );
890         if ( error )
891           goto Fail;
892
893         /* add a trailing zero to the name table */
894         name_table->elements[n][len] = '\0';
895
896         /* record index of /.notdef */
897         if ( *cur == '.'                                              &&
898              ft_strcmp( ".notdef",
899                         (const char*)(name_table->elements[n]) ) == 0 )
900         {
901           notdef_index = n;
902           notdef_found = 1;
903         }
904
905         T1_Skip_Spaces( parser );
906
907         cur = parser->root.cursor;
908
909         (void)T1_ToInt( parser );
910         if ( parser->root.cursor >= limit )
911         {
912           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
913           error = FT_THROW( Invalid_File_Format );
914           goto Fail;
915         }
916
917         len = parser->root.cursor - cur;
918
919         error = T1_Add_Table( code_table, n, cur, len + 1 );
920         if ( error )
921           goto Fail;
922
923         code_table->elements[n][len] = '\0';
924
925         n++;
926         if ( n >= loader->num_glyphs )
927           break;
928       }
929     }
930
931     loader->num_glyphs = n;
932
933     if ( !notdef_found )
934     {
935       FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
936       error = FT_THROW( Invalid_File_Format );
937       goto Fail;
938     }
939
940     /* if /.notdef does not occupy index 0, do our magic. */
941     if ( ft_strcmp( (const char*)".notdef",
942                     (const char*)name_table->elements[0] ) )
943     {
944       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
945       /* name and code entries to swap_table.  Then place notdef_index   */
946       /* name and code entries into swap_table.  Then swap name and code */
947       /* entries at indices notdef_index and 0 using values stored in    */
948       /* swap_table.                                                     */
949
950       /* Index 0 name */
951       error = T1_Add_Table( swap_table, 0,
952                             name_table->elements[0],
953                             name_table->lengths [0] );
954       if ( error )
955         goto Fail;
956
957       /* Index 0 code */
958       error = T1_Add_Table( swap_table, 1,
959                             code_table->elements[0],
960                             code_table->lengths [0] );
961       if ( error )
962         goto Fail;
963
964       /* Index notdef_index name */
965       error = T1_Add_Table( swap_table, 2,
966                             name_table->elements[notdef_index],
967                             name_table->lengths [notdef_index] );
968       if ( error )
969         goto Fail;
970
971       /* Index notdef_index code */
972       error = T1_Add_Table( swap_table, 3,
973                             code_table->elements[notdef_index],
974                             code_table->lengths [notdef_index] );
975       if ( error )
976         goto Fail;
977
978       error = T1_Add_Table( name_table, notdef_index,
979                             swap_table->elements[0],
980                             swap_table->lengths [0] );
981       if ( error )
982         goto Fail;
983
984       error = T1_Add_Table( code_table, notdef_index,
985                             swap_table->elements[1],
986                             swap_table->lengths [1] );
987       if ( error )
988         goto Fail;
989
990       error = T1_Add_Table( name_table, 0,
991                             swap_table->elements[2],
992                             swap_table->lengths [2] );
993       if ( error )
994         goto Fail;
995
996       error = T1_Add_Table( code_table, 0,
997                             swap_table->elements[3],
998                             swap_table->lengths [3] );
999       if ( error )
1000         goto Fail;
1001
1002     }
1003
1004     return;
1005
1006   Fail:
1007     parser->root.error = error;
1008   }
1009
1010
1011   static FT_Error
1012   t42_load_keyword( T42_Face    face,
1013                     T42_Loader  loader,
1014                     T1_Field    field )
1015   {
1016     FT_Error  error;
1017     void*     dummy_object;
1018     void**    objects;
1019     FT_UInt   max_objects = 0;
1020
1021
1022     /* if the keyword has a dedicated callback, call it */
1023     if ( field->type == T1_FIELD_TYPE_CALLBACK )
1024     {
1025       field->reader( (FT_Face)face, loader );
1026       error = loader->parser.root.error;
1027       goto Exit;
1028     }
1029
1030     /* now the keyword is either a simple field or a table of fields; */
1031     /* we are now going to take care of it                            */
1032
1033     switch ( field->location )
1034     {
1035     case T1_FIELD_LOCATION_FONT_INFO:
1036       dummy_object = &face->type1.font_info;
1037       break;
1038
1039     case T1_FIELD_LOCATION_FONT_EXTRA:
1040       dummy_object = &face->type1.font_extra;
1041       break;
1042
1043     case T1_FIELD_LOCATION_BBOX:
1044       dummy_object = &face->type1.font_bbox;
1045       break;
1046
1047     default:
1048       dummy_object = &face->type1;
1049     }
1050
1051     objects = &dummy_object;
1052
1053     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1054          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1055       error = T1_Load_Field_Table( &loader->parser, field,
1056                                    objects, max_objects, 0 );
1057     else
1058       error = T1_Load_Field( &loader->parser, field,
1059                              objects, max_objects, 0 );
1060
1061    Exit:
1062     return error;
1063   }
1064
1065
1066   FT_LOCAL_DEF( FT_Error )
1067   t42_parse_dict( T42_Face    face,
1068                   T42_Loader  loader,
1069                   FT_Byte*    base,
1070                   FT_Long     size )
1071   {
1072     T42_Parser  parser     = &loader->parser;
1073     FT_Byte*    limit;
1074     FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1075                                          sizeof ( t42_keywords[0] ) );
1076
1077
1078     parser->root.cursor = base;
1079     parser->root.limit  = base + size;
1080     parser->root.error  = FT_Err_Ok;
1081
1082     limit = parser->root.limit;
1083
1084     T1_Skip_Spaces( parser );
1085
1086     while ( parser->root.cursor < limit )
1087     {
1088       FT_Byte*  cur;
1089
1090
1091       cur = parser->root.cursor;
1092
1093       /* look for `FontDirectory' which causes problems for some fonts */
1094       if ( *cur == 'F' && cur + 25 < limit                    &&
1095            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1096       {
1097         FT_Byte*  cur2;
1098
1099
1100         /* skip the `FontDirectory' keyword */
1101         T1_Skip_PS_Token( parser );
1102         T1_Skip_Spaces  ( parser );
1103         cur = cur2 = parser->root.cursor;
1104
1105         /* look up the `known' keyword */
1106         while ( cur < limit )
1107         {
1108           if ( *cur == 'k' && cur + 5 < limit             &&
1109                 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1110             break;
1111
1112           T1_Skip_PS_Token( parser );
1113           if ( parser->root.error )
1114             goto Exit;
1115           T1_Skip_Spaces  ( parser );
1116           cur = parser->root.cursor;
1117         }
1118
1119         if ( cur < limit )
1120         {
1121           T1_TokenRec  token;
1122
1123
1124           /* skip the `known' keyword and the token following it */
1125           T1_Skip_PS_Token( parser );
1126           T1_ToToken( parser, &token );
1127
1128           /* if the last token was an array, skip it! */
1129           if ( token.type == T1_TOKEN_TYPE_ARRAY )
1130             cur2 = parser->root.cursor;
1131         }
1132         parser->root.cursor = cur2;
1133       }
1134
1135       /* look for immediates */
1136       else if ( *cur == '/' && cur + 2 < limit )
1137       {
1138         FT_PtrDist  len;
1139
1140
1141         cur++;
1142
1143         parser->root.cursor = cur;
1144         T1_Skip_PS_Token( parser );
1145         if ( parser->root.error )
1146           goto Exit;
1147
1148         len = parser->root.cursor - cur;
1149
1150         if ( len > 0 && len < 22 && parser->root.cursor < limit )
1151         {
1152           int  i;
1153
1154
1155           /* now compare the immediate name to the keyword table */
1156
1157           /* loop through all known keywords */
1158           for ( i = 0; i < n_keywords; i++ )
1159           {
1160             T1_Field  keyword = (T1_Field)&t42_keywords[i];
1161             FT_Byte   *name   = (FT_Byte*)keyword->ident;
1162
1163
1164             if ( !name )
1165               continue;
1166
1167             if ( cur[0] == name[0]                                  &&
1168                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
1169                  ft_memcmp( cur, name, len ) == 0                   )
1170             {
1171               /* we found it -- run the parsing callback! */
1172               parser->root.error = t42_load_keyword( face,
1173                                                      loader,
1174                                                      keyword );
1175               if ( parser->root.error )
1176                 return parser->root.error;
1177               break;
1178             }
1179           }
1180         }
1181       }
1182       else
1183       {
1184         T1_Skip_PS_Token( parser );
1185         if ( parser->root.error )
1186           goto Exit;
1187       }
1188
1189       T1_Skip_Spaces( parser );
1190     }
1191
1192   Exit:
1193     return parser->root.error;
1194   }
1195
1196
1197   FT_LOCAL_DEF( void )
1198   t42_loader_init( T42_Loader  loader,
1199                    T42_Face    face )
1200   {
1201     FT_UNUSED( face );
1202
1203     FT_MEM_ZERO( loader, sizeof ( *loader ) );
1204     loader->num_glyphs = 0;
1205     loader->num_chars  = 0;
1206
1207     /* initialize the tables -- simply set their `init' field to 0 */
1208     loader->encoding_table.init = 0;
1209     loader->charstrings.init    = 0;
1210     loader->glyph_names.init    = 0;
1211   }
1212
1213
1214   FT_LOCAL_DEF( void )
1215   t42_loader_done( T42_Loader  loader )
1216   {
1217     T42_Parser  parser = &loader->parser;
1218
1219
1220     /* finalize tables */
1221     T1_Release_Table( &loader->encoding_table );
1222     T1_Release_Table( &loader->charstrings );
1223     T1_Release_Table( &loader->glyph_names );
1224     T1_Release_Table( &loader->swap_table );
1225
1226     /* finalize parser */
1227     t42_parser_done( parser );
1228   }
1229
1230
1231 /* END */