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 */
962