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