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