1/***************************************************************************/
2/*                                                                         */
3/*  t1load.c                                                               */
4/*                                                                         */
5/*    Type 1 font loader (body).                                           */
6/*                                                                         */
7/*  Copyright 1996-2013 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.  This file is included twice here; the first  */
45  /* time to generate parsing callback functions, the second time to       */
46  /* generate a table of keywords (with pointers to the associated         */
47  /* callback functions).                                                  */
48  /*                                                                       */
49  /* The function `parse_dict' simply scans *linearly* a given dictionary  */
50  /* (either the top-level or private one) and calls the appropriate       */
51  /* callback when it encounters an immediate keyword.                     */
52  /*                                                                       */
53  /* This is by far the fastest way one can find to parse and read all     */
54  /* data.                                                                 */
55  /*                                                                       */
56  /* This led to tremendous code size reduction.  Note that later, the     */
57  /* glyph loader will also be _greatly_ simplified, and the automatic     */
58  /* hinter will replace the clumsy `t1hinter'.                            */
59  /*                                                                       */
60  /*************************************************************************/
61
62
63#include "../../include/ft2build.h"
64#include "../../include/freetype/internal/ftdebug.h"
65#include "../../include/freetype/config/ftconfig.h"
66#include "../../include/freetype/ftmm.h"
67#include "../../include/freetype/internal/t1types.h"
68#include "../../include/freetype/internal/ftcalc.h"
69
70#include "t1load.h"
71#include "t1errors.h"
72
73
74#ifdef FT_CONFIG_OPTION_INCREMENTAL
75#define IS_INCREMENTAL  (FT_Bool)( face->root.internal->incremental_interface != 0 )
76#else
77#define IS_INCREMENTAL  0
78#endif
79
80
81  /*************************************************************************/
82  /*                                                                       */
83  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
84  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
85  /* messages during execution.                                            */
86  /*                                                                       */
87#undef  FT_COMPONENT
88#define FT_COMPONENT  trace_t1load
89
90
91#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
92
93
94  /*************************************************************************/
95  /*************************************************************************/
96  /*****                                                               *****/
97  /*****                    MULTIPLE MASTERS SUPPORT                   *****/
98  /*****                                                               *****/
99  /*************************************************************************/
100  /*************************************************************************/
101
102  static FT_Error
103  t1_allocate_blend( T1_Face  face,
104                     FT_UInt  num_designs,
105                     FT_UInt  num_axis )
106  {
107    PS_Blend   blend;
108    FT_Memory  memory = face->root.memory;
109    FT_Error   error  = FT_Err_Ok;
110
111
112    blend = face->blend;
113    if ( !blend )
114    {
115      if ( FT_NEW( blend ) )
116        goto Exit;
117
118      blend->num_default_design_vector = 0;
119
120      face->blend = blend;
121    }
122
123    /* allocate design data if needed */
124    if ( num_designs > 0 )
125    {
126      if ( blend->num_designs == 0 )
127      {
128        FT_UInt  nn;
129
130
131        /* allocate the blend `private' and `font_info' dictionaries */
132        if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs     ) ||
133             FT_NEW_ARRAY( blend->privates  [1], num_designs     ) ||
134             FT_NEW_ARRAY( blend->bboxes    [1], num_designs     ) ||
135             FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
136          goto Exit;
137
138        blend->default_weight_vector = blend->weight_vector + num_designs;
139
140        blend->font_infos[0] = &face->type1.font_info;
141        blend->privates  [0] = &face->type1.private_dict;
142        blend->bboxes    [0] = &face->type1.font_bbox;
143
144        for ( nn = 2; nn <= num_designs; nn++ )
145        {
146          blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
147          blend->privates  [nn] = blend->privates  [nn - 1] + 1;
148          blend->bboxes    [nn] = blend->bboxes    [nn - 1] + 1;
149        }
150
151        blend->num_designs = num_designs;
152      }
153      else if ( blend->num_designs != num_designs )
154        goto Fail;
155    }
156
157    /* allocate axis data if needed */
158    if ( num_axis > 0 )
159    {
160      if ( blend->num_axis != 0 && blend->num_axis != num_axis )
161        goto Fail;
162
163      blend->num_axis = num_axis;
164    }
165
166    /* allocate the blend design pos table if needed */
167    num_designs = blend->num_designs;
168    num_axis    = blend->num_axis;
169    if ( num_designs && num_axis && blend->design_pos[0] == 0 )
170    {
171      FT_UInt  n;
172
173
174      if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
175        goto Exit;
176
177      for ( n = 1; n < num_designs; n++ )
178        blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
179    }
180
181  Exit:
182    return error;
183
184  Fail:
185    error = FT_THROW( Invalid_File_Format );
186    goto Exit;
187  }
188
189
190  FT_LOCAL_DEF( FT_Error )
191  T1_Get_Multi_Master( T1_Face           face,
192                       FT_Multi_Master*  master )
193  {
194    PS_Blend  blend = face->blend;
195    FT_UInt   n;
196    FT_Error  error;
197
198
199    error = FT_THROW( Invalid_Argument );
200
201    if ( blend )
202    {
203      master->num_axis    = blend->num_axis;
204      master->num_designs = blend->num_designs;
205
206      for ( n = 0; n < blend->num_axis; n++ )
207      {
208        FT_MM_Axis*   axis = master->axis + n;
209        PS_DesignMap  map = blend->design_map + n;
210
211
212        axis->name    = blend->axis_names[n];
213        axis->minimum = map->design_points[0];
214        axis->maximum = map->design_points[map->num_points - 1];
215      }
216
217      error = FT_Err_Ok;
218    }
219
220    return error;
221  }
222
223
224  /*************************************************************************/
225  /*                                                                       */
226  /* Given a normalized (blend) coordinate, figure out the design          */
227  /* coordinate appropriate for that value.                                */
228  /*                                                                       */
229  FT_LOCAL_DEF( FT_Fixed )
230  mm_axis_unmap( PS_DesignMap  axismap,
231                 FT_Fixed      ncv )
232  {
233    int  j;
234
235
236    if ( ncv <= axismap->blend_points[0] )
237      return INT_TO_FIXED( axismap->design_points[0] );
238
239    for ( j = 1; j < axismap->num_points; ++j )
240    {
241      if ( ncv <= axismap->blend_points[j] )
242        return INT_TO_FIXED( axismap->design_points[j - 1] ) +
243               ( axismap->design_points[j] - axismap->design_points[j - 1] ) *
244               FT_DivFix( ncv - axismap->blend_points[j - 1],
245                          axismap->blend_points[j] -
246                            axismap->blend_points[j - 1] );
247    }
248
249    return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
250  }
251
252
253  /*************************************************************************/
254  /*                                                                       */
255  /* Given a vector of weights, one for each design, figure out the        */
256  /* normalized axis coordinates which gave rise to those weights.         */
257  /*                                                                       */
258  FT_LOCAL_DEF( void )
259  mm_weights_unmap( FT_Fixed*  weights,
260                    FT_Fixed*  axiscoords,
261                    FT_UInt    axis_count )
262  {
263    FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
264
265    if ( axis_count == 1 )
266      axiscoords[0] = weights[1];
267
268    else if ( axis_count == 2 )
269    {
270      axiscoords[0] = weights[3] + weights[1];
271      axiscoords[1] = weights[3] + weights[2];
272    }
273
274    else if ( axis_count == 3 )
275    {
276      axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
277      axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
278      axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
279    }
280
281    else
282    {
283      axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
284                        weights[7] + weights[5] + weights[3] + weights[1];
285      axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
286                        weights[7] + weights[6] + weights[3] + weights[2];
287      axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
288                        weights[7] + weights[6] + weights[5] + weights[4];
289      axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
290                        weights[11] + weights[10] + weights[9] + weights[8];
291    }
292  }
293
294
295  /*************************************************************************/
296  /*                                                                       */
297  /* Just a wrapper around T1_Get_Multi_Master to support the different    */
298  /*  arguments needed by the GX var distortable fonts.                    */
299  /*                                                                       */
300  FT_LOCAL_DEF( FT_Error )
301  T1_Get_MM_Var( T1_Face      face,
302                 FT_MM_Var*  *master )
303  {
304    FT_Memory        memory = face->root.memory;
305    FT_MM_Var       *mmvar = NULL;
306    FT_Multi_Master  mmaster;
307    FT_Error         error;
308    FT_UInt          i;
309    FT_Fixed         axiscoords[T1_MAX_MM_AXIS];
310    PS_Blend         blend = face->blend;
311
312
313    error = T1_Get_Multi_Master( face, &mmaster );
314    if ( error )
315      goto Exit;
316    if ( FT_ALLOC( mmvar,
317                   sizeof ( FT_MM_Var ) +
318                     mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
319      goto Exit;
320
321    mmvar->num_axis        = mmaster.num_axis;
322    mmvar->num_designs     = mmaster.num_designs;
323    mmvar->num_namedstyles = ~0U;                        /* Does not apply */
324    mmvar->axis            = (FT_Var_Axis*)&mmvar[1];
325                                      /* Point to axes after MM_Var struct */
326    mmvar->namedstyle      = NULL;
327
328    for ( i = 0 ; i < mmaster.num_axis; ++i )
329    {
330      mmvar->axis[i].name    = mmaster.axis[i].name;
331      mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum);
332      mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum);
333      mmvar->axis[i].def     = ( mmvar->axis[i].minimum +
334                                   mmvar->axis[i].maximum ) / 2;
335                            /* Does not apply.  But this value is in range */
336      mmvar->axis[i].strid   = ~0U;                      /* Does not apply */
337      mmvar->axis[i].tag     = ~0U;                      /* Does not apply */
338
339      if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
340        mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
341      else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
342        mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
343      else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
344        mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
345    }
346
347    if ( blend->num_designs == ( 1U << blend->num_axis ) )
348    {
349      mm_weights_unmap( blend->default_weight_vector,
350                        axiscoords,
351                        blend->num_axis );
352
353      for ( i = 0; i < mmaster.num_axis; ++i )
354        mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
355                                            axiscoords[i] );
356    }
357
358    *master = mmvar;
359
360  Exit:
361    return error;
362  }
363
364
365  FT_LOCAL_DEF( FT_Error )
366  T1_Set_MM_Blend( T1_Face    face,
367                   FT_UInt    num_coords,
368                   FT_Fixed*  coords )
369  {
370    PS_Blend  blend = face->blend;
371    FT_Error  error;
372    FT_UInt   n, m;
373
374
375    error = FT_ERR( Invalid_Argument );
376
377    if ( blend && blend->num_axis == num_coords )
378    {
379      /* recompute the weight vector from the blend coordinates */
380      error = FT_Err_Ok;
381
382      for ( n = 0; n < blend->num_designs; n++ )
383      {
384        FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
385
386
387        for ( m = 0; m < blend->num_axis; m++ )
388        {
389          FT_Fixed  factor;
390
391
392          /* get current blend axis position */
393          factor = coords[m];
394          if ( factor < 0 )
395            factor = 0;
396          if ( factor > 0x10000L )
397            factor = 0x10000L;
398
399          if ( ( n & ( 1 << m ) ) == 0 )
400            factor = 0x10000L - factor;
401
402          result = FT_MulFix( result, factor );
403        }
404        blend->weight_vector[n] = result;
405      }
406
407      error = FT_Err_Ok;
408    }
409
410    return error;
411  }
412
413
414  FT_LOCAL_DEF( FT_Error )
415  T1_Set_MM_Design( T1_Face   face,
416                    FT_UInt   num_coords,
417                    FT_Long*  coords )
418  {
419    PS_Blend  blend = face->blend;
420    FT_Error  error;
421    FT_UInt   n, p;
422
423
424    error = FT_ERR( Invalid_Argument );
425    if ( blend && blend->num_axis == num_coords )
426    {
427      /* compute the blend coordinates through the blend design map */
428      FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
429
430
431      for ( n = 0; n < blend->num_axis; n++ )
432      {
433        FT_Long       design  = coords[n];
434        FT_Fixed      the_blend;
435        PS_DesignMap  map     = blend->design_map + n;
436        FT_Long*      designs = map->design_points;
437        FT_Fixed*     blends  = map->blend_points;
438        FT_Int        before  = -1, after = -1;
439
440
441        for ( p = 0; p < (FT_UInt)map->num_points; p++ )
442        {
443          FT_Long  p_design = designs[p];
444
445
446          /* exact match? */
447          if ( design == p_design )
448          {
449            the_blend = blends[p];
450            goto Found;
451          }
452
453          if ( design < p_design )
454          {
455            after = p;
456            break;
457          }
458
459          before = p;
460        }
461
462        /* now interpolate if necessary */
463        if ( before < 0 )
464          the_blend = blends[0];
465
466        else if ( after < 0 )
467          the_blend = blends[map->num_points - 1];
468
469        else
470          the_blend = FT_MulDiv( design         - designs[before],
471                                 blends [after] - blends [before],
472                                 designs[after] - designs[before] );
473
474      Found:
475        final_blends[n] = the_blend;
476      }
477
478      error = T1_Set_MM_Blend( face, num_coords, final_blends );
479    }
480
481    return error;
482  }
483
484
485  /*************************************************************************/
486  /*                                                                       */
487  /* Just a wrapper around T1_Set_MM_Design to support the different       */
488  /* arguments needed by the GX var distortable fonts.                     */
489  /*                                                                       */
490  FT_LOCAL_DEF( FT_Error )
491  T1_Set_Var_Design( T1_Face    face,
492                     FT_UInt    num_coords,
493                     FT_Fixed*  coords )
494  {
495     FT_Long   lcoords[4];          /* maximum axis count is 4 */
496     FT_UInt   i;
497     FT_Error  error;
498
499
500     error = FT_ERR( Invalid_Argument );
501     if ( num_coords <= 4 && num_coords > 0 )
502     {
503       for ( i = 0; i < num_coords; ++i )
504         lcoords[i] = FIXED_TO_INT( coords[i] );
505       error = T1_Set_MM_Design( face, num_coords, lcoords );
506     }
507
508     return error;
509  }
510
511
512  FT_LOCAL_DEF( void )
513  T1_Done_Blend( T1_Face  face )
514  {
515    FT_Memory  memory = face->root.memory;
516    PS_Blend   blend  = face->blend;
517
518
519    if ( blend )
520    {
521      FT_UInt  num_designs = blend->num_designs;
522      FT_UInt  num_axis    = blend->num_axis;
523      FT_UInt  n;
524
525
526      /* release design pos table */
527      FT_FREE( blend->design_pos[0] );
528      for ( n = 1; n < num_designs; n++ )
529        blend->design_pos[n] = NULL;
530
531      /* release blend `private' and `font info' dictionaries */
532      FT_FREE( blend->privates[1] );
533      FT_FREE( blend->font_infos[1] );
534      FT_FREE( blend->bboxes[1] );
535
536      for ( n = 0; n < num_designs; n++ )
537      {
538        blend->privates  [n] = NULL;
539        blend->font_infos[n] = NULL;
540        blend->bboxes    [n] = NULL;
541      }
542
543      /* release weight vectors */
544      FT_FREE( blend->weight_vector );
545      blend->default_weight_vector = NULL;
546
547      /* release axis names */
548      for ( n = 0; n < num_axis; n++ )
549        FT_FREE( blend->axis_names[n] );
550
551      /* release design map */
552      for ( n = 0; n < num_axis; n++ )
553      {
554        PS_DesignMap  dmap = blend->design_map + n;
555
556
557        FT_FREE( dmap->design_points );
558        dmap->num_points = 0;
559      }
560
561      FT_FREE( face->blend );
562    }
563  }
564
565
566  static void
567  parse_blend_axis_types( T1_Face    face,
568                          T1_Loader  loader )
569  {
570    T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
571    FT_Int       n, num_axis;
572    FT_Error     error = FT_Err_Ok;
573    PS_Blend     blend;
574    FT_Memory    memory;
575
576
577    /* take an array of objects */
578    T1_ToTokenArray( &loader->parser, axis_tokens,
579                     T1_MAX_MM_AXIS, &num_axis );
580    if ( num_axis < 0 )
581    {
582      error = FT_ERR( Ignore );
583      goto Exit;
584    }
585    if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
586    {
587      FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
588                 num_axis ));
589      error = FT_THROW( Invalid_File_Format );
590      goto Exit;
591    }
592
593    /* allocate blend if necessary */
594    error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
595    if ( error )
596      goto Exit;
597
598    blend  = face->blend;
599    memory = face->root.memory;
600
601    /* each token is an immediate containing the name of the axis */
602    for ( n = 0; n < num_axis; n++ )
603    {
604      T1_Token    token = axis_tokens + n;
605      FT_Byte*    name;
606      FT_PtrDist  len;
607
608
609      /* skip first slash, if any */
610      if ( token->start[0] == '/' )
611        token->start++;
612
613      len = token->limit - token->start;
614      if ( len == 0 )
615      {
616        error = FT_THROW( Invalid_File_Format );
617        goto Exit;
618      }
619
620      if ( FT_ALLOC( blend->axis_names[n], (FT_Long)( len + 1 ) ) )
621        goto Exit;
622
623      name = (FT_Byte*)blend->axis_names[n];
624      FT_MEM_COPY( name, token->start, len );
625      name[len] = '\0';
626    }
627
628  Exit:
629    loader->parser.root.error = error;
630  }
631
632
633  static void
634  parse_blend_design_positions( T1_Face    face,
635                                T1_Loader  loader )
636  {
637    T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
638    FT_Int       num_designs;
639    FT_Int       num_axis;
640    T1_Parser    parser = &loader->parser;
641
642    FT_Error     error = FT_Err_Ok;
643    PS_Blend     blend;
644
645
646    /* get the array of design tokens -- compute number of designs */
647    T1_ToTokenArray( parser, design_tokens,
648                     T1_MAX_MM_DESIGNS, &num_designs );
649    if ( num_designs < 0 )
650    {
651      error = FT_ERR( Ignore );
652      goto Exit;
653    }
654    if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
655    {
656      FT_ERROR(( "parse_blend_design_positions:"
657                 " incorrect number of designs: %d\n",
658                 num_designs ));
659      error = FT_THROW( Invalid_File_Format );
660      goto Exit;
661    }
662
663    {
664      FT_Byte*  old_cursor = parser->root.cursor;
665      FT_Byte*  old_limit  = parser->root.limit;
666      FT_Int    n;
667
668
669      blend    = face->blend;
670      num_axis = 0;  /* make compiler happy */
671
672      for ( n = 0; n < num_designs; n++ )
673      {
674        T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
675        T1_Token     token;
676        FT_Int       axis, n_axis;
677
678
679        /* read axis/coordinates tokens */
680        token = design_tokens + n;
681        parser->root.cursor = token->start;
682        parser->root.limit  = token->limit;
683        T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
684
685        if ( n == 0 )
686        {
687          if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
688          {
689            FT_ERROR(( "parse_blend_design_positions:"
690                       " invalid number of axes: %d\n",
691                       n_axis ));
692            error = FT_THROW( Invalid_File_Format );
693            goto Exit;
694          }
695
696          num_axis = n_axis;
697          error = t1_allocate_blend( face, num_designs, num_axis );
698          if ( error )
699            goto Exit;
700          blend = face->blend;
701        }
702        else if ( n_axis != num_axis )
703        {
704          FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
705          error = FT_THROW( Invalid_File_Format );
706          goto Exit;
707        }
708
709        /* now read each axis token into the design position */
710        for ( axis = 0; axis < n_axis; axis++ )
711        {
712          T1_Token  token2 = axis_tokens + axis;
713
714
715          parser->root.cursor = token2->start;
716          parser->root.limit  = token2->limit;
717          blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
718        }
719      }
720
721      loader->parser.root.cursor = old_cursor;
722      loader->parser.root.limit  = old_limit;
723    }
724
725  Exit:
726    loader->parser.root.error = error;
727  }
728
729
730  static void
731  parse_blend_design_map( T1_Face    face,
732                          T1_Loader  loader )
733  {
734    FT_Error     error  = FT_Err_Ok;
735    T1_Parser    parser = &loader->parser;
736    PS_Blend     blend;
737    T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
738    FT_Int       n, num_axis;
739    FT_Byte*     old_cursor;
740    FT_Byte*     old_limit;
741    FT_Memory    memory = face->root.memory;
742
743
744    T1_ToTokenArray( parser, axis_tokens,
745                     T1_MAX_MM_AXIS, &num_axis );
746    if ( num_axis < 0 )
747    {
748      error = FT_ERR( Ignore );
749      goto Exit;
750    }
751    if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
752    {
753      FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
754                 num_axis ));
755      error = FT_THROW( Invalid_File_Format );
756      goto Exit;
757    }
758
759    old_cursor = parser->root.cursor;
760    old_limit  = parser->root.limit;
761
762    error = t1_allocate_blend( face, 0, num_axis );
763    if ( error )
764      goto Exit;
765    blend = face->blend;
766
767    /* now read each axis design map */
768    for ( n = 0; n < num_axis; n++ )
769    {
770      PS_DesignMap  map = blend->design_map + n;
771      T1_Token      axis_token;
772      T1_TokenRec   point_tokens[T1_MAX_MM_MAP_POINTS];
773      FT_Int        p, num_points;
774
775
776      axis_token = axis_tokens + n;
777
778      parser->root.cursor = axis_token->start;
779      parser->root.limit  = axis_token->limit;
780      T1_ToTokenArray( parser, point_tokens,
781                       T1_MAX_MM_MAP_POINTS, &num_points );
782
783      if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
784      {
785        FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
786        error = FT_THROW( Invalid_File_Format );
787        goto Exit;
788      }
789
790      /* allocate design map data */
791      if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
792        goto Exit;
793      map->blend_points = map->design_points + num_points;
794      map->num_points   = (FT_Byte)num_points;
795
796      for ( p = 0; p < num_points; p++ )
797      {
798        T1_Token  point_token;
799
800
801        point_token = point_tokens + p;
802
803        /* don't include delimiting brackets */
804        parser->root.cursor = point_token->start + 1;
805        parser->root.limit  = point_token->limit - 1;
806
807        map->design_points[p] = T1_ToInt( parser );
808        map->blend_points [p] = T1_ToFixed( parser, 0 );
809      }
810    }
811
812    parser->root.cursor = old_cursor;
813    parser->root.limit  = old_limit;
814
815  Exit:
816    parser->root.error = error;
817  }
818
819
820  static void
821  parse_weight_vector( T1_Face    face,
822                       T1_Loader  loader )
823  {
824    T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
825    FT_Int       num_designs;
826    FT_Error     error  = FT_Err_Ok;
827    T1_Parser    parser = &loader->parser;
828    PS_Blend     blend  = face->blend;
829    T1_Token     token;
830    FT_Int       n;
831    FT_Byte*     old_cursor;
832    FT_Byte*     old_limit;
833
834
835    T1_ToTokenArray( parser, design_tokens,
836                     T1_MAX_MM_DESIGNS, &num_designs );
837    if ( num_designs < 0 )
838    {
839      error = FT_ERR( Ignore );
840      goto Exit;
841    }
842    if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
843    {
844      FT_ERROR(( "parse_weight_vector:"
845                 " incorrect number of designs: %d\n",
846                 num_designs ));
847      error = FT_THROW( Invalid_File_Format );
848      goto Exit;
849    }
850
851    if ( !blend || !blend->num_designs )
852    {
853      error = t1_allocate_blend( face, num_designs, 0 );
854      if ( error )
855        goto Exit;
856      blend = face->blend;
857    }
858    else if ( blend->num_designs != (FT_UInt)num_designs )
859    {
860      FT_ERROR(( "parse_weight_vector:"
861                 " /BlendDesignPosition and /WeightVector have\n"
862                 "                    "
863                 " different number of elements\n" ));
864      error = FT_THROW( Invalid_File_Format );
865      goto Exit;
866    }
867
868    old_cursor = parser->root.cursor;
869    old_limit  = parser->root.limit;
870
871    for ( n = 0; n < num_designs; n++ )
872    {
873      token = design_tokens + n;
874      parser->root.cursor = token->start;
875      parser->root.limit  = token->limit;
876
877      blend->default_weight_vector[n] =
878      blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
879    }
880
881    parser->root.cursor = old_cursor;
882    parser->root.limit  = old_limit;
883
884  Exit:
885    parser->root.error = error;
886  }
887
888
889  /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
890  /* we're only interested in the number of array elements */
891  static void
892  parse_buildchar( T1_Face    face,
893                   T1_Loader  loader )
894  {
895    face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
896
897    return;
898  }
899
900
901#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
902
903
904
905
906  /*************************************************************************/
907  /*************************************************************************/
908  /*****                                                               *****/
909  /*****                      TYPE 1 SYMBOL PARSING                    *****/
910  /*****                                                               *****/
911  /*************************************************************************/
912  /*************************************************************************/
913
914  static FT_Error
915  t1_load_keyword( T1_Face         face,
916                   T1_Loader       loader,
917                   const T1_Field  field )
918  {
919    FT_Error  error;
920    void*     dummy_object;
921    void**    objects;
922    FT_UInt   max_objects;
923    PS_Blend  blend = face->blend;
924
925
926    if ( blend && blend->num_designs == 0 )
927      blend = NULL;
928
929    /* if the keyword has a dedicated callback, call it */
930    if ( field->type == T1_FIELD_TYPE_CALLBACK )
931    {
932      field->reader( (FT_Face)face, loader );
933      error = loader->parser.root.error;
934      goto Exit;
935    }
936
937    /* now, the keyword is either a simple field, or a table of fields; */
938    /* we are now going to take care of it                              */
939    switch ( field->location )
940    {
941    case T1_FIELD_LOCATION_FONT_INFO:
942      dummy_object = &face->type1.font_info;
943      objects      = &dummy_object;
944      max_objects  = 0;
945
946      if ( blend )
947      {
948        objects     = (void**)blend->font_infos;
949        max_objects = blend->num_designs;
950      }
951      break;
952
953    case T1_FIELD_LOCATION_FONT_EXTRA:
954      dummy_object = &face->type1.font_extra;
955      objects      = &dummy_object;
956      max_objects  = 0;
957      break;
958
959    case T1_FIELD_LOCATION_PRIVATE:
960      dummy_object = &face->type1.private_dict;
961      objects      = &dummy_object;
962      max_objects  = 0;
963
964      if ( blend )
965      {
966        objects     = (void**)blend->privates;
967        max_objects = blend->num_designs;
968      }
969      break;
970
971    case T1_FIELD_LOCATION_BBOX:
972      dummy_object = &face->type1.font_bbox;
973      objects      = &dummy_object;
974      max_objects  = 0;
975
976      if ( blend )
977      {
978        objects     = (void**)blend->bboxes;
979        max_objects = blend->num_designs;
980      }
981      break;
982
983    case T1_FIELD_LOCATION_LOADER:
984      dummy_object = loader;
985      objects      = &dummy_object;
986      max_objects  = 0;
987      break;
988
989    case T1_FIELD_LOCATION_FACE:
990      dummy_object = face;
991      objects      = &dummy_object;
992      max_objects  = 0;
993      break;
994
995#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
996    case T1_FIELD_LOCATION_BLEND:
997      dummy_object = face->blend;
998      objects      = &dummy_object;
999      max_objects  = 0;
1000      break;
1001#endif
1002
1003    default:
1004      dummy_object = &face->type1;
1005      objects      = &dummy_object;
1006      max_objects  = 0;
1007    }
1008
1009    if ( *objects )
1010    {
1011      if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1012           field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1013        error = T1_Load_Field_Table( &loader->parser, field,
1014                                     objects, max_objects, 0 );
1015      else
1016        error = T1_Load_Field( &loader->parser, field,
1017                               objects, max_objects, 0 );
1018    }
1019    else
1020    {
1021      FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'"
1022                  " which is not valid at this point\n"
1023                  "                 (probably due to missing keywords)\n",
1024                 field->ident ));
1025      error = FT_Err_Ok;
1026    }
1027
1028  Exit:
1029    return error;
1030  }
1031
1032
1033  static void
1034  parse_private( T1_Face    face,
1035                 T1_Loader  loader )
1036  {
1037    FT_UNUSED( face );
1038
1039    loader->keywords_encountered |= T1_PRIVATE;
1040  }
1041
1042
1043  static int
1044  read_binary_data( T1_Parser  parser,
1045                    FT_Long*   size,
1046                    FT_Byte**  base,
1047                    FT_Bool    incremental )
1048  {
1049    FT_Byte*  cur;
1050    FT_Byte*  limit = parser->root.limit;
1051
1052
1053    /* the binary data has one of the following formats */
1054    /*                                                  */
1055    /*   `size' [white*] RD white ....... ND            */
1056    /*   `size' [white*] -| white ....... |-            */
1057    /*                                                  */
1058
1059    T1_Skip_Spaces( parser );
1060
1061    cur = parser->root.cursor;
1062
1063    if ( cur < limit && ft_isdigit( *cur ) )
1064    {
1065      FT_Long  s = T1_ToInt( parser );
1066
1067
1068      T1_Skip_PS_Token( parser );   /* `RD' or `-|' or something else */
1069
1070      /* there is only one whitespace char after the */
1071      /* `RD' or `-|' token                          */
1072      *base = parser->root.cursor + 1;
1073
1074      if ( s >= 0 && s < limit - *base )
1075      {
1076        parser->root.cursor += s + 1;
1077        *size = s;
1078        return !parser->root.error;
1079      }
1080    }
1081
1082    if( !incremental )
1083    {
1084      FT_ERROR(( "read_binary_data: invalid size field\n" ));
1085      parser->root.error = FT_THROW( Invalid_File_Format );
1086    }
1087
1088    return 0;
1089  }
1090
1091
1092  /* We now define the routines to handle the `/Encoding', `/Subrs', */
1093  /* and `/CharStrings' dictionaries.                                */
1094
1095  static void
1096  t1_parse_font_matrix( T1_Face    face,
1097                        T1_Loader  loader )
1098  {
1099    T1_Parser   parser = &loader->parser;
1100    FT_Matrix*  matrix = &face->type1.font_matrix;
1101    FT_Vector*  offset = &face->type1.font_offset;
1102    FT_Face     root   = (FT_Face)&face->root;
1103    FT_Fixed    temp[6];
1104    FT_Fixed    temp_scale;
1105    FT_Int      result;
1106
1107
1108    result = T1_ToFixedArray( parser, 6, temp, 3 );
1109
1110    if ( result < 0 )
1111    {
1112      parser->root.error = FT_THROW( Invalid_File_Format );
1113      return;
1114    }
1115
1116    temp_scale = FT_ABS( temp[3] );
1117
1118    if ( temp_scale == 0 )
1119    {
1120      FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
1121      parser->root.error = FT_THROW( Invalid_File_Format );
1122      return;
1123    }
1124
1125    /* Set Units per EM based on FontMatrix values.  We set the value to */
1126    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
1127    /* 1000 (in t1_tofixed, from psobjs.c).                              */
1128
1129    root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
1130
1131    /* we need to scale the values by 1.0/temp_scale */
1132    if ( temp_scale != 0x10000L )
1133    {
1134      temp[0] = FT_DivFix( temp[0], temp_scale );
1135      temp[1] = FT_DivFix( temp[1], temp_scale );
1136      temp[2] = FT_DivFix( temp[2], temp_scale );
1137      temp[4] = FT_DivFix( temp[4], temp_scale );
1138      temp[5] = FT_DivFix( temp[5], temp_scale );
1139      temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
1140    }
1141
1142    matrix->xx = temp[0];
1143    matrix->yx = temp[1];
1144    matrix->xy = temp[2];
1145    matrix->yy = temp[3];
1146
1147    /* note that the offsets must be expressed in integer font units */
1148    offset->x = temp[4] >> 16;
1149    offset->y = temp[5] >> 16;
1150  }
1151
1152
1153  static void
1154  parse_encoding( T1_Face    face,
1155                  T1_Loader  loader )
1156  {
1157    T1_Parser  parser = &loader->parser;
1158    FT_Byte*   cur;
1159    FT_Byte*   limit  = parser->root.limit;
1160
1161    PSAux_Service  psaux = (PSAux_Service)face->psaux;
1162
1163
1164    T1_Skip_Spaces( parser );
1165    cur = parser->root.cursor;
1166    if ( cur >= limit )
1167    {
1168      FT_ERROR(( "parse_encoding: out of bounds\n" ));
1169      parser->root.error = FT_THROW( Invalid_File_Format );
1170      return;
1171    }
1172
1173    /* if we have a number or `[', the encoding is an array, */
1174    /* and we must load it now                               */
1175    if ( ft_isdigit( *cur ) || *cur == '[' )
1176    {
1177      T1_Encoding  encode          = &face->type1.encoding;
1178      FT_Int       count, n;
1179      PS_Table     char_table      = &loader->encoding_table;
1180      FT_Memory    memory          = parser->root.memory;
1181      FT_Error     error;
1182      FT_Bool      only_immediates = 0;
1183
1184
1185      /* read the number of entries in the encoding; should be 256 */
1186      if ( *cur == '[' )
1187      {
1188        count           = 256;
1189        only_immediates = 1;
1190        parser->root.cursor++;
1191      }
1192      else
1193        count = (FT_Int)T1_ToInt( parser );
1194
1195      T1_Skip_Spaces( parser );
1196      if ( parser->root.cursor >= limit )
1197        return;
1198
1199      /* we use a T1_Table to store our charnames */
1200      loader->num_chars = encode->num_chars = count;
1201      if ( FT_NEW_ARRAY( encode->char_index, count )     ||
1202           FT_NEW_ARRAY( encode->char_name,  count )     ||
1203           FT_SET_ERROR( psaux->ps_table_funcs->init(
1204                           char_table, count, memory ) ) )
1205      {
1206        parser->root.error = error;
1207        return;
1208      }
1209
1210      /* We need to `zero' out encoding_table.elements */
1211      for ( n = 0; n < count; n++ )
1212      {
1213        char*  notdef = (char *)".notdef";
1214
1215
1216        T1_Add_Table( char_table, n, notdef, 8 );
1217      }
1218
1219      /* Now we need to read records of the form                */
1220      /*                                                        */
1221      /*   ... charcode /charname ...                           */
1222      /*                                                        */
1223      /* for each entry in our table.                           */
1224      /*                                                        */
1225      /* We simply look for a number followed by an immediate   */
1226      /* name.  Note that this ignores correctly the sequence   */
1227      /* that is often seen in type1 fonts:                     */
1228      /*                                                        */
1229      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
1230      /*                                                        */
1231      /* used to clean the encoding array before anything else. */
1232      /*                                                        */
1233      /* Alternatively, if the array is directly given as       */
1234      /*                                                        */
1235      /*   /Encoding [ ... ]                                    */
1236      /*                                                        */
1237      /* we only read immediates.                               */
1238
1239      n = 0;
1240      T1_Skip_Spaces( parser );
1241
1242      while ( parser->root.cursor < limit )
1243      {
1244        cur = parser->root.cursor;
1245
1246        /* we stop when we encounter a `def' or `]' */
1247        if ( *cur == 'd' && cur + 3 < limit )
1248        {
1249          if ( cur[1] == 'e'         &&
1250               cur[2] == 'f'         &&
1251               IS_PS_DELIM( cur[3] ) )
1252          {
1253            FT_TRACE6(( "encoding end\n" ));
1254            cur += 3;
1255            break;
1256          }
1257        }
1258        if ( *cur == ']' )
1259        {
1260          FT_TRACE6(( "encoding end\n" ));
1261          cur++;
1262          break;
1263        }
1264
1265        /* check whether we've found an entry */
1266        if ( ft_isdigit( *cur ) || only_immediates )
1267        {
1268          FT_Int  charcode;
1269
1270
1271          if ( only_immediates )
1272            charcode = n;
1273          else
1274          {
1275            charcode = (FT_Int)T1_ToInt( parser );
1276            T1_Skip_Spaces( parser );
1277          }
1278
1279          cur = parser->root.cursor;
1280
1281          if ( cur + 2 < limit && *cur == '/' && n < count )
1282          {
1283            FT_PtrDist  len;
1284
1285
1286            cur++;
1287
1288            parser->root.cursor = cur;
1289            T1_Skip_PS_Token( parser );
1290            if ( parser->root.cursor >= limit )
1291              return;
1292            if ( parser->root.error )
1293              return;
1294
1295            len = parser->root.cursor - cur;
1296
1297            parser->root.error = T1_Add_Table( char_table, charcode,
1298                                               cur, len + 1 );
1299            if ( parser->root.error )
1300              return;
1301            char_table->elements[charcode][len] = '\0';
1302
1303            n++;
1304          }
1305          else if ( only_immediates )
1306          {
1307            /* Since the current position is not updated for           */
1308            /* immediates-only mode we would get an infinite loop if   */
1309            /* we don't do anything here.                              */
1310            /*                                                         */
1311            /* This encoding array is not valid according to the type1 */
1312            /* specification (it might be an encoding for a CID type1  */
1313            /* font, however), so we conclude that this font is NOT a  */
1314            /* type1 font.                                             */
1315            parser->root.error = FT_THROW( Unknown_File_Format );
1316            return;
1317          }
1318        }
1319        else
1320        {
1321          T1_Skip_PS_Token( parser );
1322          if ( parser->root.error )
1323            return;
1324        }
1325
1326        T1_Skip_Spaces( parser );
1327      }
1328
1329      face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
1330      parser->root.cursor       = cur;
1331    }
1332
1333    /* Otherwise, we should have either `StandardEncoding', */
1334    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
1335    else
1336    {
1337      if ( cur + 17 < limit                                            &&
1338           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
1339        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
1340
1341      else if ( cur + 15 < limit                                          &&
1342                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
1343        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
1344
1345      else if ( cur + 18 < limit                                             &&
1346                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
1347        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
1348
1349      else
1350        parser->root.error = FT_ERR( Ignore );
1351    }
1352  }
1353
1354
1355  static void
1356  parse_subrs( T1_Face    face,
1357               T1_Loader  loader )
1358  {
1359    T1_Parser  parser = &loader->parser;
1360    PS_Table   table  = &loader->subrs;
1361    FT_Memory  memory = parser->root.memory;
1362    FT_Error   error;
1363    FT_Int     num_subrs;
1364
1365    PSAux_Service  psaux = (PSAux_Service)face->psaux;
1366
1367
1368    T1_Skip_Spaces( parser );
1369
1370    /* test for empty array */
1371    if ( parser->root.cursor < parser->root.limit &&
1372         *parser->root.cursor == '['              )
1373    {
1374      T1_Skip_PS_Token( parser );
1375      T1_Skip_Spaces  ( parser );
1376      if ( parser->root.cursor >= parser->root.limit ||
1377           *parser->root.cursor != ']'               )
1378        parser->root.error = FT_THROW( Invalid_File_Format );
1379      return;
1380    }
1381
1382    num_subrs = (FT_Int)T1_ToInt( parser );
1383
1384    /* position the parser right before the `dup' of the first subr */
1385    T1_Skip_PS_Token( parser );         /* `array' */
1386    if ( parser->root.error )
1387      return;
1388    T1_Skip_Spaces( parser );
1389
1390    /* initialize subrs array -- with synthetic fonts it is possible */
1391    /* we get here twice                                             */
1392    if ( !loader->num_subrs )
1393    {
1394      error = psaux->ps_table_funcs->init( table, num_subrs, memory );
1395      if ( error )
1396        goto Fail;
1397    }
1398
1399    /* the format is simple:   */
1400    /*                         */
1401    /*   `index' + binary data */
1402    /*                         */
1403    for (;;)
1404    {
1405      FT_Long   idx, size;
1406      FT_Byte*  base;
1407
1408
1409      /* If we are out of data, or if the next token isn't `dup', */
1410      /* we are done.                                             */
1411      if ( parser->root.cursor + 4 >= parser->root.limit          ||
1412          ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
1413        break;
1414
1415      T1_Skip_PS_Token( parser );       /* `dup' */
1416
1417      idx = T1_ToInt( parser );
1418
1419      if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
1420        return;
1421
1422      /* The binary string is followed by one token, e.g. `NP' */
1423      /* (bound to `noaccess put') or by two separate tokens:  */
1424      /* `noaccess' & `put'.  We position the parser right     */
1425      /* before the next `dup', if any.                        */
1426      T1_Skip_PS_Token( parser );   /* `NP' or `|' or `noaccess' */
1427      if ( parser->root.error )
1428        return;
1429      T1_Skip_Spaces  ( parser );
1430
1431      if ( parser->root.cursor + 4 < parser->root.limit            &&
1432           ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
1433      {
1434        T1_Skip_PS_Token( parser ); /* skip `put' */
1435        T1_Skip_Spaces  ( parser );
1436      }
1437
1438      /* with synthetic fonts it is possible we get here twice */
1439      if ( loader->num_subrs )
1440        continue;
1441
1442      /* some fonts use a value of -1 for lenIV to indicate that */
1443      /* the charstrings are unencoded                           */
1444      /*                                                         */
1445      /* thanks to Tom Kacvinsky for pointing this out           */
1446      /*                                                         */
1447      if ( face->type1.private_dict.lenIV >= 0 )
1448      {
1449        FT_Byte*  temp;
1450
1451
1452        /* some fonts define empty subr records -- this is not totally */
1453        /* compliant to the specification (which says they should at   */
1454        /* least contain a `return'), but we support them anyway       */
1455        if ( size < face->type1.private_dict.lenIV )
1456        {
1457          error = FT_THROW( Invalid_File_Format );
1458          goto Fail;
1459        }
1460
1461        /* t1_decrypt() shouldn't write to base -- make temporary copy */
1462        if ( FT_ALLOC( temp, size ) )
1463          goto Fail;
1464        FT_MEM_COPY( temp, base, size );
1465        psaux->t1_decrypt( temp, size, 4330 );
1466        size -= face->type1.private_dict.lenIV;
1467        error = T1_Add_Table( table, (FT_Int)idx,
1468                              temp + face->type1.private_dict.lenIV, size );
1469        FT_FREE( temp );
1470      }
1471      else
1472        error = T1_Add_Table( table, (FT_Int)idx, base, size );
1473      if ( error )
1474        goto Fail;
1475    }
1476
1477    if ( !loader->num_subrs )
1478      loader->num_subrs = num_subrs;
1479
1480    return;
1481
1482  Fail:
1483    parser->root.error = error;
1484  }
1485
1486
1487#define TABLE_EXTEND  5
1488
1489
1490  static void
1491  parse_charstrings( T1_Face    face,
1492                     T1_Loader  loader )
1493  {
1494    T1_Parser      parser       = &loader->parser;
1495    PS_Table       code_table   = &loader->charstrings;
1496    PS_Table       name_table   = &loader->glyph_names;
1497    PS_Table       swap_table   = &loader->swap_table;
1498    FT_Memory      memory       = parser->root.memory;
1499    FT_Error       error;
1500
1501    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
1502
1503    FT_Byte*       cur;
1504    FT_Byte*       limit        = parser->root.limit;
1505    FT_Int         n, num_glyphs;
1506    FT_UInt        notdef_index = 0;
1507    FT_Byte        notdef_found = 0;
1508
1509
1510    num_glyphs = (FT_Int)T1_ToInt( parser );
1511    if ( num_glyphs < 0 )
1512    {
1513      error = FT_THROW( Invalid_File_Format );
1514      goto Fail;
1515    }
1516
1517    /* some fonts like Optima-Oblique not only define the /CharStrings */
1518    /* array but access it also                                        */
1519    if ( num_glyphs == 0 || parser->root.error )
1520      return;
1521
1522    /* initialize tables, leaving space for addition of .notdef, */
1523    /* if necessary, and a few other glyphs to handle buggy      */
1524    /* fonts which have more glyphs than specified.              */
1525
1526    /* for some non-standard fonts like `Optima' which provides  */
1527    /* different outlines depending on the resolution it is      */
1528    /* possible to get here twice                                */
1529    if ( !loader->num_glyphs )
1530    {
1531      error = psaux->ps_table_funcs->init(
1532                code_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1533      if ( error )
1534        goto Fail;
1535
1536      error = psaux->ps_table_funcs->init(
1537                name_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1538      if ( error )
1539        goto Fail;
1540
1541      /* Initialize table for swapping index notdef_index and */
1542      /* index 0 names and codes (if necessary).              */
1543
1544      error = psaux->ps_table_funcs->init( swap_table, 4, memory );
1545      if ( error )
1546        goto Fail;
1547    }
1548
1549    n = 0;
1550
1551    for (;;)
1552    {
1553      FT_Long   size;
1554      FT_Byte*  base;
1555
1556
1557      /* the format is simple:        */
1558      /*   `/glyphname' + binary data */
1559
1560      T1_Skip_Spaces( parser );
1561
1562      cur = parser->root.cursor;
1563      if ( cur >= limit )
1564        break;
1565
1566      /* we stop when we find a `def' or `end' keyword */
1567      if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) )
1568      {
1569        if ( cur[0] == 'd' &&
1570             cur[1] == 'e' &&
1571             cur[2] == 'f' )
1572        {
1573          /* There are fonts which have this: */
1574          /*                                  */
1575          /*   /CharStrings 118 dict def      */
1576          /*   Private begin                  */
1577          /*   CharStrings begin              */
1578          /*   ...                            */
1579          /*                                  */
1580          /* To catch this we ignore `def' if */
1581          /* no charstring has actually been  */
1582          /* seen.                            */
1583          if ( n )
1584            break;
1585        }
1586
1587        if ( cur[0] == 'e' &&
1588             cur[1] == 'n' &&
1589             cur[2] == 'd' )
1590          break;
1591      }
1592
1593      T1_Skip_PS_Token( parser );
1594      if ( parser->root.error )
1595        return;
1596
1597      if ( *cur == '/' )
1598      {
1599        FT_PtrDist  len;
1600
1601
1602        if ( cur + 1 >= limit )
1603        {
1604          error = FT_THROW( Invalid_File_Format );
1605          goto Fail;
1606        }
1607
1608        cur++;                              /* skip `/' */
1609        len = parser->root.cursor - cur;
1610
1611        if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
1612          return;
1613		/* xhl: Add boundary check here. Fix the bug reported by ifilter. */
1614		/* TESTDOC: bug# 0018509, 45.pdf. */
1615		if (base + size >= limit) {
1616			error = T1_Err_Invalid_File_Format;
1617			goto Fail;
1618		}
1619        /* for some non-standard fonts like `Optima' which provides */
1620        /* different outlines depending on the resolution it is     */
1621        /* possible to get here twice                               */
1622        if ( loader->num_glyphs )
1623          continue;
1624
1625        error = T1_Add_Table( name_table, n, cur, len + 1 );
1626        if ( error )
1627          goto Fail;
1628
1629        /* add a trailing zero to the name table */
1630        name_table->elements[n][len] = '\0';
1631
1632        /* record index of /.notdef */
1633        if ( *cur == '.'                                              &&
1634             ft_strcmp( ".notdef",
1635                        (const char*)(name_table->elements[n]) ) == 0 )
1636        {
1637          notdef_index = n;
1638          notdef_found = 1;
1639        }
1640
1641        if ( face->type1.private_dict.lenIV >= 0 &&
1642             n < num_glyphs + TABLE_EXTEND       )
1643        {
1644          FT_Byte*  temp;
1645
1646
1647          if ( size <= face->type1.private_dict.lenIV )
1648          {
1649            error = FT_THROW( Invalid_File_Format );
1650            goto Fail;
1651          }
1652
1653          /* t1_decrypt() shouldn't write to base -- make temporary copy */
1654          if ( FT_ALLOC( temp, size ) )
1655            goto Fail;
1656          FT_MEM_COPY( temp, base, size );
1657          psaux->t1_decrypt( temp, size, 4330 );
1658          size -= face->type1.private_dict.lenIV;
1659          error = T1_Add_Table( code_table, n,
1660                                temp + face->type1.private_dict.lenIV, size );
1661          FT_FREE( temp );
1662        }
1663        else
1664          error = T1_Add_Table( code_table, n, base, size );
1665        if ( error )
1666          goto Fail;
1667
1668        n++;
1669      }
1670    }
1671
1672    loader->num_glyphs = n;
1673
1674    /* if /.notdef is found but does not occupy index 0, do our magic. */
1675    if ( notdef_found                                                 &&
1676         ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
1677    {
1678      /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
1679      /* name and code entries to swap_table.  Then place notdef_index   */
1680      /* name and code entries into swap_table.  Then swap name and code */
1681      /* entries at indices notdef_index and 0 using values stored in    */
1682      /* swap_table.                                                     */
1683
1684      /* Index 0 name */
1685      error = T1_Add_Table( swap_table, 0,
1686                            name_table->elements[0],
1687                            name_table->lengths [0] );
1688      if ( error )
1689        goto Fail;
1690
1691      /* Index 0 code */
1692      error = T1_Add_Table( swap_table, 1,
1693                            code_table->elements[0],
1694                            code_table->lengths [0] );
1695      if ( error )
1696        goto Fail;
1697
1698      /* Index notdef_index name */
1699      error = T1_Add_Table( swap_table, 2,
1700                            name_table->elements[notdef_index],
1701                            name_table->lengths [notdef_index] );
1702      if ( error )
1703        goto Fail;
1704
1705      /* Index notdef_index code */
1706      error = T1_Add_Table( swap_table, 3,
1707                            code_table->elements[notdef_index],
1708                            code_table->lengths [notdef_index] );
1709      if ( error )
1710        goto Fail;
1711
1712      error = T1_Add_Table( name_table, notdef_index,
1713                            swap_table->elements[0],
1714                            swap_table->lengths [0] );
1715      if ( error )
1716        goto Fail;
1717
1718      error = T1_Add_Table( code_table, notdef_index,
1719                            swap_table->elements[1],
1720                            swap_table->lengths [1] );
1721      if ( error )
1722        goto Fail;
1723
1724      error = T1_Add_Table( name_table, 0,
1725                            swap_table->elements[2],
1726                            swap_table->lengths [2] );
1727      if ( error )
1728        goto Fail;
1729
1730      error = T1_Add_Table( code_table, 0,
1731                            swap_table->elements[3],
1732                            swap_table->lengths [3] );
1733      if ( error )
1734        goto Fail;
1735
1736    }
1737    else if ( !notdef_found )
1738    {
1739      /* notdef_index is already 0, or /.notdef is undefined in   */
1740      /* charstrings dictionary.  Worry about /.notdef undefined. */
1741      /* We take index 0 and add it to the end of the table(s)    */
1742      /* and add our own /.notdef glyph to index 0.               */
1743
1744      /* 0 333 hsbw endchar */
1745      FT_Byte  notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E };
1746      char*    notdef_name    = (char *)".notdef";
1747
1748
1749      error = T1_Add_Table( swap_table, 0,
1750                            name_table->elements[0],
1751                            name_table->lengths [0] );
1752      if ( error )
1753        goto Fail;
1754
1755      error = T1_Add_Table( swap_table, 1,
1756                            code_table->elements[0],
1757                            code_table->lengths [0] );
1758      if ( error )
1759        goto Fail;
1760
1761      error = T1_Add_Table( name_table, 0, notdef_name, 8 );
1762      if ( error )
1763        goto Fail;
1764
1765      error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
1766
1767      if ( error )
1768        goto Fail;
1769
1770      error = T1_Add_Table( name_table, n,
1771                            swap_table->elements[0],
1772                            swap_table->lengths [0] );
1773      if ( error )
1774        goto Fail;
1775
1776      error = T1_Add_Table( code_table, n,
1777                            swap_table->elements[1],
1778                            swap_table->lengths [1] );
1779      if ( error )
1780        goto Fail;
1781
1782      /* we added a glyph. */
1783      loader->num_glyphs += 1;
1784    }
1785
1786    return;
1787
1788  Fail:
1789    parser->root.error = error;
1790  }
1791
1792
1793  /*************************************************************************/
1794  /*                                                                       */
1795  /* Define the token field static variables.  This is a set of            */
1796  /* T1_FieldRec variables.                                                */
1797  /*                                                                       */
1798  /*************************************************************************/
1799
1800
1801  static
1802  const T1_FieldRec  t1_keywords[] =
1803  {
1804
1805#include "t1tokens.h"
1806
1807    /* now add the special functions... */
1808    T1_FIELD_CALLBACK( "FontMatrix",           t1_parse_font_matrix,
1809                       T1_FIELD_DICT_FONTDICT )
1810    T1_FIELD_CALLBACK( "Encoding",             parse_encoding,
1811                       T1_FIELD_DICT_FONTDICT )
1812    T1_FIELD_CALLBACK( "Subrs",                parse_subrs,
1813                       T1_FIELD_DICT_PRIVATE )
1814    T1_FIELD_CALLBACK( "CharStrings",          parse_charstrings,
1815                       T1_FIELD_DICT_PRIVATE )
1816    T1_FIELD_CALLBACK( "Private",              parse_private,
1817                       T1_FIELD_DICT_FONTDICT )
1818
1819#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
1820    T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions,
1821                       T1_FIELD_DICT_FONTDICT )
1822    T1_FIELD_CALLBACK( "BlendDesignMap",       parse_blend_design_map,
1823                       T1_FIELD_DICT_FONTDICT )
1824    T1_FIELD_CALLBACK( "BlendAxisTypes",       parse_blend_axis_types,
1825                       T1_FIELD_DICT_FONTDICT )
1826    T1_FIELD_CALLBACK( "WeightVector",         parse_weight_vector,
1827                       T1_FIELD_DICT_FONTDICT )
1828    T1_FIELD_CALLBACK( "BuildCharArray",       parse_buildchar,
1829                       T1_FIELD_DICT_PRIVATE )
1830#endif
1831
1832    { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
1833  };
1834
1835
1836#define T1_FIELD_COUNT                                           \
1837          ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) )
1838
1839
1840  static FT_Error
1841  parse_dict( T1_Face    face,
1842              T1_Loader  loader,
1843              FT_Byte*   base,
1844              FT_Long    size )
1845  {
1846    T1_Parser  parser = &loader->parser;
1847    FT_Byte   *limit, *start_binary = NULL;
1848    FT_Bool    have_integer = 0;
1849
1850
1851    parser->root.cursor = base;
1852    parser->root.limit  = base + size;
1853    parser->root.error  = FT_Err_Ok;
1854
1855    limit = parser->root.limit;
1856
1857    T1_Skip_Spaces( parser );
1858
1859    while ( parser->root.cursor < limit )
1860    {
1861      FT_Byte*  cur;
1862
1863
1864      cur = parser->root.cursor;
1865
1866      /* look for `eexec' */
1867      if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
1868        break;
1869
1870      /* look for `closefile' which ends the eexec section */
1871      else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
1872        break;
1873
1874      /* in a synthetic font the base font starts after a           */
1875      /* `FontDictionary' token that is placed after a Private dict */
1876      else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
1877      {
1878        if ( loader->keywords_encountered & T1_PRIVATE )
1879          loader->keywords_encountered |=
1880            T1_FONTDIR_AFTER_PRIVATE;
1881        parser->root.cursor += 13;
1882      }
1883
1884      /* check whether we have an integer */
1885      else if ( ft_isdigit( *cur ) )
1886      {
1887        start_binary = cur;
1888        T1_Skip_PS_Token( parser );
1889        if ( parser->root.error )
1890          goto Exit;
1891        have_integer = 1;
1892      }
1893
1894      /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
1895      /* since those tokens are handled by parse_subrs and        */
1896      /* parse_charstrings                                        */
1897      else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' &&
1898                have_integer )
1899      {
1900        FT_Long   s;
1901        FT_Byte*  b;
1902
1903
1904        parser->root.cursor = start_binary;
1905        if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
1906          return FT_THROW( Invalid_File_Format );
1907        have_integer = 0;
1908      }
1909
1910      else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' &&
1911                have_integer )
1912      {
1913        FT_Long   s;
1914        FT_Byte*  b;
1915
1916
1917        parser->root.cursor = start_binary;
1918        if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
1919          return FT_THROW( Invalid_File_Format );
1920        have_integer = 0;
1921      }
1922
1923      /* look for immediates */
1924      else if ( *cur == '/' && cur + 2 < limit )
1925      {
1926        FT_PtrDist  len;
1927
1928
1929        cur++;
1930
1931        parser->root.cursor = cur;
1932        T1_Skip_PS_Token( parser );
1933        if ( parser->root.error )
1934          goto Exit;
1935
1936        len = parser->root.cursor - cur;
1937
1938        if ( len > 0 && len < 22 && parser->root.cursor < limit )
1939        {
1940          /* now compare the immediate name to the keyword table */
1941          T1_Field  keyword = (T1_Field)t1_keywords;
1942
1943
1944          for (;;)
1945          {
1946            FT_Byte*  name;
1947
1948
1949            name = (FT_Byte*)keyword->ident;
1950            if ( !name )
1951              break;
1952
1953            if ( cur[0] == name[0]                                  &&
1954                 len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
1955                 ft_memcmp( cur, name, len ) == 0                   )
1956            {
1957              /* We found it -- run the parsing callback!     */
1958              /* We record every instance of every field      */
1959              /* (until we reach the base font of a           */
1960              /* synthetic font) to deal adequately with      */
1961              /* multiple master fonts; this is also          */
1962              /* necessary because later PostScript           */
1963              /* definitions override earlier ones.           */
1964
1965              /* Once we encounter `FontDirectory' after      */
1966              /* `/Private', we know that this is a synthetic */
1967              /* font; except for `/CharStrings' we are not   */
1968              /* interested in anything that follows this     */
1969              /* `FontDirectory'.                             */
1970
1971              /* MM fonts have more than one /Private token at */
1972              /* the top level; let's hope that all the junk   */
1973              /* that follows the first /Private token is not  */
1974              /* interesting to us.                            */
1975
1976              /* According to Adobe Tech Note #5175 (CID-Keyed */
1977              /* Font Installation for ATM Software) a `begin' */
1978              /* must be followed by exactly one `end', and    */
1979              /* `begin' -- `end' pairs must be accurately     */
1980              /* paired.  We could use this to distinguish     */
1981              /* between the global Private and the Private    */
1982              /* dict that is a member of the Blend dict.      */
1983
1984              const FT_UInt dict =
1985                ( loader->keywords_encountered & T1_PRIVATE )
1986                    ? T1_FIELD_DICT_PRIVATE
1987                    : T1_FIELD_DICT_FONTDICT;
1988
1989              if ( !( dict & keyword->dict ) )
1990              {
1991                FT_TRACE1(( "parse_dict: found `%s' but ignoring it"
1992                            " since it is in the wrong dictionary\n",
1993                            keyword->ident ));
1994                break;
1995              }
1996
1997              if ( !( loader->keywords_encountered &
1998                      T1_FONTDIR_AFTER_PRIVATE     )                  ||
1999                   ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
2000              {
2001                parser->root.error = t1_load_keyword( face,
2002                                                      loader,
2003                                                      keyword );
2004                if ( parser->root.error != FT_Err_Ok )
2005                {
2006                  if ( FT_ERR_EQ( parser->root.error, Ignore ) )
2007                    parser->root.error = FT_Err_Ok;
2008                  else
2009                    return parser->root.error;
2010                }
2011              }
2012              break;
2013            }
2014
2015            keyword++;
2016          }
2017        }
2018
2019        have_integer = 0;
2020      }
2021      else
2022      {
2023        T1_Skip_PS_Token( parser );
2024        if ( parser->root.error )
2025          goto Exit;
2026        have_integer = 0;
2027      }
2028
2029      T1_Skip_Spaces( parser );
2030    }
2031
2032  Exit:
2033    return parser->root.error;
2034  }
2035
2036
2037  static void
2038  t1_init_loader( T1_Loader  loader,
2039                  T1_Face    face )
2040  {
2041    FT_UNUSED( face );
2042
2043    FT_MEM_ZERO( loader, sizeof ( *loader ) );
2044    loader->num_glyphs = 0;
2045    loader->num_chars  = 0;
2046
2047    /* initialize the tables -- simply set their `init' field to 0 */
2048    loader->encoding_table.init  = 0;
2049    loader->charstrings.init     = 0;
2050    loader->glyph_names.init     = 0;
2051    loader->subrs.init           = 0;
2052    loader->swap_table.init      = 0;
2053    loader->fontdata             = 0;
2054    loader->keywords_encountered = 0;
2055  }
2056
2057
2058  static void
2059  t1_done_loader( T1_Loader  loader )
2060  {
2061    T1_Parser  parser = &loader->parser;
2062
2063
2064    /* finalize tables */
2065    T1_Release_Table( &loader->encoding_table );
2066    T1_Release_Table( &loader->charstrings );
2067    T1_Release_Table( &loader->glyph_names );
2068    T1_Release_Table( &loader->swap_table );
2069    T1_Release_Table( &loader->subrs );
2070
2071    /* finalize parser */
2072    T1_Finalize_Parser( parser );
2073  }
2074
2075
2076  FT_LOCAL_DEF( FT_Error )
2077  T1_Open_Face( T1_Face  face )
2078  {
2079    T1_LoaderRec   loader;
2080    T1_Parser      parser;
2081    T1_Font        type1 = &face->type1;
2082    PS_Private     priv  = &type1->private_dict;
2083    FT_Error       error;
2084
2085    PSAux_Service  psaux = (PSAux_Service)face->psaux;
2086
2087
2088    t1_init_loader( &loader, face );
2089
2090    /* default values */
2091    face->ndv_idx          = -1;
2092    face->cdv_idx          = -1;
2093    face->len_buildchar    = 0;
2094
2095    priv->blue_shift       = 7;
2096    priv->blue_fuzz        = 1;
2097    priv->lenIV            = 4;
2098    priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
2099    priv->blue_scale       = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
2100
2101    parser = &loader.parser;
2102    error  = T1_New_Parser( parser,
2103                            face->root.stream,
2104                            face->root.memory,
2105                            psaux );
2106    if ( error )
2107      goto Exit;
2108
2109    error = parse_dict( face, &loader,
2110                        parser->base_dict, parser->base_len );
2111    if ( error )
2112      goto Exit;
2113
2114    error = T1_Get_Private_Dict( parser, psaux );
2115    if ( error )
2116      goto Exit;
2117
2118    error = parse_dict( face, &loader,
2119                        parser->private_dict, parser->private_len );
2120    if ( error )
2121      goto Exit;
2122
2123    /* ensure even-ness of `num_blue_values' */
2124    priv->num_blue_values &= ~1;
2125
2126#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
2127
2128    if ( face->blend                                                     &&
2129         face->blend->num_default_design_vector != 0                     &&
2130         face->blend->num_default_design_vector != face->blend->num_axis )
2131    {
2132      /* we don't use it currently so just warn, reset, and ignore */
2133      FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
2134                 "while there are %u axes.\n",
2135                 face->blend->num_default_design_vector,
2136                 face->blend->num_axis ));
2137
2138      face->blend->num_default_design_vector = 0;
2139    }
2140
2141    /* the following can happen for MM instances; we then treat the */
2142    /* font as a normal PS font                                     */
2143    if ( face->blend                                             &&
2144         ( !face->blend->num_designs || !face->blend->num_axis ) )
2145      T1_Done_Blend( face );
2146
2147    /* another safety check */
2148    if ( face->blend )
2149    {
2150      FT_UInt  i;
2151
2152
2153      for ( i = 0; i < face->blend->num_axis; i++ )
2154        if ( !face->blend->design_map[i].num_points )
2155        {
2156          T1_Done_Blend( face );
2157          break;
2158        }
2159    }
2160
2161    if ( face->blend )
2162    {
2163      if ( face->len_buildchar > 0 )
2164      {
2165        FT_Memory  memory = face->root.memory;
2166
2167
2168        if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) )
2169        {
2170          FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" ));
2171          face->len_buildchar = 0;
2172          goto Exit;
2173        }
2174      }
2175    }
2176    else
2177      face->len_buildchar = 0;
2178
2179#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
2180
2181    /* now, propagate the subrs, charstrings, and glyphnames tables */
2182    /* to the Type1 data                                            */
2183    type1->num_glyphs = loader.num_glyphs;
2184
2185    if ( loader.subrs.init )
2186    {
2187      loader.subrs.init  = 0;
2188      type1->num_subrs   = loader.num_subrs;
2189      type1->subrs_block = loader.subrs.block;
2190      type1->subrs       = loader.subrs.elements;
2191      type1->subrs_len   = loader.subrs.lengths;
2192    }
2193
2194    if ( !IS_INCREMENTAL )
2195      if ( !loader.charstrings.init )
2196      {
2197        FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
2198        error = FT_THROW( Invalid_File_Format );
2199      }
2200
2201    loader.charstrings.init  = 0;
2202    type1->charstrings_block = loader.charstrings.block;
2203    type1->charstrings       = loader.charstrings.elements;
2204    type1->charstrings_len   = loader.charstrings.lengths;
2205
2206    /* we copy the glyph names `block' and `elements' fields; */
2207    /* the `lengths' field must be released later             */
2208    type1->glyph_names_block    = loader.glyph_names.block;
2209    type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
2210    loader.glyph_names.block    = 0;
2211    loader.glyph_names.elements = 0;
2212
2213    /* we must now build type1.encoding when we have a custom array */
2214    if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
2215    {
2216      FT_Int    charcode, idx, min_char, max_char;
2217      FT_Byte*  char_name;
2218      FT_Byte*  glyph_name;
2219
2220
2221      /* OK, we do the following: for each element in the encoding  */
2222      /* table, look up the index of the glyph having the same name */
2223      /* the index is then stored in type1.encoding.char_index, and */
2224      /* the name to type1.encoding.char_name                       */
2225
2226      min_char = 0;
2227      max_char = 0;
2228
2229      charcode = 0;
2230      for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
2231      {
2232        type1->encoding.char_index[charcode] = 0;
2233        type1->encoding.char_name [charcode] = (char *)".notdef";
2234
2235        char_name = loader.encoding_table.elements[charcode];
2236        if ( char_name )
2237          for ( idx = 0; idx < type1->num_glyphs; idx++ )
2238          {
2239            glyph_name = (FT_Byte*)type1->glyph_names[idx];
2240            if ( ft_strcmp( (const char*)char_name,
2241                            (const char*)glyph_name ) == 0 )
2242            {
2243              type1->encoding.char_index[charcode] = (FT_UShort)idx;
2244              type1->encoding.char_name [charcode] = (char*)glyph_name;
2245
2246              /* Change min/max encoded char only if glyph name is */
2247              /* not /.notdef                                      */
2248              if ( ft_strcmp( (const char*)".notdef",
2249                              (const char*)glyph_name ) != 0 )
2250              {
2251                if ( charcode < min_char )
2252                  min_char = charcode;
2253                if ( charcode >= max_char )
2254                  max_char = charcode + 1;
2255              }
2256              break;
2257            }
2258          }
2259      }
2260
2261      type1->encoding.code_first = min_char;
2262      type1->encoding.code_last  = max_char;
2263      type1->encoding.num_chars  = loader.num_chars;
2264    }
2265
2266  Exit:
2267    t1_done_loader( &loader );
2268    return error;
2269  }
2270
2271
2272/* END */
2273