• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  afmparse.c                                                             */
4 /*                                                                         */
5 /*    AFM parser (body).                                                   */
6 /*                                                                         */
7 /*  Copyright 2006, 2007, 2008 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 #include <ft2build.h>
19 #include FT_FREETYPE_H
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
21 #include FT_INTERNAL_DEBUG_H
22 
23 #include "afmparse.h"
24 #include "psconv.h"
25 
26 #include "psauxerr.h"
27 
28 
29 /***************************************************************************/
30 /*                                                                         */
31 /*    AFM_Stream                                                           */
32 /*                                                                         */
33 /* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.  */
34 /*                                                                         */
35 /*                                                                         */
36 
37   enum
38   {
39     AFM_STREAM_STATUS_NORMAL,
40     AFM_STREAM_STATUS_EOC,
41     AFM_STREAM_STATUS_EOL,
42     AFM_STREAM_STATUS_EOF
43   };
44 
45 
46   typedef struct  AFM_StreamRec_
47   {
48     FT_Byte*  cursor;
49     FT_Byte*  base;
50     FT_Byte*  limit;
51 
52     FT_Int    status;
53 
54   } AFM_StreamRec;
55 
56 
57 #ifndef EOF
58 #define EOF -1
59 #endif
60 
61 
62   /* this works because empty lines are ignored */
63 #define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )
64 
65 #define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
66 #define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )
67 
68   /* column separator; there is no `column' in the spec actually */
69 #define AFM_IS_SEP( ch )      ( (ch) == ';' )
70 
71 #define AFM_GETC()                                                       \
72           ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
73                                                    : EOF )
74 
75 #define AFM_STREAM_KEY_BEGIN( stream )    \
76           (char*)( (stream)->cursor - 1 )
77 
78 #define AFM_STREAM_KEY_LEN( stream, key )       \
79           ( (char*)(stream)->cursor - key - 1 )
80 
81 #define AFM_STATUS_EOC( stream ) \
82           ( (stream)->status >= AFM_STREAM_STATUS_EOC )
83 
84 #define AFM_STATUS_EOL( stream ) \
85           ( (stream)->status >= AFM_STREAM_STATUS_EOL )
86 
87 #define AFM_STATUS_EOF( stream ) \
88           ( (stream)->status >= AFM_STREAM_STATUS_EOF )
89 
90 
91   static int
afm_stream_skip_spaces(AFM_Stream stream)92   afm_stream_skip_spaces( AFM_Stream  stream )
93   {
94     int  ch = 0;  /* make stupid compiler happy */
95 
96 
97     if ( AFM_STATUS_EOC( stream ) )
98       return ';';
99 
100     while ( 1 )
101     {
102       ch = AFM_GETC();
103       if ( !AFM_IS_SPACE( ch ) )
104         break;
105     }
106 
107     if ( AFM_IS_NEWLINE( ch ) )
108       stream->status = AFM_STREAM_STATUS_EOL;
109     else if ( AFM_IS_SEP( ch ) )
110       stream->status = AFM_STREAM_STATUS_EOC;
111     else if ( AFM_IS_EOF( ch ) )
112       stream->status = AFM_STREAM_STATUS_EOF;
113 
114     return ch;
115   }
116 
117 
118   /* read a key or value in current column */
119   static char*
afm_stream_read_one(AFM_Stream stream)120   afm_stream_read_one( AFM_Stream  stream )
121   {
122     char*  str;
123     int    ch;
124 
125 
126     afm_stream_skip_spaces( stream );
127     if ( AFM_STATUS_EOC( stream ) )
128       return NULL;
129 
130     str = AFM_STREAM_KEY_BEGIN( stream );
131 
132     while ( 1 )
133     {
134       ch = AFM_GETC();
135       if ( AFM_IS_SPACE( ch ) )
136         break;
137       else if ( AFM_IS_NEWLINE( ch ) )
138       {
139         stream->status = AFM_STREAM_STATUS_EOL;
140         break;
141       }
142       else if ( AFM_IS_SEP( ch ) )
143       {
144         stream->status = AFM_STREAM_STATUS_EOC;
145         break;
146       }
147       else if ( AFM_IS_EOF( ch ) )
148       {
149         stream->status = AFM_STREAM_STATUS_EOF;
150         break;
151       }
152     }
153 
154     return str;
155   }
156 
157 
158   /* read a string (i.e., read to EOL) */
159   static char*
afm_stream_read_string(AFM_Stream stream)160   afm_stream_read_string( AFM_Stream  stream )
161   {
162     char*  str;
163     int    ch;
164 
165 
166     afm_stream_skip_spaces( stream );
167     if ( AFM_STATUS_EOL( stream ) )
168       return NULL;
169 
170     str = AFM_STREAM_KEY_BEGIN( stream );
171 
172     /* scan to eol */
173     while ( 1 )
174     {
175       ch = AFM_GETC();
176       if ( AFM_IS_NEWLINE( ch ) )
177       {
178         stream->status = AFM_STREAM_STATUS_EOL;
179         break;
180       }
181       else if ( AFM_IS_EOF( ch ) )
182       {
183         stream->status = AFM_STREAM_STATUS_EOF;
184         break;
185       }
186     }
187 
188     return str;
189   }
190 
191 
192   /*************************************************************************/
193   /*                                                                       */
194   /*    AFM_Parser                                                         */
195   /*                                                                       */
196   /*                                                                       */
197 
198   /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
199   typedef enum  AFM_Token_
200   {
201     AFM_TOKEN_ASCENDER,
202     AFM_TOKEN_AXISLABEL,
203     AFM_TOKEN_AXISTYPE,
204     AFM_TOKEN_B,
205     AFM_TOKEN_BLENDAXISTYPES,
206     AFM_TOKEN_BLENDDESIGNMAP,
207     AFM_TOKEN_BLENDDESIGNPOSITIONS,
208     AFM_TOKEN_C,
209     AFM_TOKEN_CC,
210     AFM_TOKEN_CH,
211     AFM_TOKEN_CAPHEIGHT,
212     AFM_TOKEN_CHARWIDTH,
213     AFM_TOKEN_CHARACTERSET,
214     AFM_TOKEN_CHARACTERS,
215     AFM_TOKEN_DESCENDER,
216     AFM_TOKEN_ENCODINGSCHEME,
217     AFM_TOKEN_ENDAXIS,
218     AFM_TOKEN_ENDCHARMETRICS,
219     AFM_TOKEN_ENDCOMPOSITES,
220     AFM_TOKEN_ENDDIRECTION,
221     AFM_TOKEN_ENDFONTMETRICS,
222     AFM_TOKEN_ENDKERNDATA,
223     AFM_TOKEN_ENDKERNPAIRS,
224     AFM_TOKEN_ENDTRACKKERN,
225     AFM_TOKEN_ESCCHAR,
226     AFM_TOKEN_FAMILYNAME,
227     AFM_TOKEN_FONTBBOX,
228     AFM_TOKEN_FONTNAME,
229     AFM_TOKEN_FULLNAME,
230     AFM_TOKEN_ISBASEFONT,
231     AFM_TOKEN_ISCIDFONT,
232     AFM_TOKEN_ISFIXEDPITCH,
233     AFM_TOKEN_ISFIXEDV,
234     AFM_TOKEN_ITALICANGLE,
235     AFM_TOKEN_KP,
236     AFM_TOKEN_KPH,
237     AFM_TOKEN_KPX,
238     AFM_TOKEN_KPY,
239     AFM_TOKEN_L,
240     AFM_TOKEN_MAPPINGSCHEME,
241     AFM_TOKEN_METRICSSETS,
242     AFM_TOKEN_N,
243     AFM_TOKEN_NOTICE,
244     AFM_TOKEN_PCC,
245     AFM_TOKEN_STARTAXIS,
246     AFM_TOKEN_STARTCHARMETRICS,
247     AFM_TOKEN_STARTCOMPOSITES,
248     AFM_TOKEN_STARTDIRECTION,
249     AFM_TOKEN_STARTFONTMETRICS,
250     AFM_TOKEN_STARTKERNDATA,
251     AFM_TOKEN_STARTKERNPAIRS,
252     AFM_TOKEN_STARTKERNPAIRS0,
253     AFM_TOKEN_STARTKERNPAIRS1,
254     AFM_TOKEN_STARTTRACKKERN,
255     AFM_TOKEN_STDHW,
256     AFM_TOKEN_STDVW,
257     AFM_TOKEN_TRACKKERN,
258     AFM_TOKEN_UNDERLINEPOSITION,
259     AFM_TOKEN_UNDERLINETHICKNESS,
260     AFM_TOKEN_VV,
261     AFM_TOKEN_VVECTOR,
262     AFM_TOKEN_VERSION,
263     AFM_TOKEN_W,
264     AFM_TOKEN_W0,
265     AFM_TOKEN_W0X,
266     AFM_TOKEN_W0Y,
267     AFM_TOKEN_W1,
268     AFM_TOKEN_W1X,
269     AFM_TOKEN_W1Y,
270     AFM_TOKEN_WX,
271     AFM_TOKEN_WY,
272     AFM_TOKEN_WEIGHT,
273     AFM_TOKEN_WEIGHTVECTOR,
274     AFM_TOKEN_XHEIGHT,
275     N_AFM_TOKENS,
276     AFM_TOKEN_UNKNOWN
277 
278   } AFM_Token;
279 
280 
281   static const char*  const afm_key_table[N_AFM_TOKENS] =
282   {
283     "Ascender",
284     "AxisLabel",
285     "AxisType",
286     "B",
287     "BlendAxisTypes",
288     "BlendDesignMap",
289     "BlendDesignPositions",
290     "C",
291     "CC",
292     "CH",
293     "CapHeight",
294     "CharWidth",
295     "CharacterSet",
296     "Characters",
297     "Descender",
298     "EncodingScheme",
299     "EndAxis",
300     "EndCharMetrics",
301     "EndComposites",
302     "EndDirection",
303     "EndFontMetrics",
304     "EndKernData",
305     "EndKernPairs",
306     "EndTrackKern",
307     "EscChar",
308     "FamilyName",
309     "FontBBox",
310     "FontName",
311     "FullName",
312     "IsBaseFont",
313     "IsCIDFont",
314     "IsFixedPitch",
315     "IsFixedV",
316     "ItalicAngle",
317     "KP",
318     "KPH",
319     "KPX",
320     "KPY",
321     "L",
322     "MappingScheme",
323     "MetricsSets",
324     "N",
325     "Notice",
326     "PCC",
327     "StartAxis",
328     "StartCharMetrics",
329     "StartComposites",
330     "StartDirection",
331     "StartFontMetrics",
332     "StartKernData",
333     "StartKernPairs",
334     "StartKernPairs0",
335     "StartKernPairs1",
336     "StartTrackKern",
337     "StdHW",
338     "StdVW",
339     "TrackKern",
340     "UnderlinePosition",
341     "UnderlineThickness",
342     "VV",
343     "VVector",
344     "Version",
345     "W",
346     "W0",
347     "W0X",
348     "W0Y",
349     "W1",
350     "W1X",
351     "W1Y",
352     "WX",
353     "WY",
354     "Weight",
355     "WeightVector",
356     "XHeight"
357   };
358 
359 
360   /*
361    * `afm_parser_read_vals' and `afm_parser_next_key' provide
362    * high-level operations to an AFM_Stream.  The rest of the
363    * parser functions should use them without accessing the
364    * AFM_Stream directly.
365    */
366 
367   FT_LOCAL_DEF( FT_Int )
afm_parser_read_vals(AFM_Parser parser,AFM_Value vals,FT_Int n)368   afm_parser_read_vals( AFM_Parser  parser,
369                         AFM_Value   vals,
370                         FT_Int      n )
371   {
372     AFM_Stream  stream = parser->stream;
373     char*       str;
374     FT_Int      i;
375 
376 
377     if ( n > AFM_MAX_ARGUMENTS )
378       return 0;
379 
380     for ( i = 0; i < n; i++ )
381     {
382       FT_UInt    len;
383       AFM_Value  val = vals + i;
384 
385 
386       if ( val->type == AFM_VALUE_TYPE_STRING )
387         str = afm_stream_read_string( stream );
388       else
389         str = afm_stream_read_one( stream );
390 
391       if ( !str )
392         break;
393 
394       len = AFM_STREAM_KEY_LEN( stream, str );
395 
396       switch ( val->type )
397       {
398       case AFM_VALUE_TYPE_STRING:
399       case AFM_VALUE_TYPE_NAME:
400         {
401           FT_Memory  memory = parser->memory;
402           FT_Error   error;
403 
404 
405           if ( !FT_QALLOC( val->u.s, len + 1 ) )
406           {
407             ft_memcpy( val->u.s, str, len );
408             val->u.s[len] = '\0';
409           }
410         }
411         break;
412 
413       case AFM_VALUE_TYPE_FIXED:
414         val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
415                                     (FT_Byte*)str + len, 0 );
416         break;
417 
418       case AFM_VALUE_TYPE_INTEGER:
419         val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
420                                   (FT_Byte*)str + len );
421         break;
422 
423       case AFM_VALUE_TYPE_BOOL:
424         val->u.b = FT_BOOL( len == 4                      &&
425                             !ft_strncmp( str, "true", 4 ) );
426         break;
427 
428       case AFM_VALUE_TYPE_INDEX:
429         if ( parser->get_index )
430           val->u.i = parser->get_index( str, len, parser->user_data );
431         else
432           val->u.i = 0;
433         break;
434       }
435     }
436 
437     return i;
438   }
439 
440 
441   FT_LOCAL_DEF( char* )
afm_parser_next_key(AFM_Parser parser,FT_Bool line,FT_UInt * len)442   afm_parser_next_key( AFM_Parser  parser,
443                        FT_Bool     line,
444                        FT_UInt*    len )
445   {
446     AFM_Stream  stream = parser->stream;
447     char*       key    = 0;  /* make stupid compiler happy */
448 
449 
450     if ( line )
451     {
452       while ( 1 )
453       {
454         /* skip current line */
455         if ( !AFM_STATUS_EOL( stream ) )
456           afm_stream_read_string( stream );
457 
458         stream->status = AFM_STREAM_STATUS_NORMAL;
459         key = afm_stream_read_one( stream );
460 
461         /* skip empty line */
462         if ( !key                      &&
463              !AFM_STATUS_EOF( stream ) &&
464              AFM_STATUS_EOL( stream )  )
465           continue;
466 
467         break;
468       }
469     }
470     else
471     {
472       while ( 1 )
473       {
474         /* skip current column */
475         while ( !AFM_STATUS_EOC( stream ) )
476           afm_stream_read_one( stream );
477 
478         stream->status = AFM_STREAM_STATUS_NORMAL;
479         key = afm_stream_read_one( stream );
480 
481         /* skip empty column */
482         if ( !key                      &&
483              !AFM_STATUS_EOF( stream ) &&
484              AFM_STATUS_EOC( stream )  )
485           continue;
486 
487         break;
488       }
489     }
490 
491     if ( len )
492       *len = ( key ) ? AFM_STREAM_KEY_LEN( stream, key )
493                      : 0;
494 
495     return key;
496   }
497 
498 
499   static AFM_Token
afm_tokenize(const char * key,FT_UInt len)500   afm_tokenize( const char*  key,
501                 FT_UInt      len )
502   {
503     int  n;
504 
505 
506     for ( n = 0; n < N_AFM_TOKENS; n++ )
507     {
508       if ( *( afm_key_table[n] ) == *key )
509       {
510         for ( ; n < N_AFM_TOKENS; n++ )
511         {
512           if ( *( afm_key_table[n] ) != *key )
513             return AFM_TOKEN_UNKNOWN;
514 
515           if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
516             return (AFM_Token) n;
517         }
518       }
519     }
520 
521     return AFM_TOKEN_UNKNOWN;
522   }
523 
524 
525   FT_LOCAL_DEF( FT_Error )
afm_parser_init(AFM_Parser parser,FT_Memory memory,FT_Byte * base,FT_Byte * limit)526   afm_parser_init( AFM_Parser  parser,
527                    FT_Memory   memory,
528                    FT_Byte*    base,
529                    FT_Byte*    limit )
530   {
531     AFM_Stream  stream;
532     FT_Error    error;
533 
534 
535     if ( FT_NEW( stream ) )
536       return error;
537 
538     stream->cursor = stream->base = base;
539     stream->limit  = limit;
540 
541     /* don't skip the first line during the first call */
542     stream->status = AFM_STREAM_STATUS_EOL;
543 
544     parser->memory    = memory;
545     parser->stream    = stream;
546     parser->FontInfo  = NULL;
547     parser->get_index = NULL;
548 
549     return PSaux_Err_Ok;
550   }
551 
552 
553   FT_LOCAL( void )
afm_parser_done(AFM_Parser parser)554   afm_parser_done( AFM_Parser  parser )
555   {
556     FT_Memory  memory = parser->memory;
557 
558 
559     FT_FREE( parser->stream );
560   }
561 
562 
563   FT_LOCAL_DEF( FT_Error )
afm_parser_read_int(AFM_Parser parser,FT_Int * aint)564   afm_parser_read_int( AFM_Parser  parser,
565                        FT_Int*     aint )
566   {
567     AFM_ValueRec  val;
568 
569 
570     val.type = AFM_VALUE_TYPE_INTEGER;
571 
572     if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
573     {
574       *aint = val.u.i;
575 
576       return PSaux_Err_Ok;
577     }
578     else
579       return PSaux_Err_Syntax_Error;
580   }
581 
582 
583   static FT_Error
afm_parse_track_kern(AFM_Parser parser)584   afm_parse_track_kern( AFM_Parser  parser )
585   {
586     AFM_FontInfo   fi = parser->FontInfo;
587     AFM_TrackKern  tk;
588     char*          key;
589     FT_UInt        len;
590     int            n = -1;
591 
592 
593     if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
594         goto Fail;
595 
596     if ( fi->NumTrackKern )
597     {
598       FT_Memory  memory = parser->memory;
599       FT_Error   error;
600 
601 
602       if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
603         return error;
604     }
605 
606     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
607     {
608       AFM_ValueRec  shared_vals[5];
609 
610 
611       switch ( afm_tokenize( key, len ) )
612       {
613       case AFM_TOKEN_TRACKKERN:
614         n++;
615 
616         if ( n >= fi->NumTrackKern )
617           goto Fail;
618 
619         tk = fi->TrackKerns + n;
620 
621         shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
622         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
623         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
624         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
625         shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
626         if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
627           goto Fail;
628 
629         tk->degree     = shared_vals[0].u.i;
630         tk->min_ptsize = shared_vals[1].u.f;
631         tk->min_kern   = shared_vals[2].u.f;
632         tk->max_ptsize = shared_vals[3].u.f;
633         tk->max_kern   = shared_vals[4].u.f;
634 
635         /* is this correct? */
636         if ( tk->degree < 0 && tk->min_kern > 0 )
637           tk->min_kern = -tk->min_kern;
638         break;
639 
640       case AFM_TOKEN_ENDTRACKKERN:
641       case AFM_TOKEN_ENDKERNDATA:
642       case AFM_TOKEN_ENDFONTMETRICS:
643         fi->NumTrackKern = n + 1;
644         return PSaux_Err_Ok;
645 
646       case AFM_TOKEN_UNKNOWN:
647         break;
648 
649       default:
650         goto Fail;
651       }
652     }
653 
654   Fail:
655     return PSaux_Err_Syntax_Error;
656   }
657 
658 
659 #undef  KERN_INDEX
660 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
661 
662 
663   /* compare two kerning pairs */
664   FT_CALLBACK_DEF( int )
afm_compare_kern_pairs(const void * a,const void * b)665   afm_compare_kern_pairs( const void*  a,
666                           const void*  b )
667   {
668     AFM_KernPair  kp1 = (AFM_KernPair)a;
669     AFM_KernPair  kp2 = (AFM_KernPair)b;
670 
671     FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
672     FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
673 
674 
675     if ( index1 > index2 )
676       return 1;
677     else if ( index1 < index2 )
678       return -1;
679     else
680       return 0;
681   }
682 
683 
684   static FT_Error
afm_parse_kern_pairs(AFM_Parser parser)685   afm_parse_kern_pairs( AFM_Parser  parser )
686   {
687     AFM_FontInfo  fi = parser->FontInfo;
688     AFM_KernPair  kp;
689     char*         key;
690     FT_UInt       len;
691     int           n = -1;
692 
693 
694     if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
695       goto Fail;
696 
697     if ( fi->NumKernPair )
698     {
699       FT_Memory  memory = parser->memory;
700       FT_Error   error;
701 
702 
703       if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
704         return error;
705     }
706 
707     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
708     {
709       AFM_Token  token = afm_tokenize( key, len );
710 
711 
712       switch ( token )
713       {
714       case AFM_TOKEN_KP:
715       case AFM_TOKEN_KPX:
716       case AFM_TOKEN_KPY:
717         {
718           FT_Int        r;
719           AFM_ValueRec  shared_vals[4];
720 
721 
722           n++;
723 
724           if ( n >= fi->NumKernPair )
725             goto Fail;
726 
727           kp = fi->KernPairs + n;
728 
729           shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
730           shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
731           shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
732           shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
733           r = afm_parser_read_vals( parser, shared_vals, 4 );
734           if ( r < 3 )
735             goto Fail;
736 
737           kp->index1 = shared_vals[0].u.i;
738           kp->index2 = shared_vals[1].u.i;
739           if ( token == AFM_TOKEN_KPY )
740           {
741             kp->x = 0;
742             kp->y = shared_vals[2].u.i;
743           }
744           else
745           {
746             kp->x = shared_vals[2].u.i;
747             kp->y = ( token == AFM_TOKEN_KP && r == 4 )
748                       ? shared_vals[3].u.i : 0;
749           }
750         }
751         break;
752 
753       case AFM_TOKEN_ENDKERNPAIRS:
754       case AFM_TOKEN_ENDKERNDATA:
755       case AFM_TOKEN_ENDFONTMETRICS:
756         fi->NumKernPair = n + 1;
757         ft_qsort( fi->KernPairs, fi->NumKernPair,
758                   sizeof( AFM_KernPairRec ),
759                   afm_compare_kern_pairs );
760         return PSaux_Err_Ok;
761 
762       case AFM_TOKEN_UNKNOWN:
763         break;
764 
765       default:
766         goto Fail;
767       }
768     }
769 
770   Fail:
771     return PSaux_Err_Syntax_Error;
772   }
773 
774 
775   static FT_Error
afm_parse_kern_data(AFM_Parser parser)776   afm_parse_kern_data( AFM_Parser  parser )
777   {
778     FT_Error  error;
779     char*     key;
780     FT_UInt   len;
781 
782 
783     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
784     {
785       switch ( afm_tokenize( key, len ) )
786       {
787       case AFM_TOKEN_STARTTRACKKERN:
788         error = afm_parse_track_kern( parser );
789         if ( error )
790           return error;
791         break;
792 
793       case AFM_TOKEN_STARTKERNPAIRS:
794       case AFM_TOKEN_STARTKERNPAIRS0:
795         error = afm_parse_kern_pairs( parser );
796         if ( error )
797           return error;
798         break;
799 
800       case AFM_TOKEN_ENDKERNDATA:
801       case AFM_TOKEN_ENDFONTMETRICS:
802         return PSaux_Err_Ok;
803 
804       case AFM_TOKEN_UNKNOWN:
805         break;
806 
807       default:
808         goto Fail;
809       }
810     }
811 
812   Fail:
813     return PSaux_Err_Syntax_Error;
814   }
815 
816 
817   static FT_Error
afm_parser_skip_section(AFM_Parser parser,FT_UInt n,AFM_Token end_section)818   afm_parser_skip_section( AFM_Parser  parser,
819                            FT_UInt     n,
820                            AFM_Token   end_section )
821   {
822     char*    key;
823     FT_UInt  len;
824 
825 
826     while ( n-- > 0 )
827     {
828       key = afm_parser_next_key( parser, 1, NULL );
829       if ( !key )
830         goto Fail;
831     }
832 
833     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
834     {
835       AFM_Token  token = afm_tokenize( key, len );
836 
837 
838       if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
839         return PSaux_Err_Ok;
840     }
841 
842   Fail:
843     return PSaux_Err_Syntax_Error;
844   }
845 
846 
847   FT_LOCAL_DEF( FT_Error )
afm_parser_parse(AFM_Parser parser)848   afm_parser_parse( AFM_Parser  parser )
849   {
850     FT_Memory     memory = parser->memory;
851     AFM_FontInfo  fi     = parser->FontInfo;
852     FT_Error      error  = PSaux_Err_Syntax_Error;
853     char*         key;
854     FT_UInt       len;
855     FT_Int        metrics_sets = 0;
856 
857 
858     if ( !fi )
859       return PSaux_Err_Invalid_Argument;
860 
861     key = afm_parser_next_key( parser, 1, &len );
862     if ( !key || len != 16                              ||
863          ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
864       return PSaux_Err_Unknown_File_Format;
865 
866     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
867     {
868       AFM_ValueRec  shared_vals[4];
869 
870 
871       switch ( afm_tokenize( key, len ) )
872       {
873       case AFM_TOKEN_METRICSSETS:
874         if ( afm_parser_read_int( parser, &metrics_sets ) )
875           goto Fail;
876 
877         if ( metrics_sets != 0 && metrics_sets != 2 )
878         {
879           error = PSaux_Err_Unimplemented_Feature;
880 
881           goto Fail;
882         }
883         break;
884 
885       case AFM_TOKEN_ISCIDFONT:
886         shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
887         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
888           goto Fail;
889 
890         fi->IsCIDFont = shared_vals[0].u.b;
891         break;
892 
893       case AFM_TOKEN_FONTBBOX:
894         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
895         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
896         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
897         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
898         if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
899           goto Fail;
900 
901         fi->FontBBox.xMin = shared_vals[0].u.f;
902         fi->FontBBox.yMin = shared_vals[1].u.f;
903         fi->FontBBox.xMax = shared_vals[2].u.f;
904         fi->FontBBox.yMax = shared_vals[3].u.f;
905         break;
906 
907       case AFM_TOKEN_ASCENDER:
908         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
909         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
910           goto Fail;
911 
912         fi->Ascender = shared_vals[0].u.f;
913         break;
914 
915       case AFM_TOKEN_DESCENDER:
916         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
917         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
918           goto Fail;
919 
920         fi->Descender = shared_vals[0].u.f;
921         break;
922 
923       case AFM_TOKEN_STARTCHARMETRICS:
924         {
925           FT_Int  n = 0;
926 
927 
928           if ( afm_parser_read_int( parser, &n ) )
929             goto Fail;
930 
931           error = afm_parser_skip_section( parser, n,
932                                            AFM_TOKEN_ENDCHARMETRICS );
933           if ( error )
934             return error;
935         }
936         break;
937 
938       case AFM_TOKEN_STARTKERNDATA:
939         error = afm_parse_kern_data( parser );
940         if ( error )
941           goto Fail;
942         /* fall through since we only support kern data */
943 
944       case AFM_TOKEN_ENDFONTMETRICS:
945         return PSaux_Err_Ok;
946 
947       default:
948         break;
949       }
950     }
951 
952   Fail:
953     FT_FREE( fi->TrackKerns );
954     fi->NumTrackKern = 0;
955 
956     FT_FREE( fi->KernPairs );
957     fi->NumKernPair = 0;
958 
959     fi->IsCIDFont = 0;
960 
961     return error;
962   }
963 
964 
965 /* END */
966