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