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