8bb2e7ba6c556faa8e6baea6d6fa4216a7cb1c52
[reactos.git] / lib / freetype / src / type42 / t42parse.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  t42parse.c                                                             */
4 /*                                                                         */
5 /*    Type 42 font parser (body).                                          */
6 /*                                                                         */
7 /*  Copyright 2002 by Roberto Alameda.                                     */
8 /*                                                                         */
9 /*  This file is part of the FreeType project, and may only be used,       */
10 /*  modified, and distributed under the terms of the FreeType project      */
11 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
12 /*  this file you indicate that you have read the license and              */
13 /*  understand and accept it fully.                                        */
14 /*                                                                         */
15 /***************************************************************************/
16
17
18 #include "t42parse.h"
19 #include "t42error.h"
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_STREAM_H
22 #include FT_LIST_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_name( T42_Face    face,
38                        T42_Loader  loader );
39                        
40   static void
41   t42_parse_font_bbox( T42_Face    face,
42                        T42_Loader  loader );
43                        
44   static void
45   t42_parse_font_matrix( T42_Face    face,
46                          T42_Loader  loader );
47   static void
48   t42_parse_encoding( T42_Face    face,
49                       T42_Loader  loader );
50                       
51   static void
52   t42_parse_charstrings( T42_Face    face,
53                          T42_Loader  loader );
54                          
55   static void
56   t42_parse_sfnts( T42_Face    face,
57                    T42_Loader  loader );
58
59
60   static const
61   T1_FieldRec  t42_keywords[] = {
62
63 #undef  FT_STRUCTURE
64 #define FT_STRUCTURE  T1_FontInfo
65 #undef  T1CODE
66 #define T1CODE        T1_FIELD_LOCATION_FONT_INFO
67
68     T1_FIELD_STRING   ( "version",            version )
69     T1_FIELD_STRING   ( "Notice",             notice )
70     T1_FIELD_STRING   ( "FullName",           full_name )
71     T1_FIELD_STRING   ( "FamilyName",         family_name )
72     T1_FIELD_STRING   ( "Weight",             weight )
73     T1_FIELD_NUM      ( "ItalicAngle",        italic_angle )
74     T1_FIELD_TYPE_BOOL( "isFixedPitch",       is_fixed_pitch )
75     T1_FIELD_NUM      ( "UnderlinePosition",  underline_position )
76     T1_FIELD_NUM      ( "UnderlineThickness", underline_thickness )
77
78 #undef  FT_STRUCTURE
79 #define FT_STRUCTURE  T1_FontRec
80 #undef  T1CODE
81 #define T1CODE        T1_FIELD_LOCATION_FONT_DICT
82
83     T1_FIELD_NUM( "PaintType",   paint_type )
84     T1_FIELD_NUM( "FontType",    font_type )
85     T1_FIELD_NUM( "StrokeWidth", stroke_width )
86
87     T1_FIELD_CALLBACK( "FontName",    t42_parse_font_name )
88     T1_FIELD_CALLBACK( "FontBBox",    t42_parse_font_bbox )
89     T1_FIELD_CALLBACK( "FontMatrix",  t42_parse_font_matrix )
90     T1_FIELD_CALLBACK( "Encoding",    t42_parse_encoding )
91     T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings )
92     T1_FIELD_CALLBACK( "sfnts",       t42_parse_sfnts )
93
94     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
95   };
96
97
98 #define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
99 #define T1_Done_Table( p )          \
100           do                        \
101           {                         \
102             if ( (p)->funcs.done )  \
103               (p)->funcs.done( p ); \
104           } while ( 0 )
105 #define T1_Release_Table( p )          \
106           do                           \
107           {                            \
108             if ( (p)->funcs.release )  \
109               (p)->funcs.release( p ); \
110           } while ( 0 )
111
112 #define T1_Skip_Spaces( p )  (p)->root.funcs.skip_spaces( &(p)->root )
113 #define T1_Skip_Alpha( p )   (p)->root.funcs.skip_alpha ( &(p)->root )
114
115 #define T1_ToInt( p )       (p)->root.funcs.to_int( &(p)->root )
116 #define T1_ToFixed( p, t )  (p)->root.funcs.to_fixed( &(p)->root, t )
117
118 #define T1_ToCoordArray( p, m, c )                           \
119           (p)->root.funcs.to_coord_array( &(p)->root, m, c )
120 #define T1_ToFixedArray( p, m, f, t )                           \
121           (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
122 #define T1_ToToken( p, t )                          \
123           (p)->root.funcs.to_token( &(p)->root, t )
124 #define T1_ToTokenArray( p, t, m, c )                           \
125           (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
126
127 #define T1_Load_Field( p, f, o, m, pf )                         \
128           (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
129 #define T1_Load_Field_Table( p, f, o, m, pf )                         \
130           (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
131
132
133   /********************* Parsing Functions ******************/
134
135   FT_LOCAL_DEF( FT_Error )
136   t42_parser_init( T42_Parser     parser,
137                    FT_Stream      stream,
138                    FT_Memory      memory,
139                    PSAux_Service  psaux )
140   {
141     FT_Error  error = T42_Err_Ok;
142     FT_Long   size;
143
144
145     psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
146
147     parser->stream    = stream;
148     parser->base_len  = 0;
149     parser->base_dict = 0;
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 setup pointers in */
160     /*   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       goto Exit;
168
169     size = stream->size;
170
171     /* now, try to load `size' bytes of the `base' dictionary we */
172     /* found previously                                          */
173
174     /* if it is a memory-based resource, set up pointers */
175     if ( !stream->read )
176     {
177       parser->base_dict = (FT_Byte*)stream->base + stream->pos;
178       parser->base_len  = size;
179       parser->in_memory = 1;
180
181       /* check that the `size' field is valid */
182       if ( FT_STREAM_SKIP( size ) )
183         goto Exit;
184     }
185     else
186     {
187       /* read segment in memory */
188       if ( FT_ALLOC( parser->base_dict, size )       ||
189            FT_STREAM_READ( parser->base_dict, size ) )
190         goto Exit;
191
192       parser->base_len = size;
193     }
194
195     /* Now check font format; we must see `%!PS-TrueTypeFont' */
196     if (size <= 17                                    ||
197         ( ft_strncmp( (const char*)parser->base_dict,
198                       "%!PS-TrueTypeFont", 17) )      )
199       error = T42_Err_Unknown_File_Format;
200     else
201     {
202       parser->root.base   = parser->base_dict;
203       parser->root.cursor = parser->base_dict;
204       parser->root.limit  = parser->root.cursor + parser->base_len;
205     }
206
207   Exit:
208     if ( error && !parser->in_memory )
209       FT_FREE( parser->base_dict );
210
211     return error;
212   }
213
214
215   FT_LOCAL_DEF( void )
216   t42_parser_done( T42_Parser  parser )
217   {
218     FT_Memory  memory = parser->root.memory;
219
220
221     /* free the base dictionary only when we have a disk stream */
222     if ( !parser->in_memory )
223       FT_FREE( parser->base_dict );
224
225     parser->root.funcs.done( &parser->root );
226   }
227
228
229   static int
230   t42_is_alpha( FT_Byte  c )
231   {
232     /* Note: we must accept "+" as a valid character, as it is used in */
233     /*       embedded type1 fonts in PDF documents.                    */
234     /*                                                                 */
235     return ( ft_isalnum( c ) ||
236              c == '.'        ||
237              c == '_'        ||
238              c == '-'        ||
239              c == '+'        );
240   }
241
242
243   static int
244   t42_is_space( FT_Byte  c )
245   {
246     return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
247   }
248
249
250   static void
251   t42_parse_font_name( T42_Face    face,
252                        T42_Loader  loader )
253   {
254     T42_Parser  parser = &loader->parser;
255     FT_Error    error;
256     FT_Memory   memory = parser->root.memory;
257     FT_Int      len;
258     FT_Byte*    cur;
259     FT_Byte*    cur2;
260     FT_Byte*    limit;
261
262
263     T1_Skip_Spaces( parser );
264
265     cur   = parser->root.cursor;
266     limit = parser->root.limit;
267
268     if ( cur >= limit - 1              ||
269          ( *cur != '/' && *cur != '(') )
270       return;
271
272     cur++;
273     cur2 = cur;
274     while ( cur2 < limit && t42_is_alpha( *cur2 ) )
275       cur2++;
276
277     len = (FT_Int)( cur2 - cur );
278     if ( len > 0 )
279     {
280       if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
281       {
282         parser->root.error = error;
283         return;
284       }
285
286       FT_MEM_COPY( face->type1.font_name, cur, len );
287       face->type1.font_name[len] = '\0';
288     }
289     parser->root.cursor = cur2;
290   }
291
292
293   static void
294   t42_parse_font_bbox( T42_Face   face,
295                        T42_Loader  loader )
296   {
297     T42_Parser  parser = &loader->parser;
298     FT_BBox*    bbox   = &face->type1.font_bbox;
299
300     bbox->xMin = T1_ToInt( parser );
301     bbox->yMin = T1_ToInt( parser );
302     bbox->xMax = T1_ToInt( parser );
303     bbox->yMax = T1_ToInt( parser );
304   }
305
306
307   static void
308   t42_parse_font_matrix( T42_Face    face,
309                          T42_Loader  loader )
310   {
311     T42_Parser  parser = &loader->parser;
312     FT_Matrix*  matrix = &face->type1.font_matrix;
313     FT_Vector*  offset = &face->type1.font_offset;
314     FT_Face     root   = (FT_Face)&face->root;
315     FT_Fixed    temp[6];
316     FT_Fixed    temp_scale;
317
318
319     (void)T1_ToFixedArray( parser, 6, temp, 3 );
320
321     temp_scale = ABS( temp[3] );
322
323     /* Set Units per EM based on FontMatrix values.  We set the value to */
324     /* 1000 / temp_scale, because temp_scale was already multiplied by   */
325     /* 1000 (in t1_tofixed, from psobjs.c).                              */
326
327     root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
328                                                  temp_scale ) >> 16 );
329
330     /* we need to scale the values by 1.0/temp_scale */
331     if ( temp_scale != 0x10000L ) {
332       temp[0] = FT_DivFix( temp[0], temp_scale );
333       temp[1] = FT_DivFix( temp[1], temp_scale );
334       temp[2] = FT_DivFix( temp[2], temp_scale );
335       temp[4] = FT_DivFix( temp[4], temp_scale );
336       temp[5] = FT_DivFix( temp[5], temp_scale );
337       temp[3] = 0x10000L;
338     }
339
340     matrix->xx = temp[0];
341     matrix->yx = temp[1];
342     matrix->xy = temp[2];
343     matrix->yy = temp[3];
344
345     /* note that the offsets must be expressed in integer font units */
346     offset->x  = temp[4] >> 16;
347     offset->y  = temp[5] >> 16;
348   }
349
350
351   static void
352   t42_parse_encoding( T42_Face    face,
353                       T42_Loader  loader )
354   {
355     T42_Parser     parser = &loader->parser;
356     FT_Byte*       cur    = parser->root.cursor;
357     FT_Byte*       limit  = parser->root.limit;
358
359     PSAux_Service  psaux  = (PSAux_Service)face->psaux;
360
361
362     /* skip whitespace */
363     while ( t42_is_space( *cur ) )
364     {
365       cur++;
366       if ( cur >= limit )
367       {
368         FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
369         parser->root.error = T42_Err_Invalid_File_Format;
370         return;
371       }
372     }
373
374     /* if we have a number, then the encoding is an array, */
375     /* and we must load it now                             */
376     if ( (FT_Byte)( *cur - '0' ) < 10 )
377     {
378       T1_Encoding  encode     = &face->type1.encoding;
379       FT_Int       count, n;
380       PS_Table     char_table = &loader->encoding_table;
381       FT_Memory    memory     = parser->root.memory;
382       FT_Error     error;
383
384
385       /* read the number of entries in the encoding, should be 256 */
386       count = T1_ToInt( parser );
387       if ( parser->root.error )
388         return;
389
390       /* we use a T1_Table to store our charnames */
391       loader->num_chars = encode->num_chars = count;
392       if ( FT_NEW_ARRAY( encode->char_index, count ) ||
393            FT_NEW_ARRAY( encode->char_name,  count ) ||
394            FT_SET_ERROR( psaux->ps_table_funcs->init(
395                            char_table, count, memory ) ) )
396       {
397         parser->root.error = error;
398         return;
399       }
400
401       /* We need to `zero' out encoding_table.elements */
402       for ( n = 0; n < count; n++ )
403       {
404         char*  notdef = (char *)".notdef";
405
406
407         T1_Add_Table( char_table, n, notdef, 8 );
408       }
409
410       /* Now, we will need to read a record of the form         */
411       /* ... charcode /charname ... for each entry in our table */
412       /*                                                        */
413       /* We simply look for a number followed by an immediate   */
414       /* name.  Note that this ignores correctly the sequence   */
415       /* that is often seen in type1 fonts:                     */
416       /*                                                        */
417       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
418       /*                                                        */
419       /* used to clean the encoding array before anything else. */
420       /*                                                        */
421       /* We stop when we encounter a `def'.                     */
422
423       cur   = parser->root.cursor;
424       limit = parser->root.limit;
425       n     = 0;
426
427       for ( ; cur < limit; )
428       {
429         FT_Byte  c;
430
431
432         c = *cur;
433
434         /* we stop when we encounter a `def' */
435         if ( c == 'd' && cur + 3 < limit )
436         {
437           if ( cur[1] == 'e'       &&
438                cur[2] == 'f'       &&
439                t42_is_space( cur[-1] ) &&
440                t42_is_space( cur[3] )  )
441           {
442             FT_TRACE6(( "encoding end\n" ));
443             break;
444           }
445         }
446
447         /* otherwise, we must find a number before anything else */
448         if ( (FT_Byte)( c - '0' ) < 10 )
449         {
450           FT_Int  charcode;
451
452
453           parser->root.cursor = cur;
454           charcode = T1_ToInt( parser );
455           cur      = parser->root.cursor;
456
457           /* skip whitespace */
458           while ( cur < limit && t42_is_space( *cur ) )
459             cur++;
460
461           if ( cur < limit && *cur == '/' )
462           {
463             /* bingo, we have an immediate name -- it must be a */
464             /* character name                                   */
465             FT_Byte*  cur2 = cur + 1;
466             FT_Int    len;
467
468
469             while ( cur2 < limit && t42_is_alpha( *cur2 ) )
470               cur2++;
471
472             len = (FT_Int)( cur2 - cur - 1 );
473
474             parser->root.error = T1_Add_Table( char_table, charcode,
475                                                cur + 1, len + 1 );
476             char_table->elements[charcode][len] = '\0';
477             if ( parser->root.error )
478               return;
479
480             cur = cur2;
481           }
482         }
483         else
484           cur++;
485       }
486
487       face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
488       parser->root.cursor        = cur;
489     }
490     /* Otherwise, we should have either `StandardEncoding', */
491     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
492     else
493     {
494       if ( cur + 17 < limit                                            &&
495            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
496         face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
497
498       else if ( cur + 15 < limit                                          &&
499                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
500         face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
501
502       else if ( cur + 18 < limit                                             &&
503                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
504         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
505
506       else {
507         FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
508         parser->root.error = T42_Err_Invalid_File_Format;
509       }
510     }
511   }
512
513
514   static FT_UInt
515   t42_hexval( FT_Byte  v )
516   {
517     FT_UInt  d;
518     
519     d = (FT_UInt)( v - 'A' );
520     if ( d < 6 )
521     {
522       d += 10;
523       goto Exit;
524     }
525       
526     d = (FT_UInt)( v - 'a' );
527     if ( d < 6 )
528     {
529       d += 10;
530       goto Exit;
531     }
532       
533     d = (FT_UInt)( v - '0' );
534     if ( d < 10 )
535       goto Exit;
536       
537     d = 0;
538  
539   Exit:         
540     return d;
541   }
542
543
544   static void
545   t42_parse_sfnts( T42_Face    face,
546                    T42_Loader  loader )
547   {
548     T42_Parser  parser = &loader->parser;
549     FT_Memory   memory = parser->root.memory;
550     FT_Byte*    cur    = parser->root.cursor;
551     FT_Byte*    limit  = parser->root.limit;
552     FT_Error    error;
553     FT_Int      num_tables = 0, status;
554     FT_ULong    count, ttf_size = 0, string_size = 0;
555     FT_Bool     in_string  = 0;
556     FT_Byte     v = 0;
557
558
559     /* The format is `/sfnts [ <...> <...> ... ] def' */
560
561     while ( t42_is_space( *cur ) )
562       cur++;
563
564     if (*cur++ == '[')
565     {
566       status = 0;
567       count = 0;
568     }
569     else
570     {
571       FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
572       error = T42_Err_Invalid_File_Format;
573       goto Fail;
574     }
575
576     while ( cur < limit - 2 )
577     {
578       while ( t42_is_space( *cur ) )
579         cur++;
580
581       switch ( *cur )
582       {
583       case ']':
584         parser->root.cursor = cur++;
585         return;
586
587       case '<':
588         in_string   = 1;
589         string_size = 0;
590         cur++;
591         continue;
592
593       case '>':
594         if ( !in_string )
595         {
596           FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" ));
597           error = T42_Err_Invalid_File_Format;
598           goto Fail;
599         }
600
601         /* A string can have, as a last byte,         */
602         /* a zero byte for padding.  If so, ignore it */
603         if ( ( v == 0 ) && ( string_size % 2 == 1 ) )
604           count--;
605         in_string = 0;
606         cur++;
607         continue;
608
609       case '%':
610         if ( !in_string )
611         {
612           /* Comment found; skip till end of line */
613           while ( *cur != '\n' )
614             cur++;
615           continue;
616         }
617         else
618         {
619           FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" ));
620           error = T42_Err_Invalid_File_Format;
621           goto Fail;
622         }
623
624       default:
625         if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) )
626         {
627           FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" ));
628           error = T42_Err_Invalid_File_Format;
629           goto Fail;
630         }
631
632         v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) );
633         cur += 2;
634         string_size++;
635       }
636
637       switch ( status )
638       {
639       case 0: /* The '[' was read, so load offset table, 12 bytes */
640         if ( count < 12 )
641         {
642           face->ttf_data[count++] = v;
643           continue;
644         }
645         else
646         {
647           num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
648           status     = 1;
649           ttf_size   = 12 + 16 * num_tables;
650
651           if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
652             goto Fail;
653         }
654         /* No break, fall-through */
655
656       case 1: /* The offset table is read; read now the table directory */
657         if ( count < ttf_size )
658         {
659           face->ttf_data[count++] = v;
660           continue;
661         }
662         else
663         {
664           int      i;
665           FT_ULong len;
666
667
668           for ( i = 0; i < num_tables; i++ )
669           {
670             FT_Byte*  p = face->ttf_data + 12 + 16*i + 12;
671             
672             len = FT_PEEK_ULONG( p );
673
674             /* Pad to a 4-byte boundary length */
675             ttf_size += ( len + 3 ) & ~3;
676           }
677
678           status         = 2;
679           face->ttf_size = ttf_size;
680
681           if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
682                            ttf_size + 1 ) )
683             goto Fail;
684         }
685         /* No break, fall-through */
686
687       case 2: /* We are reading normal tables; just swallow them */
688         face->ttf_data[count++] = v;
689
690       }
691     }
692
693     /* If control reaches this point, the format was not valid */
694     error = T42_Err_Invalid_File_Format;
695
696   Fail:
697     parser->root.error = error;
698   }
699
700
701   static void
702   t42_parse_charstrings( T42_Face    face,
703                          T42_Loader  loader )
704   {
705     T42_Parser     parser     = &loader->parser;
706     PS_Table       code_table = &loader->charstrings;
707     PS_Table       name_table = &loader->glyph_names;
708     FT_Memory      memory     = parser->root.memory;
709     FT_Error       error;
710
711     PSAux_Service  psaux      = (PSAux_Service)face->psaux;
712
713     FT_Byte*       cur;
714     FT_Byte*       limit      = parser->root.limit;
715     FT_Int         n;
716
717
718     loader->num_glyphs = T1_ToInt( parser );
719     if ( parser->root.error )
720       return;
721
722     /* initialize tables */
723
724     error = psaux->ps_table_funcs->init( code_table,
725                                          loader->num_glyphs,
726                                          memory );
727     if ( error )
728       goto Fail;
729
730     error = psaux->ps_table_funcs->init( name_table,
731                                          loader->num_glyphs,
732                                          memory );
733     if ( error )
734       goto Fail;
735
736     n = 0;
737
738     for (;;)
739     {
740       /* the format is simple:                    */
741       /*   `/glyphname' + index + def             */
742       /*                                          */
743       /* note that we stop when we find an `end'  */
744       /*                                          */
745       T1_Skip_Spaces( parser );
746
747       cur = parser->root.cursor;
748       if ( cur >= limit )
749         break;
750
751       /* we stop when we find an `end' keyword */
752       if ( *cur   == 'e'   &&
753            cur + 3 < limit &&
754            cur[1] == 'n'   &&
755            cur[2] == 'd'   )
756         break;
757
758       if ( *cur != '/' )
759         T1_Skip_Alpha( parser );
760       else
761       {
762         FT_Byte*  cur2 = cur + 1;
763         FT_Int    len;
764
765
766         while ( cur2 < limit && t42_is_alpha( *cur2 ) )
767           cur2++;
768         len = (FT_Int)( cur2 - cur - 1 );
769
770         error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
771         if ( error )
772           goto Fail;
773
774         /* add a trailing zero to the name table */
775         name_table->elements[n][len] = '\0';
776
777         parser->root.cursor = cur2;
778         T1_Skip_Spaces( parser );
779
780         cur2 = cur = parser->root.cursor;
781         if ( cur >= limit )
782           break;
783
784         while ( cur2 < limit && t42_is_alpha( *cur2 ) )
785           cur2++;
786         len = (FT_Int)( cur2 - cur );
787
788         error = T1_Add_Table( code_table, n, cur, len + 1 );
789         if ( error )
790           goto Fail;
791
792         code_table->elements[n][len] = '\0';
793
794         n++;
795         if ( n >= loader->num_glyphs )
796           break;
797       }
798     }
799
800     /* Index 0 must be a .notdef element */
801     if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) )
802     {
803       FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" ));
804       error = T42_Err_Invalid_File_Format;
805       goto Fail;
806     }
807
808     loader->num_glyphs = n;
809     return;
810
811   Fail:
812     parser->root.error = error;
813   }
814
815
816   static FT_Error
817   t42_load_keyword( T42_Face    face,
818                     T42_Loader  loader,
819                     T1_Field    field )
820   {
821     FT_Error  error;
822     void*     dummy_object;
823     void**    objects;
824     FT_UInt   max_objects = 0;
825
826
827     /* if the keyword has a dedicated callback, call it */
828     if ( field->type == T1_FIELD_TYPE_CALLBACK ) {
829       field->reader( (FT_Face)face, loader );
830       error = loader->parser.root.error;
831       goto Exit;
832     }
833
834     /* now, the keyword is either a simple field, or a table of fields; */
835     /* we are now going to take care of it                              */
836     switch ( field->location )
837     {
838     case T1_FIELD_LOCATION_FONT_INFO:
839       dummy_object = &face->type1.font_info;
840       objects      = &dummy_object;
841       break;
842
843     default:
844       dummy_object = &face->type1;
845       objects      = &dummy_object;
846     }
847
848     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
849          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
850       error = T1_Load_Field_Table( &loader->parser, field,
851                                    objects, max_objects, 0 );
852     else
853       error = T1_Load_Field( &loader->parser, field,
854                              objects, max_objects, 0 );
855
856    Exit:
857     return error;
858   }
859
860
861   FT_LOCAL_DEF( FT_Error )
862   t42_parse_dict( T42_Face    face,
863                   T42_Loader  loader,
864                   FT_Byte*    base,
865                   FT_Long     size )
866   {
867     T42_Parser  parser = &loader->parser;
868     FT_Byte*    cur    = base;
869     FT_Byte*    limit  = cur + size;
870     FT_UInt     n_keywords = sizeof ( t42_keywords ) / 
871                              sizeof ( t42_keywords[0] );
872
873
874     parser->root.cursor = base;
875     parser->root.limit  = base + size;
876     parser->root.error  = 0;
877
878     for ( ; cur < limit; cur++ )
879     {
880       /* look for `FontDirectory', which causes problems on some fonts */
881       if ( *cur == 'F' && cur + 25 < limit                    &&
882            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
883       {
884         FT_Byte*  cur2;
885
886
887         /* skip the `FontDirectory' keyword */
888         cur += 13;
889         cur2 = cur;
890
891         /* lookup the `known' keyword */
892         while ( cur < limit && *cur != 'k'           &&
893                 ft_strncmp( (char*)cur, "known", 5 ) )
894           cur++;
895
896         if ( cur < limit )
897         {
898           T1_TokenRec  token;
899
900
901           /* skip the `known' keyword and the token following it */
902           cur += 5;
903           loader->parser.root.cursor = cur;
904           T1_ToToken( &loader->parser, &token );
905
906           /* if the last token was an array, skip it! */
907           if ( token.type == T1_TOKEN_TYPE_ARRAY )
908             cur2 = parser->root.cursor;
909         }
910         cur = cur2;
911       }
912       /* look for immediates */
913       else if ( *cur == '/' && cur + 2 < limit )
914       {
915         FT_Byte*  cur2;
916         FT_UInt    i, len;
917
918
919         cur++;
920         cur2 = cur;
921         while ( cur2 < limit && t42_is_alpha( *cur2 ) )
922           cur2++;
923
924         len  = (FT_UInt)( cur2 - cur );
925         if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */
926         {
927           /* now, compare the immediate name to the keyword table */
928
929           /* Loop through all known keywords */
930           for ( i = 0; i < n_keywords; i++ )
931           {
932             T1_Field  keyword = (T1_Field)&t42_keywords[i];
933             FT_Byte   *name   = (FT_Byte*)keyword->ident;
934
935
936             if ( !name )
937               continue;
938
939             if ( ( len == ft_strlen( (const char *)name ) ) &&
940                  ( ft_memcmp( cur, name, len ) == 0 )       )
941             {
942               /* we found it -- run the parsing callback! */
943               parser->root.cursor = cur2;
944               T1_Skip_Spaces( parser );
945               parser->root.error = t42_load_keyword(face,
946                                                     loader,
947                                                     keyword );
948               if ( parser->root.error )
949                 return parser->root.error;
950               cur = parser->root.cursor;
951               break;
952             }
953           }
954         }
955       }
956     }
957     return parser->root.error;
958   }
959
960
961   FT_LOCAL_DEF( void )
962   t42_loader_init( T42_Loader  loader,
963                    T42_Face    face )
964   {
965     FT_UNUSED( face );
966
967     FT_MEM_ZERO( loader, sizeof ( *loader ) );
968     loader->num_glyphs = 0;
969     loader->num_chars  = 0;
970
971     /* initialize the tables -- simply set their `init' field to 0 */
972     loader->encoding_table.init = 0;
973     loader->charstrings.init    = 0;
974     loader->glyph_names.init    = 0;
975   }
976
977
978   FT_LOCAL_DEF( void )
979   t42_loader_done( T42_Loader  loader )
980   {
981     T42_Parser  parser = &loader->parser;
982
983
984     /* finalize tables */
985     T1_Release_Table( &loader->encoding_table );
986     T1_Release_Table( &loader->charstrings );
987     T1_Release_Table( &loader->glyph_names );
988
989     /* finalize parser */
990     t42_parser_done( parser );
991   }
992
993
994 /* END */