The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / t1load.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  t1load.c                                                               */
4 /*                                                                         */
5 /*    Type 1 font loader (body).                                           */
6 /*                                                                         */
7 /*  Copyright 1996-2001 by                                                 */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
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   /*************************************************************************/
20   /*                                                                       */
21   /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
22   /* old loader has several problems: it is slow, complex, difficult to    */
23   /* maintain, and contains incredible hacks to make it accept some        */
24   /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
25   /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
26   /*                                                                       */
27   /* This version is much simpler, much faster and also easier to read and */
28   /* maintain by a great order of magnitude.  The idea behind it is to     */
29   /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
30   /* a Postscript-like interpreter) but rather to perform simple pattern   */
31   /* matching.                                                             */
32   /*                                                                       */
33   /* Indeed, nearly all data definitions follow a simple pattern like      */
34   /*                                                                       */
35   /*  ... /Field <data> ...                                                */
36   /*                                                                       */
37   /* where <data> can be a number, a boolean, a string, or an array of     */
38   /* numbers.  There are a few exceptions, namely the encoding, font name, */
39   /* charstrings, and subrs; they are handled with a special pattern       */
40   /* matching routine.                                                     */
41   /*                                                                       */
42   /* All other common cases are handled very simply.  The matching rules   */
43   /* are defined in the file `t1tokens.h' through the use of several       */
44   /* macros calls PARSE_XXX.                                               */
45   /*                                                                       */
46   /* This file is included twice here; the first time to generate parsing  */
47   /* callback functions, the second to generate a table of keywords (with  */
48   /* pointers to the associated callback).                                 */
49   /*                                                                       */
50   /* The function `parse_dict' simply scans *linearly* a given dictionary  */
51   /* (either the top-level or private one) and calls the appropriate       */
52   /* callback when it encounters an immediate keyword.                     */
53   /*                                                                       */
54   /* This is by far the fastest way one can find to parse and read all     */
55   /* data.                                                                 */
56   /*                                                                       */
57   /* This led to tremendous code size reduction.  Note that later, the     */
58   /* glyph loader will also be _greatly_ simplified, and the automatic     */
59   /* hinter will replace the clumsy `t1hinter'.                            */
60   /*                                                                       */
61   /*************************************************************************/
62
63
64 #include <ft2build.h>
65 #include FT_INTERNAL_DEBUG_H
66 #include FT_CONFIG_CONFIG_H
67 #include FT_MULTIPLE_MASTERS_H
68 #include FT_INTERNAL_TYPE1_TYPES_H
69
70 #include "t1load.h"
71
72 #include "t1errors.h"
73
74 #include <string.h>     /* for strncmp(), strcmp() */
75 #include <ctype.h>      /* for isalnum()           */
76
77
78   /*************************************************************************/
79   /*                                                                       */
80   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
81   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
82   /* messages during execution.                                            */
83   /*                                                                       */
84 #undef  FT_COMPONENT
85 #define FT_COMPONENT  trace_t1load
86
87
88 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
89
90
91   /*************************************************************************/
92   /*************************************************************************/
93   /*****                                                               *****/
94   /*****                    MULTIPLE MASTERS SUPPORT                   *****/
95   /*****                                                               *****/
96   /*************************************************************************/
97   /*************************************************************************/
98
99   static FT_Error
100   t1_allocate_blend( T1_Face  face,
101                      FT_UInt  num_designs,
102                      FT_UInt  num_axis )
103   {
104     T1_Blend*  blend;
105     FT_Memory  memory = face->root.memory;
106     FT_Error   error  = 0;
107
108
109     blend = face->blend;
110     if ( !blend )
111     {
112       if ( ALLOC( blend, sizeof ( *blend ) ) )
113         goto Exit;
114
115       face->blend = blend;
116     }
117
118     /* allocate design data if needed */
119     if ( num_designs > 0 )
120     {
121       if ( blend->num_designs == 0 )
122       {
123         FT_UInt  nn;
124
125
126         /* allocate the blend `private' and `font_info' dictionaries */
127         if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo )  ||
128              ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private )     ||
129              ALLOC_ARRAY( blend->weight_vector, num_designs * 2, FT_Fixed ) )
130           goto Exit;
131
132         blend->default_weight_vector = blend->weight_vector + num_designs;
133
134         blend->font_infos[0] = &face->type1.font_info;
135         blend->privates  [0] = &face->type1.private_dict;
136
137         for ( nn = 2; nn <= num_designs; nn++ )
138         {
139           blend->privates[nn]   = blend->privates  [nn - 1] + 1;
140           blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
141         }
142
143         blend->num_designs   = num_designs;
144       }
145       else if ( blend->num_designs != num_designs )
146         goto Fail;
147     }
148
149     /* allocate axis data if needed */
150     if ( num_axis > 0 )
151     {
152       if ( blend->num_axis != 0 && blend->num_axis != num_axis )
153         goto Fail;
154
155       blend->num_axis = num_axis;
156     }
157
158     /* allocate the blend design pos table if needed */
159     num_designs = blend->num_designs;
160     num_axis    = blend->num_axis;
161     if ( num_designs && num_axis && blend->design_pos[0] == 0 )
162     {
163       FT_UInt  n;
164
165
166       if ( ALLOC_ARRAY( blend->design_pos[0],
167                         num_designs * num_axis, FT_Fixed ) )
168         goto Exit;
169
170       for ( n = 1; n < num_designs; n++ )
171         blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
172     }
173
174   Exit:
175     return error;
176
177   Fail:
178     error = -1;
179     goto Exit;
180   }
181
182
183   FT_LOCAL_DEF FT_Error
184   T1_Get_Multi_Master( T1_Face           face,
185                        FT_Multi_Master*  master )
186   {
187     T1_Blend*  blend = face->blend;
188     FT_UInt    n;
189     FT_Error   error;
190
191
192     error = T1_Err_Invalid_Argument;
193
194     if ( blend )
195     {
196       master->num_axis    = blend->num_axis;
197       master->num_designs = blend->num_designs;
198
199       for ( n = 0; n < blend->num_axis; n++ )
200       {
201         FT_MM_Axis*    axis = master->axis + n;
202         T1_DesignMap*  map = blend->design_map + n;
203
204
205         axis->name    = blend->axis_names[n];
206         axis->minimum = map->design_points[0];
207         axis->maximum = map->design_points[map->num_points - 1];
208       }
209       error = 0;
210     }
211     return error;
212   }
213
214
215   FT_LOCAL_DEF FT_Error
216   T1_Set_MM_Blend( T1_Face    face,
217                    FT_UInt    num_coords,
218                    FT_Fixed*  coords )
219   {
220     T1_Blend*  blend = face->blend;
221     FT_Error   error;
222     FT_UInt    n, m;
223
224
225     error = T1_Err_Invalid_Argument;
226
227     if ( blend && blend->num_axis == num_coords )
228     {
229       /* recompute the weight vector from the blend coordinates */
230       error = T1_Err_Ok;
231
232       for ( n = 0; n < blend->num_designs; n++ )
233       {
234         FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
235
236
237         for ( m = 0; m < blend->num_axis; m++ )
238         {
239           FT_Fixed  factor;
240
241
242           /* get current blend axis position */
243           factor = coords[m];
244           if ( factor < 0 )        factor = 0;
245           if ( factor > 0x10000L ) factor = 0x10000L;
246
247           if ( ( n & ( 1 << m ) ) == 0 )
248             factor = 0x10000L - factor;
249
250           result = FT_MulFix( result, factor );
251         }
252         blend->weight_vector[n] = result;
253       }
254
255       error = T1_Err_Ok;
256     }
257     return error;
258   }
259
260
261   FT_LOCAL_DEF FT_Error
262   T1_Set_MM_Design( T1_Face   face,
263                     FT_UInt   num_coords,
264                     FT_Long*  coords )
265   {
266     T1_Blend*  blend = face->blend;
267     FT_Error   error;
268     FT_UInt    n, p;
269
270
271     error = T1_Err_Invalid_Argument;
272     if ( blend && blend->num_axis == num_coords )
273     {
274       /* compute the blend coordinates through the blend design map */
275       FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
276
277
278       for ( n = 0; n < blend->num_axis; n++ )
279       {
280         FT_Long        design  = coords[n];
281         FT_Fixed       the_blend;
282         T1_DesignMap*  map     = blend->design_map + n;
283         FT_Fixed*      designs = map->design_points;
284         FT_Fixed*      blends  = map->blend_points;
285         FT_Int         before  = -1, after = -1;
286
287         for ( p = 0; p < (FT_UInt)map->num_points; p++ )
288         {
289           FT_Fixed  p_design = designs[p];
290
291
292           /* exact match ? */
293           if ( design == p_design )
294           {
295             the_blend = blends[p];
296             goto Found;
297           }
298
299           if ( design < p_design )
300           {
301             after = p;
302             break;
303           }
304
305           before = p;
306         }
307
308         /* now, interpolate if needed */
309         if ( before < 0 )
310           the_blend = blends[0];
311
312         else if ( after < 0 )
313           the_blend = blends[map->num_points - 1];
314
315         else
316           the_blend = FT_MulDiv( design         - designs[before],
317                                  blends [after] - blends [before],
318                                  designs[after] - designs[before] );
319
320       Found:
321         final_blends[n] = the_blend;
322       }
323
324       error = T1_Set_MM_Blend( face, num_coords, final_blends );
325     }
326
327     return error;
328   }
329
330
331   FT_LOCAL_DEF void
332   T1_Done_Blend( T1_Face  face )
333   {
334     FT_Memory  memory = face->root.memory;
335     T1_Blend*  blend  = face->blend;
336
337
338     if ( blend )
339     {
340       FT_UInt  num_designs = blend->num_designs;
341       FT_UInt  num_axis    = blend->num_axis;
342       FT_UInt  n;
343
344
345       /* release design pos table */
346       FREE( blend->design_pos[0] );
347       for ( n = 1; n < num_designs; n++ )
348         blend->design_pos[n] = 0;
349
350       /* release blend `private' and `font info' dictionaries */
351       FREE( blend->privates[1] );
352       FREE( blend->font_infos[1] );
353
354       for ( n = 0; n < num_designs; n++ )
355       {
356         blend->privates  [n] = 0;
357         blend->font_infos[n] = 0;
358       }
359
360       /* release weight vectors */
361       FREE( blend->weight_vector );
362       blend->default_weight_vector = 0;
363
364       /* release axis names */
365       for ( n = 0; n < num_axis; n++ )
366         FREE( blend->axis_names[n] );
367
368       /* release design map */
369       for ( n = 0; n < num_axis; n++ )
370       {
371         T1_DesignMap*  dmap = blend->design_map + n;
372
373
374         FREE( dmap->design_points );
375         dmap->num_points = 0;
376       }
377
378       FREE( face->blend );
379     }
380   }
381
382
383   static void
384   parse_blend_axis_types( T1_Face     face,
385                           T1_Loader*  loader )
386   {
387     T1_Token   axis_tokens[ T1_MAX_MM_AXIS ];
388     FT_Int     n, num_axis;
389     FT_Error   error = 0;
390     T1_Blend*  blend;
391     FT_Memory  memory;
392
393
394     /* take an array of objects */
395     T1_ToTokenArray( &loader->parser, axis_tokens,
396                      T1_MAX_MM_AXIS, &num_axis );
397     if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
398     {
399       FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
400                  num_axis ));
401       error = T1_Err_Invalid_File_Format;
402       goto Exit;
403     }
404
405     /* allocate blend if necessary */
406     error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
407     if ( error )
408       goto Exit;
409
410     blend  = face->blend;
411     memory = face->root.memory;
412
413     /* each token is an immediate containing the name of the axis */
414     for ( n = 0; n < num_axis; n++ )
415     {
416       T1_Token*  token = axis_tokens + n;
417       FT_Byte*   name;
418       FT_Int     len;
419
420       /* skip first slash, if any */
421       if (token->start[0] == '/')
422         token->start++;
423
424       len = (FT_Int)( token->limit - token->start );
425       if ( len <= 0 )
426       {
427         error = T1_Err_Invalid_File_Format;
428         goto Exit;
429       }
430
431       if ( ALLOC( blend->axis_names[n], len + 1 ) )
432         goto Exit;
433
434       name = (FT_Byte*)blend->axis_names[n];
435       MEM_Copy( name, token->start, len );
436       name[len] = 0;
437     }
438
439   Exit:
440     loader->parser.root.error = error;
441   }
442
443
444   static void
445   parse_blend_design_positions( T1_Face     face,
446                                 T1_Loader*  loader )
447   {
448     T1_Token       design_tokens[ T1_MAX_MM_DESIGNS ];
449     FT_Int         num_designs;
450     FT_Int         num_axis;
451     T1_ParserRec*  parser = &loader->parser;
452
453     FT_Error       error = 0;
454     T1_Blend*      blend;
455
456
457     /* get the array of design tokens - compute number of designs */
458     T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
459     if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
460     {
461       FT_ERROR(( "parse_blend_design_positions:" ));
462       FT_ERROR(( " incorrect number of designs: %d\n",
463                  num_designs ));
464       error = T1_Err_Invalid_File_Format;
465       goto Exit;
466     }
467
468     {
469       FT_Byte*  old_cursor = parser->root.cursor;
470       FT_Byte*  old_limit  = parser->root.limit;
471       FT_UInt   n;
472
473
474       blend    = face->blend;
475       num_axis = 0;  /* make compiler happy */
476
477       for ( n = 0; n < (FT_UInt)num_designs; n++ )
478       {
479         T1_Token   axis_tokens[ T1_MAX_MM_DESIGNS ];
480         T1_Token*  token;
481         FT_Int     axis, n_axis;
482
483
484         /* read axis/coordinates tokens */
485         token = design_tokens + n;
486         parser->root.cursor = token->start - 1;
487         parser->root.limit  = token->limit + 1;
488         T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
489
490         if ( n == 0 )
491         {
492           num_axis = n_axis;
493           error = t1_allocate_blend( face, num_designs, num_axis );
494           if ( error )
495             goto Exit;
496           blend = face->blend;
497         }
498         else if ( n_axis != num_axis )
499         {
500           FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
501           error = T1_Err_Invalid_File_Format;
502           goto Exit;
503         }
504
505         /* now, read each axis token into the design position */
506         for ( axis = 0; axis < n_axis; axis++ )
507         {
508           T1_Token*  token2 = axis_tokens + axis;
509
510
511           parser->root.cursor = token2->start;
512           parser->root.limit  = token2->limit;
513           blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
514         }
515       }
516
517       loader->parser.root.cursor = old_cursor;
518       loader->parser.root.limit  = old_limit;
519     }
520
521   Exit:
522     loader->parser.root.error = error;
523   }
524
525
526   static void
527   parse_blend_design_map( T1_Face     face,
528                           T1_Loader*  loader )
529   {
530     FT_Error       error  = 0;
531     T1_ParserRec*  parser = &loader->parser;
532     T1_Blend*      blend;
533     T1_Token       axis_tokens[ T1_MAX_MM_AXIS ];
534     FT_Int         n, num_axis;
535     FT_Byte*       old_cursor;
536     FT_Byte*       old_limit;
537     FT_Memory      memory = face->root.memory;
538
539
540     T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
541     if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
542     {
543       FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
544                  num_axis ));
545       error = T1_Err_Invalid_File_Format;
546       goto Exit;
547     }
548     old_cursor = parser->root.cursor;
549     old_limit  = parser->root.limit;
550
551     error = t1_allocate_blend( face, 0, num_axis );
552     if ( error )
553       goto Exit;
554     blend = face->blend;
555
556     /* now, read each axis design map */
557     for ( n = 0; n < num_axis; n++ )
558     {
559       T1_DesignMap* map = blend->design_map + n;
560       T1_Token*     token;
561       FT_Int        p, num_points;
562
563
564       token = axis_tokens + n;
565       parser->root.cursor = token->start;
566       parser->root.limit  = token->limit;
567
568       /* count the number of map points */
569       {
570         FT_Byte*  ptr   = token->start;
571         FT_Byte*  limit = token->limit;
572
573
574         num_points = 0;
575         for ( ; ptr < limit; ptr++ )
576           if ( ptr[0] == '[' )
577             num_points++;
578       }
579       if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
580       {
581         FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
582         error = T1_Err_Invalid_File_Format;
583         goto Exit;
584       }
585
586       /* allocate design map data */
587       if ( ALLOC_ARRAY( map->design_points, num_points * 2, FT_Fixed ) )
588         goto Exit;
589       map->blend_points = map->design_points + num_points;
590       map->num_points   = (FT_Byte)num_points;
591
592       for ( p = 0; p < num_points; p++ )
593       {
594         map->design_points[p] = T1_ToInt( parser );
595         map->blend_points [p] = T1_ToFixed( parser, 0 );
596       }
597     }
598
599     parser->root.cursor = old_cursor;
600     parser->root.limit  = old_limit;
601
602   Exit:
603     parser->root.error = error;
604   }
605
606
607   static void
608   parse_weight_vector( T1_Face     face,
609                        T1_Loader*  loader )
610   {
611     FT_Error       error  = 0;
612     T1_ParserRec*  parser = &loader->parser;
613     T1_Blend*      blend  = face->blend;
614     T1_Token       master;
615     FT_UInt        n;
616     FT_Byte*       old_cursor;
617     FT_Byte*       old_limit;
618
619
620     if ( !blend || blend->num_designs == 0 )
621     {
622       FT_ERROR(( "parse_weight_vector: too early!\n" ));
623       error = T1_Err_Invalid_File_Format;
624       goto Exit;
625     }
626
627     T1_ToToken( parser, &master );
628     if ( master.type != t1_token_array )
629     {
630       FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
631       error = T1_Err_Invalid_File_Format;
632       goto Exit;
633     }
634
635     old_cursor = parser->root.cursor;
636     old_limit  = parser->root.limit;
637
638     parser->root.cursor = master.start;
639     parser->root.limit  = master.limit;
640
641     for ( n = 0; n < blend->num_designs; n++ )
642     {
643       blend->default_weight_vector[n] =
644       blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
645     }
646
647     parser->root.cursor = old_cursor;
648     parser->root.limit  = old_limit;
649
650   Exit:
651     parser->root.error = error;
652   }
653
654
655   /* the keyword `/shareddict' appears in some multiple master fonts   */
656   /* with a lot of Postscript garbage behind it (that's completely out */
657   /* of spec!); we detect it and terminate the parsing                 */
658   /*                                                                   */
659   static void
660   parse_shared_dict( T1_Face     face,
661                      T1_Loader*  loader )
662   {
663     T1_ParserRec*  parser = &loader->parser;
664
665     FT_UNUSED( face );
666
667
668     parser->root.cursor = parser->root.limit;
669     parser->root.error  = 0;
670   }
671
672 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
673
674
675   /*************************************************************************/
676   /*************************************************************************/
677   /*****                                                               *****/
678   /*****                      TYPE 1 SYMBOL PARSING                    *****/
679   /*****                                                               *****/
680   /*************************************************************************/
681   /*************************************************************************/
682
683
684   /*************************************************************************/
685   /*                                                                       */
686   /* First of all, define the token field static variables.  This is a set */
687   /* of T1_Field variables used later.                                     */
688   /*                                                                       */
689   /*************************************************************************/
690
691
692   static FT_Error
693   t1_load_keyword( T1_Face     face,
694                    T1_Loader*  loader,
695                    T1_Field*   field )
696   {
697     FT_Error   error;
698     void*      dummy_object;
699     void**     objects;
700     FT_UInt    max_objects;
701     T1_Blend*  blend = face->blend;
702
703
704     /* if the keyword has a dedicated callback, call it */
705     if ( field->type == t1_field_callback )
706     {
707       field->reader( (FT_Face)face, loader );
708       error = loader->parser.root.error;
709       goto Exit;
710     }
711
712     /* now, the keyword is either a simple field, or a table of fields; */
713     /* we are now going to take care of it                              */
714     switch ( field->location )
715     {
716     case t1_field_font_info:
717       dummy_object = &face->type1.font_info;
718       objects      = &dummy_object;
719       max_objects  = 0;
720
721       if ( blend )
722       {
723         objects     = (void**)blend->font_infos;
724         max_objects = blend->num_designs;
725       }
726       break;
727
728     case t1_field_private:
729       dummy_object = &face->type1.private_dict;
730       objects      = &dummy_object;
731       max_objects  = 0;
732
733       if ( blend )
734       {
735         objects     = (void**)blend->privates;
736         max_objects = blend->num_designs;
737       }
738       break;
739
740     default:
741       dummy_object = &face->type1;
742       objects      = &dummy_object;
743       max_objects  = 0;
744     }
745
746     if ( field->type == t1_field_integer_array ||
747          field->type == t1_field_fixed_array   )
748       error = T1_Load_Field_Table( &loader->parser, field,
749                                    objects, max_objects, 0 );
750     else
751       error = T1_Load_Field( &loader->parser, field,
752                              objects, max_objects, 0 );
753
754   Exit:
755     return error;
756   }
757
758
759   static int
760   is_space( FT_Byte  c )
761   {
762     return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
763   }
764
765
766   static int
767   is_alpha( FT_Byte  c )
768   {
769     /* Note: we must accept "+" as a valid character, as it is used in */
770     /*       embedded type1 fonts in PDF documents.                    */
771     /*                                                                 */
772     return ( isalnum( c ) || c == '.' || c == '_' || c == '-' || c == '+' );
773   }
774
775
776   static int
777   read_binary_data( T1_ParserRec*  parser,
778                     FT_Int*        size,
779                     FT_Byte**      base )
780   {
781     FT_Byte*  cur;
782     FT_Byte*  limit = parser->root.limit;
783
784
785     /* the binary data has the following format */
786     /*                                          */
787     /* `size' [white*] RD white ....... ND      */
788     /*                                          */
789
790     T1_Skip_Spaces( parser );
791     cur = parser->root.cursor;
792
793     if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
794     {
795       *size = T1_ToInt( parser );
796
797       T1_Skip_Spaces( parser );
798       T1_Skip_Alpha ( parser );  /* `RD' or `-|' or something else */
799
800       /* there is only one whitespace char after the */
801       /* `RD' or `-|' token                          */
802       *base = parser->root.cursor + 1;
803
804       parser->root.cursor += *size + 1;
805       return 1;
806     }
807
808     FT_ERROR(( "read_binary_data: invalid size field\n" ));
809     parser->root.error = T1_Err_Invalid_File_Format;
810     return 0;
811   }
812
813
814   /* we will now define the routines used to handle */
815   /* the `/Encoding', `/Subrs', and `/CharStrings'  */
816   /* dictionaries                                   */
817
818   static void
819   parse_font_name( T1_Face     face,
820                    T1_Loader*  loader )
821   {
822     T1_ParserRec*  parser = &loader->parser;
823     FT_Error       error;
824     FT_Memory      memory = parser->root.memory;
825     FT_Int         len;
826     FT_Byte*       cur;
827     FT_Byte*       cur2;
828     FT_Byte*       limit;
829
830
831     T1_Skip_Spaces( parser );
832
833     cur   = parser->root.cursor;
834     limit = parser->root.limit;
835
836     if ( cur >= limit - 1 || *cur != '/' )
837       return;
838
839     cur++;
840     cur2 = cur;
841     while ( cur2 < limit && is_alpha( *cur2 ) )
842       cur2++;
843
844     len = (FT_Int)( cur2 - cur );
845     if ( len > 0 )
846     {
847       if ( ALLOC( face->type1.font_name, len + 1 ) )
848       {
849         parser->root.error = error;
850         return;
851       }
852
853       MEM_Copy( face->type1.font_name, cur, len );
854       face->type1.font_name[len] = '\0';
855     }
856     parser->root.cursor = cur2;
857   }
858
859
860   static void
861   parse_font_bbox( T1_Face     face,
862                    T1_Loader*  loader )
863   {
864     T1_ParserRec*  parser = &loader->parser;
865     FT_Fixed       temp[4];
866     FT_BBox*       bbox   = &face->type1.font_bbox;
867
868
869     (void)T1_ToFixedArray( parser, 4, temp, 0 );
870     bbox->xMin = FT_RoundFix( temp[0] );
871     bbox->yMin = FT_RoundFix( temp[1] );
872     bbox->xMax = FT_RoundFix( temp[2] );
873     bbox->yMax = FT_RoundFix( temp[3] );
874   }
875
876
877   static void
878   parse_font_matrix( T1_Face     face,
879                      T1_Loader*  loader )
880   {
881     T1_ParserRec*  parser = &loader->parser;
882     FT_Matrix*     matrix = &face->type1.font_matrix;
883     FT_Vector*     offset = &face->type1.font_offset;
884     FT_Face        root   = (FT_Face)&face->root;
885     FT_Fixed       temp[6];
886     FT_Fixed       temp_scale;
887
888
889     if ( matrix->xx || matrix->yx )
890       /*  with synthetic fonts, it's possible we get here twice  */
891       return;
892
893     (void)T1_ToFixedArray( parser, 6, temp, 3 );
894
895     temp_scale = ABS( temp[3] );
896
897     /* Set Units per EM based on FontMatrix values.  We set the value to */
898     /* 1000 / temp_scale, because temp_scale was already multiplied by   */
899     /* 1000 (in t1_tofixed, from psobjs.c).                              */
900
901     root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
902                                                  temp_scale ) >> 16 );
903
904     /* we need to scale the values by 1.0/temp_scale */
905     if ( temp_scale != 0x10000L )
906     {
907       temp[0] = FT_DivFix( temp[0], temp_scale );
908       temp[1] = FT_DivFix( temp[1], temp_scale );
909       temp[2] = FT_DivFix( temp[2], temp_scale );
910       temp[4] = FT_DivFix( temp[4], temp_scale );
911       temp[5] = FT_DivFix( temp[5], temp_scale );
912       temp[3] = 0x10000L;
913     }
914
915     matrix->xx = temp[0];
916     matrix->yx = temp[1];
917     matrix->xy = temp[2];
918     matrix->yy = temp[3];
919
920     /* note that the offsets must be expressed in integer font units */
921     offset->x  = temp[4] >> 16;
922     offset->y  = temp[5] >> 16;
923   }
924
925
926   static void
927   parse_encoding( T1_Face     face,
928                   T1_Loader*  loader )
929   {
930     T1_ParserRec*  parser = &loader->parser;
931     FT_Byte*       cur    = parser->root.cursor;
932     FT_Byte*       limit  = parser->root.limit;
933
934     PSAux_Interface*  psaux = (PSAux_Interface*)face->psaux;
935
936
937     /* skip whitespace */
938     while ( is_space( *cur ) )
939     {
940       cur++;
941       if ( cur >= limit )
942       {
943         FT_ERROR(( "parse_encoding: out of bounds!\n" ));
944         parser->root.error = T1_Err_Invalid_File_Format;
945         return;
946       }
947     }
948
949     /* if we have a number, then the encoding is an array, */
950     /* and we must load it now                             */
951     if ( (FT_Byte)( *cur - '0' ) < 10 )
952     {
953       T1_Encoding*  encode     = &face->type1.encoding;
954       FT_Int        count, n;
955       PS_Table*     char_table = &loader->encoding_table;
956       FT_Memory     memory     = parser->root.memory;
957       FT_Error      error;
958
959
960       /* read the number of entries in the encoding, should be 256 */
961       count = T1_ToInt( parser );
962       if ( parser->root.error )
963         return;
964
965       /* we use a T1_Table to store our charnames */
966       encode->num_chars = count;
967       if ( ALLOC_ARRAY( encode->char_index, count, FT_Short   ) ||
968            ALLOC_ARRAY( encode->char_name,  count, FT_String* ) ||
969            ( error = psaux->ps_table_funcs->init(
970                        char_table, count, memory ) ) != 0       )
971       {
972         parser->root.error = error;
973         return;
974       }
975
976       /* We need to `zero' out encoding_table.elements          */
977       for ( n = 0; n < count; n++ )
978       {
979         char*  notdef = (char *)".notdef";
980
981
982         T1_Add_Table( char_table, n, notdef, 8 );
983       }
984
985       /* Now, we will need to read a record of the form         */
986       /* ... charcode /charname ... for each entry in our table */
987       /*                                                        */
988       /* We simply look for a number followed by an immediate   */
989       /* name.  Note that this ignores correctly the sequence   */
990       /* that is often seen in type1 fonts:                     */
991       /*                                                        */
992       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
993       /*                                                        */
994       /* used to clean the encoding array before anything else. */
995       /*                                                        */
996       /* We stop when we encounter a `def'.                     */
997
998       cur   = parser->root.cursor;
999       limit = parser->root.limit;
1000       n     = 0;
1001
1002       for ( ; cur < limit; )
1003       {
1004         FT_Byte  c;
1005
1006
1007         c = *cur;
1008
1009         /* we stop when we encounter a `def' */
1010         if ( c == 'd' && cur + 3 < limit )
1011         {
1012           if ( cur[1] == 'e' &&
1013                cur[2] == 'f' &&
1014                is_space(cur[-1]) &&
1015                is_space(cur[3]) )
1016           {
1017             FT_TRACE6(( "encoding end\n" ));
1018             break;
1019           }
1020         }
1021
1022         /* otherwise, we must find a number before anything else */
1023         if ( (FT_Byte)( c - '0' ) < 10 )
1024         {
1025           FT_Int  charcode;
1026
1027
1028           parser->root.cursor = cur;
1029           charcode = T1_ToInt( parser );
1030           cur = parser->root.cursor;
1031
1032           /* skip whitespace */
1033           while ( cur < limit && is_space( *cur ) )
1034             cur++;
1035
1036           if ( cur < limit && *cur == '/' )
1037           {
1038             /* bingo, we have an immediate name -- it must be a */
1039             /* character name                                   */
1040             FT_Byte*  cur2 = cur + 1;
1041             FT_Int    len;
1042
1043
1044             while ( cur2 < limit && is_alpha( *cur2 ) )
1045               cur2++;
1046
1047             len = (FT_Int)( cur2 - cur - 1 );
1048
1049             parser->root.error = T1_Add_Table( char_table, charcode,
1050                                                cur + 1, len + 1 );
1051             char_table->elements[charcode][len] = '\0';
1052             if ( parser->root.error )
1053               return;
1054
1055             cur = cur2;
1056           }
1057         }
1058         else
1059           cur++;
1060       }
1061
1062       face->type1.encoding_type = t1_encoding_array;
1063       parser->root.cursor       = cur;
1064     }
1065     /* Otherwise, we should have either `StandardEncoding' or */
1066     /* `ExpertEncoding'                                       */
1067     else
1068     {
1069       if ( cur + 17 < limit &&
1070            strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
1071         face->type1.encoding_type = t1_encoding_standard;
1072
1073       else if ( cur + 15 < limit &&
1074                 strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
1075         face->type1.encoding_type = t1_encoding_expert;
1076
1077       else
1078       {
1079         FT_ERROR(( "parse_encoding: invalid token!\n" ));
1080         parser->root.error = T1_Err_Invalid_File_Format;
1081       }
1082     }
1083   }
1084
1085
1086   static void
1087   parse_subrs( T1_Face     face,
1088                T1_Loader*  loader )
1089   {
1090     T1_ParserRec*  parser = &loader->parser;
1091     PS_Table*      table  = &loader->subrs;
1092     FT_Memory      memory = parser->root.memory;
1093     FT_Error       error;
1094     FT_Int         n;
1095
1096     PSAux_Interface*  psaux = (PSAux_Interface*)face->psaux;
1097
1098
1099     loader->num_subrs = T1_ToInt( parser );
1100     if ( parser->root.error )
1101       return;
1102
1103     /* position the parser right before the `dup' of the first subr */
1104     T1_Skip_Spaces( parser );
1105     T1_Skip_Alpha( parser );      /* `array' */
1106     T1_Skip_Spaces( parser );
1107
1108     /* initialize subrs array */
1109     error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
1110     if ( error )
1111       goto Fail;
1112
1113     /* the format is simple:                                 */
1114     /*                                                       */
1115     /*   `index' + binary data                               */
1116     /*                                                       */
1117
1118     for ( n = 0; n < loader->num_subrs; n++ )
1119     {
1120       FT_Int    index, size;
1121       FT_Byte*  base;
1122
1123
1124       /* If the next token isn't `dup', we are also done.  This */
1125       /* happens when there are `holes' in the Subrs array.     */
1126       if ( strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
1127         break;
1128
1129       index = T1_ToInt( parser );
1130
1131       if ( !read_binary_data( parser, &size, &base ) )
1132         return;
1133
1134       /* The binary string is followed by one token, e.g. `NP' */
1135       /* (bound to `noaccess put') or by two separate tokens:  */
1136       /* `noaccess' & `put'.  We position the parser right     */
1137       /* before the next `dup', if any.                        */
1138       T1_Skip_Spaces( parser );
1139       T1_Skip_Alpha( parser );    /* `NP' or `I' or `noaccess' */
1140       T1_Skip_Spaces( parser );
1141
1142       if ( strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
1143       {
1144         T1_Skip_Alpha( parser );  /* skip `put' */
1145         T1_Skip_Spaces( parser );
1146       }
1147
1148       /* some fonts use a value of -1 for lenIV to indicate that */
1149       /* the charstrings are unencoded                           */
1150       /*                                                         */
1151       /* thanks to Tom Kacvinsky for pointing this out           */
1152       /*                                                         */
1153       if ( face->type1.private_dict.lenIV >= 0 )
1154       {
1155         psaux->t1_decrypt( base, size, 4330 );
1156         size -= face->type1.private_dict.lenIV;
1157         base += face->type1.private_dict.lenIV;
1158       }
1159
1160       error = T1_Add_Table( table, index, base, size );
1161       if ( error )
1162         goto Fail;
1163     }
1164     return;
1165
1166   Fail:
1167     parser->root.error = error;
1168   }
1169
1170
1171   static void
1172   parse_charstrings( T1_Face     face,
1173                      T1_Loader*  loader )
1174   {
1175     T1_ParserRec*  parser     = &loader->parser;
1176     PS_Table*      code_table = &loader->charstrings;
1177     PS_Table*      name_table = &loader->glyph_names;
1178     PS_Table*      swap_table = &loader->swap_table;
1179     FT_Memory      memory     = parser->root.memory;
1180     FT_Error       error;
1181
1182     PSAux_Interface*  psaux = (PSAux_Interface*)face->psaux;
1183
1184     FT_Byte*    cur;
1185     FT_Byte*    limit = parser->root.limit;
1186     FT_Int      n;
1187     FT_UInt     notdef_index = 0;
1188     FT_Byte     notdef_found = 0;
1189
1190
1191     if ( loader->num_glyphs )
1192       /*  with synthetic fonts, it's possible we get here twice  */
1193       return;
1194
1195     loader->num_glyphs = T1_ToInt( parser );
1196     if ( parser->root.error )
1197       return;
1198
1199     /* initialize tables (leaving room for addition of .notdef, */
1200     /* if necessary).                                           */
1201
1202     error = psaux->ps_table_funcs->init( code_table,
1203                                          loader->num_glyphs + 1,
1204                                          memory );
1205     if ( error )
1206       goto Fail;
1207
1208     error = psaux->ps_table_funcs->init( name_table,
1209                                          loader->num_glyphs + 1,
1210                                          memory );
1211     if ( error )
1212       goto Fail;
1213
1214     /* Initialize table for swapping index notdef_index and */
1215     /* index 0 names and codes (if necessary).              */
1216
1217     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
1218
1219     if ( error )
1220       goto Fail;
1221
1222
1223     n = 0;
1224     for (;;)
1225     {
1226       FT_Int    size;
1227       FT_Byte*  base;
1228
1229
1230       /* the format is simple:                    */
1231       /*   `/glyphname' + binary data             */
1232       /*                                          */
1233       /* note that we stop when we find a `def'   */
1234       /*                                          */
1235       T1_Skip_Spaces( parser );
1236
1237       cur = parser->root.cursor;
1238       if ( cur >= limit )
1239         break;
1240
1241       /* we stop when we find a `def' or `end' keyword */
1242       if ( *cur   == 'd'   &&
1243            cur + 3 < limit &&
1244            cur[1] == 'e'   &&
1245            cur[2] == 'f'   )
1246         break;
1247
1248       if ( *cur   == 'e'   &&
1249            cur + 3 < limit &&
1250            cur[1] == 'n'   &&
1251            cur[2] == 'd'   )
1252         break;
1253
1254       if ( *cur != '/' )
1255         T1_Skip_Alpha( parser );
1256       else
1257       {
1258         FT_Byte*  cur2 = cur + 1;
1259         FT_Int    len;
1260
1261
1262         while ( cur2 < limit && is_alpha( *cur2 ) )
1263           cur2++;
1264         len = (FT_Int)( cur2 - cur - 1 );
1265
1266         error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
1267         if ( error )
1268           goto Fail;
1269
1270         /* add a trailing zero to the name table */
1271         name_table->elements[n][len] = '\0';
1272
1273         /* record index of /.notdef              */
1274         if ( strcmp( (const char*)".notdef",
1275                      (const char*)(name_table->elements[n]) ) == 0 )
1276         {
1277           notdef_index = n;
1278           notdef_found = 1;
1279         }
1280
1281         parser->root.cursor = cur2;
1282         if ( !read_binary_data( parser, &size, &base ) )
1283           return;
1284
1285         if ( face->type1.private_dict.lenIV >= 0 )
1286         {
1287           psaux->t1_decrypt( base, size, 4330 );
1288           size -= face->type1.private_dict.lenIV;
1289           base += face->type1.private_dict.lenIV;
1290         }
1291
1292         error = T1_Add_Table( code_table, n, base, size );
1293         if ( error )
1294           goto Fail;
1295
1296         n++;
1297         if ( n >= loader->num_glyphs )
1298           break;
1299       }
1300     }
1301
1302     loader->num_glyphs = n;
1303
1304     /* if /.notdef is found but does not occupy index 0, do our magic.      */
1305     if ( strcmp( (const char*)".notdef",
1306                  (const char*)name_table->elements[0] ) &&
1307          notdef_found                                      )
1308     {
1309       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0    */
1310       /* name and code entries to swap_table. Then place notdef_index name */
1311       /* and code entries into swap_table.  Then swap name and code        */
1312       /* entries at indices notdef_index and 0 using values stored in      */
1313       /* swap_table.                                                       */
1314
1315       /* Index 0 name */
1316       error = T1_Add_Table( swap_table, 0,
1317                             name_table->elements[0],
1318                             name_table->lengths [0] );
1319       if ( error )
1320         goto Fail;
1321
1322       /* Index 0 code */
1323       error = T1_Add_Table( swap_table, 1,
1324                             code_table->elements[0],
1325                             code_table->lengths [0] );
1326       if ( error )
1327         goto Fail;
1328
1329       /* Index notdef_index name */
1330       error = T1_Add_Table( swap_table, 2,
1331                             name_table->elements[notdef_index],
1332                             name_table->lengths [notdef_index] );
1333       if ( error )
1334         goto Fail;
1335
1336       /* Index notdef_index code */
1337       error = T1_Add_Table( swap_table, 3,
1338                             code_table->elements[notdef_index],
1339                             code_table->lengths [notdef_index] );
1340       if ( error )
1341         goto Fail;
1342
1343       error = T1_Add_Table( name_table, notdef_index,
1344                             swap_table->elements[0],
1345                             swap_table->lengths [0] );
1346       if ( error )
1347         goto Fail;
1348
1349       error = T1_Add_Table( code_table, notdef_index,
1350                             swap_table->elements[1],
1351                             swap_table->lengths [1] );
1352       if ( error )
1353         goto Fail;
1354
1355       error = T1_Add_Table( name_table, 0,
1356                             swap_table->elements[2],
1357                             swap_table->lengths [2] );
1358       if ( error )
1359         goto Fail;
1360
1361       error = T1_Add_Table( code_table, 0,
1362                             swap_table->elements[3],
1363                             swap_table->lengths [3] );
1364       if ( error )
1365         goto Fail;
1366
1367     }
1368     else if ( !notdef_found )
1369     {
1370
1371       /* notdef_index is already 0, or /.notdef is undefined in  */
1372       /* charstrings dictionary. Worry about /.notdef undefined. */
1373       /* We take index 0 and add it to the end of the table(s)   */
1374       /* and add our own /.notdef glyph to index 0.              */
1375
1376       /* 0 333 hsbw endchar                                      */
1377       FT_Byte  notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
1378       char*    notdef_name    = (char *)".notdef";
1379
1380
1381       error = T1_Add_Table( swap_table, 0,
1382                             name_table->elements[0],
1383                             name_table->lengths [0] );
1384       if ( error )
1385         goto Fail;
1386
1387       error = T1_Add_Table( swap_table, 1,
1388                             code_table->elements[0],
1389                             code_table->lengths [0] );
1390       if ( error )
1391         goto Fail;
1392
1393       error = T1_Add_Table( name_table, 0, notdef_name, 8 );
1394       if ( error )
1395         goto Fail;
1396
1397       error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
1398
1399       if ( error )
1400         goto Fail;
1401
1402       error = T1_Add_Table( name_table, n,
1403                             swap_table->elements[0],
1404                             swap_table->lengths [0] );
1405       if ( error )
1406         goto Fail;
1407
1408       error = T1_Add_Table( code_table, n,
1409                             swap_table->elements[1],
1410                             swap_table->lengths [1] );
1411       if ( error )
1412         goto Fail;
1413
1414       /* we added a glyph. */
1415       loader->num_glyphs = n + 1;
1416
1417     }
1418
1419
1420     return;
1421
1422   Fail:
1423     parser->root.error = error;
1424   }
1425
1426
1427   static
1428   const T1_Field  t1_keywords[] =
1429   {
1430
1431 #include "t1tokens.h"
1432
1433     /* now add the special functions... */
1434     T1_FIELD_CALLBACK( "FontName", parse_font_name )
1435     T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
1436     T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
1437     T1_FIELD_CALLBACK( "Encoding", parse_encoding )
1438     T1_FIELD_CALLBACK( "Subrs", parse_subrs )
1439     T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
1440
1441 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
1442     T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
1443     T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
1444     T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
1445     T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
1446     T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
1447 #endif
1448
1449     { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
1450   };
1451
1452
1453   static FT_Error
1454   parse_dict( T1_Face     face,
1455               T1_Loader*  loader,
1456               FT_Byte*    base,
1457               FT_Long     size )
1458   {
1459     T1_ParserRec*  parser = &loader->parser;
1460
1461
1462     parser->root.cursor = base;
1463     parser->root.limit  = base + size;
1464     parser->root.error  = 0;
1465
1466     {
1467       FT_Byte*  cur   = base;
1468       FT_Byte*  limit = cur + size;
1469
1470
1471       for ( ; cur < limit; cur++ )
1472       {
1473         /* look for `FontDirectory', which causes problems on some fonts */
1474         if ( *cur == 'F' && cur + 25 < limit                 &&
1475              strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1476         {
1477           FT_Byte*  cur2;
1478
1479
1480           /* skip the `FontDirectory' keyword */
1481           cur += 13;
1482           cur2 = cur;
1483
1484           /* lookup the `known' keyword */
1485           while ( cur < limit && *cur != 'k'        &&
1486                   strncmp( (char*)cur, "known", 5 ) )
1487             cur++;
1488
1489           if ( cur < limit )
1490           {
1491             T1_Token  token;
1492
1493
1494             /* skip the `known' keyword and the token following it */
1495             cur += 5;
1496             loader->parser.root.cursor = cur;
1497             T1_ToToken( &loader->parser, &token );
1498
1499             /* if the last token was an array, skip it! */
1500             if ( token.type == t1_token_array )
1501               cur2 = parser->root.cursor;
1502           }
1503           cur = cur2;
1504         }
1505         /* look for immediates */
1506         else if ( *cur == '/' && cur + 2 < limit )
1507         {
1508           FT_Byte*  cur2;
1509           FT_Int    len;
1510
1511
1512           cur++;
1513           cur2 = cur;
1514           while ( cur2 < limit && is_alpha( *cur2 ) )
1515             cur2++;
1516
1517           len  = (FT_Int)( cur2 - cur );
1518           if ( len > 0 && len < 22 )
1519           {
1520             {
1521               /* now, compare the immediate name to the keyword table */
1522               T1_Field*  keyword = (T1_Field*)t1_keywords;
1523
1524
1525               for (;;)
1526               {
1527                 FT_Byte*  name;
1528
1529
1530                 name = (FT_Byte*)keyword->ident;
1531                 if ( !name )
1532                   break;
1533
1534                 if ( cur[0] == name[0]                          &&
1535                      len == (FT_Int)strlen( (const char*)name ) )
1536                 {
1537                   FT_Int  n;
1538
1539
1540                   for ( n = 1; n < len; n++ )
1541                     if ( cur[n] != name[n] )
1542                       break;
1543
1544                   if ( n >= len )
1545                   {
1546                     /* we found it -- run the parsing callback! */
1547                     parser->root.cursor = cur2;
1548                     T1_Skip_Spaces( parser );
1549                     parser->root.error = t1_load_keyword( face,
1550                                                           loader,
1551                                                           keyword );
1552                     if ( parser->root.error )
1553                       return parser->root.error;
1554
1555                     cur = parser->root.cursor;
1556                     break;
1557                   }
1558                 }
1559                 keyword++;
1560               }
1561             }
1562           }
1563         }
1564       }
1565     }
1566     return parser->root.error;
1567   }
1568
1569
1570   static void
1571   t1_init_loader( T1_Loader*  loader,
1572                   T1_Face     face )
1573   {
1574     FT_UNUSED( face );
1575
1576     MEM_Set( loader, 0, sizeof ( *loader ) );
1577     loader->num_glyphs = 0;
1578     loader->num_chars  = 0;
1579
1580     /* initialize the tables -- simply set their `init' field to 0 */
1581     loader->encoding_table.init = 0;
1582     loader->charstrings.init    = 0;
1583     loader->glyph_names.init    = 0;
1584     loader->subrs.init          = 0;
1585     loader->swap_table.init     = 0;
1586     loader->fontdata            = 0;
1587   }
1588
1589
1590   static void
1591   t1_done_loader( T1_Loader*  loader )
1592   {
1593     T1_ParserRec*  parser = &loader->parser;
1594
1595
1596     /* finalize tables */
1597     T1_Release_Table( &loader->encoding_table );
1598     T1_Release_Table( &loader->charstrings );
1599     T1_Release_Table( &loader->glyph_names );
1600     T1_Release_Table( &loader->swap_table );
1601     T1_Release_Table( &loader->subrs );
1602
1603     /* finalize parser */
1604     T1_Finalize_Parser( parser );
1605   }
1606
1607
1608   FT_LOCAL_DEF FT_Error
1609   T1_Open_Face( T1_Face  face )
1610   {
1611     T1_Loader      loader;
1612     T1_ParserRec*  parser;
1613     T1_Font*       type1 = &face->type1;
1614     FT_Error       error;
1615
1616     PSAux_Interface*  psaux = (PSAux_Interface*)face->psaux;
1617
1618
1619     t1_init_loader( &loader, face );
1620
1621     /* default lenIV */
1622     type1->private_dict.lenIV = 4;
1623
1624     parser = &loader.parser;
1625     error = T1_New_Parser( parser,
1626                            face->root.stream,
1627                            face->root.memory,
1628                            psaux );
1629     if ( error )
1630       goto Exit;
1631
1632     error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
1633     if ( error )
1634       goto Exit;
1635
1636     error = T1_Get_Private_Dict( parser, psaux );
1637     if ( error )
1638       goto Exit;
1639
1640     error = parse_dict( face, &loader, parser->private_dict,
1641                         parser->private_len );
1642     if ( error )
1643       goto Exit;
1644
1645     /* now, propagate the subrs, charstrings, and glyphnames tables */
1646     /* to the Type1 data                                            */
1647     type1->num_glyphs = loader.num_glyphs;
1648
1649     if ( loader.subrs.init )
1650     {
1651       loader.subrs.init  = 0;
1652       type1->num_subrs   = loader.num_subrs;
1653       type1->subrs_block = loader.subrs.block;
1654       type1->subrs       = loader.subrs.elements;
1655       type1->subrs_len   = loader.subrs.lengths;
1656     }
1657
1658     if ( !loader.charstrings.init )
1659     {
1660       FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" ));
1661       error = T1_Err_Invalid_File_Format;
1662     }
1663
1664     loader.charstrings.init  = 0;
1665     type1->charstrings_block = loader.charstrings.block;
1666     type1->charstrings       = loader.charstrings.elements;
1667     type1->charstrings_len   = loader.charstrings.lengths;
1668
1669     /* we copy the glyph names `block' and `elements' fields; */
1670     /* the `lengths' field must be released later             */
1671     type1->glyph_names_block    = loader.glyph_names.block;
1672     type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
1673     loader.glyph_names.block    = 0;
1674     loader.glyph_names.elements = 0;
1675
1676     /* we must now build type1.encoding when we have a custom */
1677     /* array..                                                */
1678     if ( type1->encoding_type == t1_encoding_array )
1679     {
1680       FT_Int    charcode, index, min_char, max_char;
1681       FT_Byte*  char_name;
1682       FT_Byte*  glyph_name;
1683
1684
1685       /* OK, we do the following: for each element in the encoding  */
1686       /* table, look up the index of the glyph having the same name */
1687       /* the index is then stored in type1.encoding.char_index, and */
1688       /* a the name to type1.encoding.char_name                     */
1689
1690       min_char = +32000;
1691       max_char = -32000;
1692
1693       charcode = 0;
1694       for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
1695       {
1696         type1->encoding.char_index[charcode] = 0;
1697         type1->encoding.char_name [charcode] = (char *)".notdef";
1698
1699         char_name = loader.encoding_table.elements[charcode];
1700         if ( char_name )
1701           for ( index = 0; index < type1->num_glyphs; index++ )
1702           {
1703             glyph_name = (FT_Byte*)type1->glyph_names[index];
1704             if ( strcmp( (const char*)char_name,
1705                          (const char*)glyph_name ) == 0 )
1706             {
1707               type1->encoding.char_index[charcode] = (FT_UShort)index;
1708               type1->encoding.char_name [charcode] = (char*)glyph_name;
1709
1710               /* Change min/max encoded char only if glyph name is */
1711               /* not /.notdef                                      */
1712               if ( strcmp( (const char*)".notdef",
1713                            (const char*)glyph_name ) != 0 )
1714               {
1715                 if (charcode < min_char) min_char = charcode;
1716                 if (charcode > max_char) max_char = charcode;
1717               }
1718               break;
1719             }
1720           }
1721       }
1722       type1->encoding.code_first = min_char;
1723       type1->encoding.code_last  = max_char;
1724       type1->encoding.num_chars  = loader.num_chars;
1725    }
1726
1727   Exit:
1728     t1_done_loader( &loader );
1729     return error;
1730   }
1731
1732
1733 /* END */