Home | History | Annotate | Download | only in psaux
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  afmparse.c                                                             */
      4 /*                                                                         */
      5 /*    AFM parser (body).                                                   */
      6 /*                                                                         */
      7 /*  Copyright 2006-2015 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           (FT_Offset)( (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_Int      n )
    373   {
    374     AFM_Stream  stream = parser->stream;
    375     char*       str;
    376     FT_Int      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    = NULL;  /* 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   static 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     FT_Int         tmp;
    594 
    595 
    596     if ( afm_parser_read_int( parser, &tmp ) )
    597         goto Fail;
    598 
    599     if ( tmp < 0 )
    600       goto Fail;
    601 
    602     fi->NumTrackKern = (FT_UInt)tmp;
    603 
    604     if ( fi->NumTrackKern )
    605     {
    606       FT_Memory  memory = parser->memory;
    607       FT_Error   error;
    608 
    609 
    610       if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
    611         return error;
    612     }
    613 
    614     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    615     {
    616       AFM_ValueRec  shared_vals[5];
    617 
    618 
    619       switch ( afm_tokenize( key, len ) )
    620       {
    621       case AFM_TOKEN_TRACKKERN:
    622         n++;
    623 
    624         if ( n >= (int)fi->NumTrackKern )
    625           goto Fail;
    626 
    627         tk = fi->TrackKerns + n;
    628 
    629         shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
    630         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
    631         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
    632         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
    633         shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
    634         if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
    635           goto Fail;
    636 
    637         tk->degree     = shared_vals[0].u.i;
    638         tk->min_ptsize = shared_vals[1].u.f;
    639         tk->min_kern   = shared_vals[2].u.f;
    640         tk->max_ptsize = shared_vals[3].u.f;
    641         tk->max_kern   = shared_vals[4].u.f;
    642 
    643         break;
    644 
    645       case AFM_TOKEN_ENDTRACKKERN:
    646       case AFM_TOKEN_ENDKERNDATA:
    647       case AFM_TOKEN_ENDFONTMETRICS:
    648         fi->NumTrackKern = (FT_UInt)( n + 1 );
    649         return FT_Err_Ok;
    650 
    651       case AFM_TOKEN_UNKNOWN:
    652         break;
    653 
    654       default:
    655         goto Fail;
    656       }
    657     }
    658 
    659   Fail:
    660     return FT_THROW( Syntax_Error );
    661   }
    662 
    663 
    664 #undef  KERN_INDEX
    665 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
    666 
    667 
    668   /* compare two kerning pairs */
    669   FT_CALLBACK_DEF( int )
    670   afm_compare_kern_pairs( const void*  a,
    671                           const void*  b )
    672   {
    673     AFM_KernPair  kp1 = (AFM_KernPair)a;
    674     AFM_KernPair  kp2 = (AFM_KernPair)b;
    675 
    676     FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
    677     FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
    678 
    679 
    680     if ( index1 > index2 )
    681       return 1;
    682     else if ( index1 < index2 )
    683       return -1;
    684     else
    685       return 0;
    686   }
    687 
    688 
    689   static FT_Error
    690   afm_parse_kern_pairs( AFM_Parser  parser )
    691   {
    692     AFM_FontInfo  fi = parser->FontInfo;
    693     AFM_KernPair  kp;
    694     char*         key;
    695     FT_Offset     len;
    696     int           n = -1;
    697     FT_Int        tmp;
    698 
    699 
    700     if ( afm_parser_read_int( parser, &tmp ) )
    701       goto Fail;
    702 
    703     if ( tmp < 0 )
    704       goto Fail;
    705 
    706     fi->NumKernPair = (FT_UInt)tmp;
    707 
    708     if ( fi->NumKernPair )
    709     {
    710       FT_Memory  memory = parser->memory;
    711       FT_Error   error;
    712 
    713 
    714       if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
    715         return error;
    716     }
    717 
    718     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    719     {
    720       AFM_Token  token = afm_tokenize( key, len );
    721 
    722 
    723       switch ( token )
    724       {
    725       case AFM_TOKEN_KP:
    726       case AFM_TOKEN_KPX:
    727       case AFM_TOKEN_KPY:
    728         {
    729           FT_Int        r;
    730           AFM_ValueRec  shared_vals[4];
    731 
    732 
    733           n++;
    734 
    735           if ( n >= (int)fi->NumKernPair )
    736             goto Fail;
    737 
    738           kp = fi->KernPairs + n;
    739 
    740           shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
    741           shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
    742           shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
    743           shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
    744           r = afm_parser_read_vals( parser, shared_vals, 4 );
    745           if ( r < 3 )
    746             goto Fail;
    747 
    748           /* index values can't be negative */
    749           kp->index1 = shared_vals[0].u.u;
    750           kp->index2 = shared_vals[1].u.u;
    751           if ( token == AFM_TOKEN_KPY )
    752           {
    753             kp->x = 0;
    754             kp->y = shared_vals[2].u.i;
    755           }
    756           else
    757           {
    758             kp->x = shared_vals[2].u.i;
    759             kp->y = ( token == AFM_TOKEN_KP && r == 4 )
    760                       ? shared_vals[3].u.i : 0;
    761           }
    762         }
    763         break;
    764 
    765       case AFM_TOKEN_ENDKERNPAIRS:
    766       case AFM_TOKEN_ENDKERNDATA:
    767       case AFM_TOKEN_ENDFONTMETRICS:
    768         fi->NumKernPair = (FT_UInt)( n + 1 );
    769         ft_qsort( fi->KernPairs, fi->NumKernPair,
    770                   sizeof ( AFM_KernPairRec ),
    771                   afm_compare_kern_pairs );
    772         return FT_Err_Ok;
    773 
    774       case AFM_TOKEN_UNKNOWN:
    775         break;
    776 
    777       default:
    778         goto Fail;
    779       }
    780     }
    781 
    782   Fail:
    783     return FT_THROW( Syntax_Error );
    784   }
    785 
    786 
    787   static FT_Error
    788   afm_parse_kern_data( AFM_Parser  parser )
    789   {
    790     FT_Error   error;
    791     char*      key;
    792     FT_Offset  len;
    793 
    794 
    795     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    796     {
    797       switch ( afm_tokenize( key, len ) )
    798       {
    799       case AFM_TOKEN_STARTTRACKKERN:
    800         error = afm_parse_track_kern( parser );
    801         if ( error )
    802           return error;
    803         break;
    804 
    805       case AFM_TOKEN_STARTKERNPAIRS:
    806       case AFM_TOKEN_STARTKERNPAIRS0:
    807         error = afm_parse_kern_pairs( parser );
    808         if ( error )
    809           return error;
    810         break;
    811 
    812       case AFM_TOKEN_ENDKERNDATA:
    813       case AFM_TOKEN_ENDFONTMETRICS:
    814         return FT_Err_Ok;
    815 
    816       case AFM_TOKEN_UNKNOWN:
    817         break;
    818 
    819       default:
    820         goto Fail;
    821       }
    822     }
    823 
    824   Fail:
    825     return FT_THROW( Syntax_Error );
    826   }
    827 
    828 
    829   static FT_Error
    830   afm_parser_skip_section( AFM_Parser  parser,
    831                            FT_Int      n,
    832                            AFM_Token   end_section )
    833   {
    834     char*      key;
    835     FT_Offset  len;
    836 
    837 
    838     while ( n-- > 0 )
    839     {
    840       key = afm_parser_next_key( parser, 1, NULL );
    841       if ( !key )
    842         goto Fail;
    843     }
    844 
    845     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    846     {
    847       AFM_Token  token = afm_tokenize( key, len );
    848 
    849 
    850       if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
    851         return FT_Err_Ok;
    852     }
    853 
    854   Fail:
    855     return FT_THROW( Syntax_Error );
    856   }
    857 
    858 
    859   FT_LOCAL_DEF( FT_Error )
    860   afm_parser_parse( AFM_Parser  parser )
    861   {
    862     FT_Memory     memory = parser->memory;
    863     AFM_FontInfo  fi     = parser->FontInfo;
    864     FT_Error      error  = FT_ERR( Syntax_Error );
    865     char*         key;
    866     FT_Offset     len;
    867     FT_Int        metrics_sets = 0;
    868 
    869 
    870     if ( !fi )
    871       return FT_THROW( Invalid_Argument );
    872 
    873     key = afm_parser_next_key( parser, 1, &len );
    874     if ( !key || len != 16                              ||
    875          ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
    876       return FT_THROW( Unknown_File_Format );
    877 
    878     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    879     {
    880       AFM_ValueRec  shared_vals[4];
    881 
    882 
    883       switch ( afm_tokenize( key, len ) )
    884       {
    885       case AFM_TOKEN_METRICSSETS:
    886         if ( afm_parser_read_int( parser, &metrics_sets ) )
    887           goto Fail;
    888 
    889         if ( metrics_sets != 0 && metrics_sets != 2 )
    890         {
    891           error = FT_THROW( Unimplemented_Feature );
    892 
    893           goto Fail;
    894         }
    895         break;
    896 
    897       case AFM_TOKEN_ISCIDFONT:
    898         shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
    899         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    900           goto Fail;
    901 
    902         fi->IsCIDFont = shared_vals[0].u.b;
    903         break;
    904 
    905       case AFM_TOKEN_FONTBBOX:
    906         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    907         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
    908         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
    909         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
    910         if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
    911           goto Fail;
    912 
    913         fi->FontBBox.xMin = shared_vals[0].u.f;
    914         fi->FontBBox.yMin = shared_vals[1].u.f;
    915         fi->FontBBox.xMax = shared_vals[2].u.f;
    916         fi->FontBBox.yMax = shared_vals[3].u.f;
    917         break;
    918 
    919       case AFM_TOKEN_ASCENDER:
    920         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    921         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    922           goto Fail;
    923 
    924         fi->Ascender = shared_vals[0].u.f;
    925         break;
    926 
    927       case AFM_TOKEN_DESCENDER:
    928         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    929         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    930           goto Fail;
    931 
    932         fi->Descender = shared_vals[0].u.f;
    933         break;
    934 
    935       case AFM_TOKEN_STARTCHARMETRICS:
    936         {
    937           FT_Int  n = 0;
    938 
    939 
    940           if ( afm_parser_read_int( parser, &n ) )
    941             goto Fail;
    942 
    943           error = afm_parser_skip_section( parser, n,
    944                                            AFM_TOKEN_ENDCHARMETRICS );
    945           if ( error )
    946             return error;
    947         }
    948         break;
    949 
    950       case AFM_TOKEN_STARTKERNDATA:
    951         error = afm_parse_kern_data( parser );
    952         if ( error )
    953           goto Fail;
    954         /* fall through since we only support kern data */
    955 
    956       case AFM_TOKEN_ENDFONTMETRICS:
    957         return FT_Err_Ok;
    958 
    959       default:
    960         break;
    961       }
    962     }
    963 
    964   Fail:
    965     FT_FREE( fi->TrackKerns );
    966     fi->NumTrackKern = 0;
    967 
    968     FT_FREE( fi->KernPairs );
    969     fi->NumKernPair = 0;
    970 
    971     fi->IsCIDFont = 0;
    972 
    973     return error;
    974   }
    975 
    976 
    977 /* END */
    978