XFA: merge patch from CL 815103002
[pdfium.git] / third_party / freetype / src / psaux / afmparse.c
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
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*
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*
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 )
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* )
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
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 )
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 )
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 )
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
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;
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 )
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
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;
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
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
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 )
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 */