PageRenderTime 101ms CodeModel.GetById 36ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/freetype2/src/psaux/afmparse.c

http://github.com/zpao/v8monkey
C | 964 lines | 718 code | 197 blank | 49 comment | 124 complexity | d16e233056495797643b21e9257f802f MD5 | raw file
  1/***************************************************************************/
  2/*                                                                         */
  3/*  afmparse.c                                                             */
  4/*                                                                         */
  5/*    AFM parser (body).                                                   */
  6/*                                                                         */
  7/*  Copyright 2006, 2007, 2008, 2009, 2010 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        /* is this correct? */
635        if ( tk->degree < 0 && tk->min_kern > 0 )
636          tk->min_kern = -tk->min_kern;
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 PSaux_Err_Ok;
644
645      case AFM_TOKEN_UNKNOWN:
646        break;
647
648      default:
649        goto Fail;
650      }
651    }
652
653  Fail:
654    return PSaux_Err_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 PSaux_Err_Ok;
760
761      case AFM_TOKEN_UNKNOWN:
762        break;
763
764      default:
765        goto Fail;
766      }
767    }
768
769  Fail:
770    return PSaux_Err_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 PSaux_Err_Ok;
802
803      case AFM_TOKEN_UNKNOWN:
804        break;
805
806      default:
807        goto Fail;
808      }
809    }
810
811  Fail:
812    return PSaux_Err_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 PSaux_Err_Ok;
839    }
840
841  Fail:
842    return PSaux_Err_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  = PSaux_Err_Syntax_Error;
852    char*         key;
853    FT_Offset     len;
854    FT_Int        metrics_sets = 0;
855
856
857    if ( !fi )
858      return PSaux_Err_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 PSaux_Err_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 = PSaux_Err_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 PSaux_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 */