Home | History | Annotate | Download | only in psaux
      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 */
    965