1 /***************************************************************************/
2 /*                                                                         */
3 /*  afmparse.c                                                             */
4 /*                                                                         */
5 /*    AFM parser (body).                                                   */
6 /*                                                                         */
7 /*  Copyright 2006-2010, 2012, 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 #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           ( (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_UInt n)370   afm_parser_read_vals( AFM_Parser  parser,
371                         AFM_Value   vals,
372                         FT_UInt     n )
373   {
374     AFM_Stream  stream = parser->stream;
375     char*       str;
376     FT_UInt     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    = 0;  /* 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 = FT_Err_Ok;
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   FT_LOCAL_DEF( 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 
594 
595     if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
596         goto Fail;
597 
598     if ( fi->NumTrackKern )
599     {
600       FT_Memory  memory = parser->memory;
601       FT_Error   error = FT_Err_Ok;
602 
603 
604       if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
605         return error;
606     }
607 
608     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
609     {
610       AFM_ValueRec  shared_vals[5];
611 
612 
613       switch ( afm_tokenize( key, len ) )
614       {
615       case AFM_TOKEN_TRACKKERN:
616         n++;
617 
618         if ( n >= fi->NumTrackKern )
619           goto Fail;
620 
621         tk = fi->TrackKerns + n;
622 
623         shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
624         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
625         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
626         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
627         shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
628         if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
629           goto Fail;
630 
631         tk->degree     = shared_vals[0].u.i;
632         tk->min_ptsize = shared_vals[1].u.f;
633         tk->min_kern   = shared_vals[2].u.f;
634         tk->max_ptsize = shared_vals[3].u.f;
635         tk->max_kern   = shared_vals[4].u.f;
636 
637         break;
638 
639       case AFM_TOKEN_ENDTRACKKERN:
640       case AFM_TOKEN_ENDKERNDATA:
641       case AFM_TOKEN_ENDFONTMETRICS:
642         fi->NumTrackKern = n + 1;
643         return FT_Err_Ok;
644 
645       case AFM_TOKEN_UNKNOWN:
646         break;
647 
648       default:
649         goto Fail;
650       }
651     }
652 
653   Fail:
654     return FT_THROW( Syntax_Error );
655   }
656 
657 
658 #undef  KERN_INDEX
659 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
660 
661 
662   /* compare two kerning pairs */
663   FT_CALLBACK_DEF( int )
afm_compare_kern_pairs(const void * a,const void * b)664   afm_compare_kern_pairs( const void*  a,
665                           const void*  b )
666   {
667     AFM_KernPair  kp1 = (AFM_KernPair)a;
668     AFM_KernPair  kp2 = (AFM_KernPair)b;
669 
670     FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
671     FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
672 
673 
674     if ( index1 > index2 )
675       return 1;
676     else if ( index1 < index2 )
677       return -1;
678     else
679       return 0;
680   }
681 
682 
683   static FT_Error
afm_parse_kern_pairs(AFM_Parser parser)684   afm_parse_kern_pairs( AFM_Parser  parser )
685   {
686     AFM_FontInfo  fi = parser->FontInfo;
687     AFM_KernPair  kp;
688     char*         key;
689     FT_Offset     len;
690     int           n = -1;
691 
692 
693     if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
694       goto Fail;
695 
696     if ( fi->NumKernPair )
697     {
698       FT_Memory  memory = parser->memory;
699       FT_Error   error = FT_Err_Ok;
700 
701 
702       if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
703         return error;
704     }
705 
706     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
707     {
708       AFM_Token  token = afm_tokenize( key, len );
709 
710 
711       switch ( token )
712       {
713       case AFM_TOKEN_KP:
714       case AFM_TOKEN_KPX:
715       case AFM_TOKEN_KPY:
716         {
717           FT_Int        r;
718           AFM_ValueRec  shared_vals[4];
719 
720 
721           n++;
722 
723           if ( n >= fi->NumKernPair )
724             goto Fail;
725 
726           kp = fi->KernPairs + n;
727 
728           shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
729           shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
730           shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
731           shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
732           r = afm_parser_read_vals( parser, shared_vals, 4 );
733           if ( r < 3 )
734             goto Fail;
735 
736           kp->index1 = shared_vals[0].u.i;
737           kp->index2 = shared_vals[1].u.i;
738           if ( token == AFM_TOKEN_KPY )
739           {
740             kp->x = 0;
741             kp->y = shared_vals[2].u.i;
742           }
743           else
744           {
745             kp->x = shared_vals[2].u.i;
746             kp->y = ( token == AFM_TOKEN_KP && r == 4 )
747                       ? shared_vals[3].u.i : 0;
748           }
749         }
750         break;
751 
752       case AFM_TOKEN_ENDKERNPAIRS:
753       case AFM_TOKEN_ENDKERNDATA:
754       case AFM_TOKEN_ENDFONTMETRICS:
755         fi->NumKernPair = n + 1;
756         ft_qsort( fi->KernPairs, fi->NumKernPair,
757                   sizeof ( AFM_KernPairRec ),
758                   afm_compare_kern_pairs );
759         return FT_Err_Ok;
760 
761       case AFM_TOKEN_UNKNOWN:
762         break;
763 
764       default:
765         goto Fail;
766       }
767     }
768 
769   Fail:
770     return FT_THROW( Syntax_Error );
771   }
772 
773 
774   static FT_Error
afm_parse_kern_data(AFM_Parser parser)775   afm_parse_kern_data( AFM_Parser  parser )
776   {
777     FT_Error   error;
778     char*      key;
779     FT_Offset  len;
780 
781 
782     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
783     {
784       switch ( afm_tokenize( key, len ) )
785       {
786       case AFM_TOKEN_STARTTRACKKERN:
787         error = afm_parse_track_kern( parser );
788         if ( error )
789           return error;
790         break;
791 
792       case AFM_TOKEN_STARTKERNPAIRS:
793       case AFM_TOKEN_STARTKERNPAIRS0:
794         error = afm_parse_kern_pairs( parser );
795         if ( error )
796           return error;
797         break;
798 
799       case AFM_TOKEN_ENDKERNDATA:
800       case AFM_TOKEN_ENDFONTMETRICS:
801         return FT_Err_Ok;
802 
803       case AFM_TOKEN_UNKNOWN:
804         break;
805 
806       default:
807         goto Fail;
808       }
809     }
810 
811   Fail:
812     return FT_THROW( Syntax_Error );
813   }
814 
815 
816   static FT_Error
afm_parser_skip_section(AFM_Parser parser,FT_UInt n,AFM_Token end_section)817   afm_parser_skip_section( AFM_Parser  parser,
818                            FT_UInt     n,
819                            AFM_Token   end_section )
820   {
821     char*      key;
822     FT_Offset  len;
823 
824 
825     while ( n-- > 0 )
826     {
827       key = afm_parser_next_key( parser, 1, NULL );
828       if ( !key )
829         goto Fail;
830     }
831 
832     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
833     {
834       AFM_Token  token = afm_tokenize( key, len );
835 
836 
837       if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
838         return FT_Err_Ok;
839     }
840 
841   Fail:
842     return FT_THROW( Syntax_Error );
843   }
844 
845 
846   FT_LOCAL_DEF( FT_Error )
afm_parser_parse(AFM_Parser parser)847   afm_parser_parse( AFM_Parser  parser )
848   {
849     FT_Memory     memory = parser->memory;
850     AFM_FontInfo  fi     = parser->FontInfo;
851     FT_Error      error  = FT_ERR( Syntax_Error );
852     char*         key;
853     FT_Offset     len;
854     FT_Int        metrics_sets = 0;
855 
856 
857     if ( !fi )
858       return FT_THROW( Invalid_Argument );
859 
860     key = afm_parser_next_key( parser, 1, &len );
861     if ( !key || len != 16                              ||
862          ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
863       return FT_THROW( Unknown_File_Format );
864 
865     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
866     {
867       AFM_ValueRec  shared_vals[4];
868 
869 
870       switch ( afm_tokenize( key, len ) )
871       {
872       case AFM_TOKEN_METRICSSETS:
873         if ( afm_parser_read_int( parser, &metrics_sets ) )
874           goto Fail;
875 
876         if ( metrics_sets != 0 && metrics_sets != 2 )
877         {
878           error = FT_THROW( Unimplemented_Feature );
879 
880           goto Fail;
881         }
882         break;
883 
884       case AFM_TOKEN_ISCIDFONT:
885         shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
886         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
887           goto Fail;
888 
889         fi->IsCIDFont = shared_vals[0].u.b;
890         break;
891 
892       case AFM_TOKEN_FONTBBOX:
893         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
894         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
895         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
896         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
897         if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
898           goto Fail;
899 
900         fi->FontBBox.xMin = shared_vals[0].u.f;
901         fi->FontBBox.yMin = shared_vals[1].u.f;
902         fi->FontBBox.xMax = shared_vals[2].u.f;
903         fi->FontBBox.yMax = shared_vals[3].u.f;
904         break;
905 
906       case AFM_TOKEN_ASCENDER:
907         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
908         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
909           goto Fail;
910 
911         fi->Ascender = shared_vals[0].u.f;
912         break;
913 
914       case AFM_TOKEN_DESCENDER:
915         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
916         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
917           goto Fail;
918 
919         fi->Descender = shared_vals[0].u.f;
920         break;
921 
922       case AFM_TOKEN_STARTCHARMETRICS:
923         {
924           FT_Int  n = 0;
925 
926 
927           if ( afm_parser_read_int( parser, &n ) )
928             goto Fail;
929 
930           error = afm_parser_skip_section( parser, n,
931                                            AFM_TOKEN_ENDCHARMETRICS );
932           if ( error )
933             return error;
934         }
935         break;
936 
937       case AFM_TOKEN_STARTKERNDATA:
938         error = afm_parse_kern_data( parser );
939         if ( error )
940           goto Fail;
941         /* fall through since we only support kern data */
942 
943       case AFM_TOKEN_ENDFONTMETRICS:
944         return FT_Err_Ok;
945 
946       default:
947         break;
948       }
949     }
950 
951   Fail:
952     FT_FREE( fi->TrackKerns );
953     fi->NumTrackKern = 0;
954 
955     FT_FREE( fi->KernPairs );
956     fi->NumKernPair = 0;
957 
958     fi->IsCIDFont = 0;
959 
960     return error;
961   }
962 
963 
964 /* END */
965