Home | History | Annotate | Download | only in psaux
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  afmparse.c                                                             */
      4 /*                                                                         */
      5 /*    AFM parser (body).                                                   */
      6 /*                                                                         */
      7 /*  Copyright 2006-2018 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 #ifndef T1_CONFIG_OPTION_NO_AFM
     24 
     25 #include "afmparse.h"
     26 #include "psconv.h"
     27 
     28 #include "psauxerr.h"
     29 
     30 
     31 /***************************************************************************/
     32 /*                                                                         */
     33 /*    AFM_Stream                                                           */
     34 /*                                                                         */
     35 /* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.  */
     36 /*                                                                         */
     37 /*                                                                         */
     38 
     39   enum
     40   {
     41     AFM_STREAM_STATUS_NORMAL,
     42     AFM_STREAM_STATUS_EOC,
     43     AFM_STREAM_STATUS_EOL,
     44     AFM_STREAM_STATUS_EOF
     45   };
     46 
     47 
     48   typedef struct  AFM_StreamRec_
     49   {
     50     FT_Byte*  cursor;
     51     FT_Byte*  base;
     52     FT_Byte*  limit;
     53 
     54     FT_Int    status;
     55 
     56   } AFM_StreamRec;
     57 
     58 
     59 #ifndef EOF
     60 #define EOF -1
     61 #endif
     62 
     63 
     64   /* this works because empty lines are ignored */
     65 #define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )
     66 
     67 #define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
     68 #define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )
     69 
     70   /* column separator; there is no `column' in the spec actually */
     71 #define AFM_IS_SEP( ch )      ( (ch) == ';' )
     72 
     73 #define AFM_GETC()                                                       \
     74           ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
     75                                                    : EOF )
     76 
     77 #define AFM_STREAM_KEY_BEGIN( stream )    \
     78           (char*)( (stream)->cursor - 1 )
     79 
     80 #define AFM_STREAM_KEY_LEN( stream, key )           \
     81           (FT_Offset)( (char*)(stream)->cursor - key - 1 )
     82 
     83 #define AFM_STATUS_EOC( stream ) \
     84           ( (stream)->status >= AFM_STREAM_STATUS_EOC )
     85 
     86 #define AFM_STATUS_EOL( stream ) \
     87           ( (stream)->status >= AFM_STREAM_STATUS_EOL )
     88 
     89 #define AFM_STATUS_EOF( stream ) \
     90           ( (stream)->status >= AFM_STREAM_STATUS_EOF )
     91 
     92 
     93   static int
     94   afm_stream_skip_spaces( AFM_Stream  stream )
     95   {
     96     int  ch = 0;  /* make stupid compiler happy */
     97 
     98 
     99     if ( AFM_STATUS_EOC( stream ) )
    100       return ';';
    101 
    102     while ( 1 )
    103     {
    104       ch = AFM_GETC();
    105       if ( !AFM_IS_SPACE( ch ) )
    106         break;
    107     }
    108 
    109     if ( AFM_IS_NEWLINE( ch ) )
    110       stream->status = AFM_STREAM_STATUS_EOL;
    111     else if ( AFM_IS_SEP( ch ) )
    112       stream->status = AFM_STREAM_STATUS_EOC;
    113     else if ( AFM_IS_EOF( ch ) )
    114       stream->status = AFM_STREAM_STATUS_EOF;
    115 
    116     return ch;
    117   }
    118 
    119 
    120   /* read a key or value in current column */
    121   static char*
    122   afm_stream_read_one( AFM_Stream  stream )
    123   {
    124     char*  str;
    125 
    126 
    127     afm_stream_skip_spaces( stream );
    128     if ( AFM_STATUS_EOC( stream ) )
    129       return NULL;
    130 
    131     str = AFM_STREAM_KEY_BEGIN( stream );
    132 
    133     while ( 1 )
    134     {
    135       int  ch = AFM_GETC();
    136 
    137 
    138       if ( AFM_IS_SPACE( ch ) )
    139         break;
    140       else if ( AFM_IS_NEWLINE( ch ) )
    141       {
    142         stream->status = AFM_STREAM_STATUS_EOL;
    143         break;
    144       }
    145       else if ( AFM_IS_SEP( ch ) )
    146       {
    147         stream->status = AFM_STREAM_STATUS_EOC;
    148         break;
    149       }
    150       else if ( AFM_IS_EOF( ch ) )
    151       {
    152         stream->status = AFM_STREAM_STATUS_EOF;
    153         break;
    154       }
    155     }
    156 
    157     return str;
    158   }
    159 
    160 
    161   /* read a string (i.e., read to EOL) */
    162   static char*
    163   afm_stream_read_string( AFM_Stream  stream )
    164   {
    165     char*  str;
    166 
    167 
    168     afm_stream_skip_spaces( stream );
    169     if ( AFM_STATUS_EOL( stream ) )
    170       return NULL;
    171 
    172     str = AFM_STREAM_KEY_BEGIN( stream );
    173 
    174     /* scan to eol */
    175     while ( 1 )
    176     {
    177       int  ch = AFM_GETC();
    178 
    179 
    180       if ( AFM_IS_NEWLINE( ch ) )
    181       {
    182         stream->status = AFM_STREAM_STATUS_EOL;
    183         break;
    184       }
    185       else if ( AFM_IS_EOF( ch ) )
    186       {
    187         stream->status = AFM_STREAM_STATUS_EOF;
    188         break;
    189       }
    190     }
    191 
    192     return str;
    193   }
    194 
    195 
    196   /*************************************************************************/
    197   /*                                                                       */
    198   /*    AFM_Parser                                                         */
    199   /*                                                                       */
    200   /*                                                                       */
    201 
    202   /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
    203   typedef enum  AFM_Token_
    204   {
    205     AFM_TOKEN_ASCENDER,
    206     AFM_TOKEN_AXISLABEL,
    207     AFM_TOKEN_AXISTYPE,
    208     AFM_TOKEN_B,
    209     AFM_TOKEN_BLENDAXISTYPES,
    210     AFM_TOKEN_BLENDDESIGNMAP,
    211     AFM_TOKEN_BLENDDESIGNPOSITIONS,
    212     AFM_TOKEN_C,
    213     AFM_TOKEN_CC,
    214     AFM_TOKEN_CH,
    215     AFM_TOKEN_CAPHEIGHT,
    216     AFM_TOKEN_CHARWIDTH,
    217     AFM_TOKEN_CHARACTERSET,
    218     AFM_TOKEN_CHARACTERS,
    219     AFM_TOKEN_DESCENDER,
    220     AFM_TOKEN_ENCODINGSCHEME,
    221     AFM_TOKEN_ENDAXIS,
    222     AFM_TOKEN_ENDCHARMETRICS,
    223     AFM_TOKEN_ENDCOMPOSITES,
    224     AFM_TOKEN_ENDDIRECTION,
    225     AFM_TOKEN_ENDFONTMETRICS,
    226     AFM_TOKEN_ENDKERNDATA,
    227     AFM_TOKEN_ENDKERNPAIRS,
    228     AFM_TOKEN_ENDTRACKKERN,
    229     AFM_TOKEN_ESCCHAR,
    230     AFM_TOKEN_FAMILYNAME,
    231     AFM_TOKEN_FONTBBOX,
    232     AFM_TOKEN_FONTNAME,
    233     AFM_TOKEN_FULLNAME,
    234     AFM_TOKEN_ISBASEFONT,
    235     AFM_TOKEN_ISCIDFONT,
    236     AFM_TOKEN_ISFIXEDPITCH,
    237     AFM_TOKEN_ISFIXEDV,
    238     AFM_TOKEN_ITALICANGLE,
    239     AFM_TOKEN_KP,
    240     AFM_TOKEN_KPH,
    241     AFM_TOKEN_KPX,
    242     AFM_TOKEN_KPY,
    243     AFM_TOKEN_L,
    244     AFM_TOKEN_MAPPINGSCHEME,
    245     AFM_TOKEN_METRICSSETS,
    246     AFM_TOKEN_N,
    247     AFM_TOKEN_NOTICE,
    248     AFM_TOKEN_PCC,
    249     AFM_TOKEN_STARTAXIS,
    250     AFM_TOKEN_STARTCHARMETRICS,
    251     AFM_TOKEN_STARTCOMPOSITES,
    252     AFM_TOKEN_STARTDIRECTION,
    253     AFM_TOKEN_STARTFONTMETRICS,
    254     AFM_TOKEN_STARTKERNDATA,
    255     AFM_TOKEN_STARTKERNPAIRS,
    256     AFM_TOKEN_STARTKERNPAIRS0,
    257     AFM_TOKEN_STARTKERNPAIRS1,
    258     AFM_TOKEN_STARTTRACKKERN,
    259     AFM_TOKEN_STDHW,
    260     AFM_TOKEN_STDVW,
    261     AFM_TOKEN_TRACKKERN,
    262     AFM_TOKEN_UNDERLINEPOSITION,
    263     AFM_TOKEN_UNDERLINETHICKNESS,
    264     AFM_TOKEN_VV,
    265     AFM_TOKEN_VVECTOR,
    266     AFM_TOKEN_VERSION,
    267     AFM_TOKEN_W,
    268     AFM_TOKEN_W0,
    269     AFM_TOKEN_W0X,
    270     AFM_TOKEN_W0Y,
    271     AFM_TOKEN_W1,
    272     AFM_TOKEN_W1X,
    273     AFM_TOKEN_W1Y,
    274     AFM_TOKEN_WX,
    275     AFM_TOKEN_WY,
    276     AFM_TOKEN_WEIGHT,
    277     AFM_TOKEN_WEIGHTVECTOR,
    278     AFM_TOKEN_XHEIGHT,
    279     N_AFM_TOKENS,
    280     AFM_TOKEN_UNKNOWN
    281 
    282   } AFM_Token;
    283 
    284 
    285   static const char*  const afm_key_table[N_AFM_TOKENS] =
    286   {
    287     "Ascender",
    288     "AxisLabel",
    289     "AxisType",
    290     "B",
    291     "BlendAxisTypes",
    292     "BlendDesignMap",
    293     "BlendDesignPositions",
    294     "C",
    295     "CC",
    296     "CH",
    297     "CapHeight",
    298     "CharWidth",
    299     "CharacterSet",
    300     "Characters",
    301     "Descender",
    302     "EncodingScheme",
    303     "EndAxis",
    304     "EndCharMetrics",
    305     "EndComposites",
    306     "EndDirection",
    307     "EndFontMetrics",
    308     "EndKernData",
    309     "EndKernPairs",
    310     "EndTrackKern",
    311     "EscChar",
    312     "FamilyName",
    313     "FontBBox",
    314     "FontName",
    315     "FullName",
    316     "IsBaseFont",
    317     "IsCIDFont",
    318     "IsFixedPitch",
    319     "IsFixedV",
    320     "ItalicAngle",
    321     "KP",
    322     "KPH",
    323     "KPX",
    324     "KPY",
    325     "L",
    326     "MappingScheme",
    327     "MetricsSets",
    328     "N",
    329     "Notice",
    330     "PCC",
    331     "StartAxis",
    332     "StartCharMetrics",
    333     "StartComposites",
    334     "StartDirection",
    335     "StartFontMetrics",
    336     "StartKernData",
    337     "StartKernPairs",
    338     "StartKernPairs0",
    339     "StartKernPairs1",
    340     "StartTrackKern",
    341     "StdHW",
    342     "StdVW",
    343     "TrackKern",
    344     "UnderlinePosition",
    345     "UnderlineThickness",
    346     "VV",
    347     "VVector",
    348     "Version",
    349     "W",
    350     "W0",
    351     "W0X",
    352     "W0Y",
    353     "W1",
    354     "W1X",
    355     "W1Y",
    356     "WX",
    357     "WY",
    358     "Weight",
    359     "WeightVector",
    360     "XHeight"
    361   };
    362 
    363 
    364   /*
    365    * `afm_parser_read_vals' and `afm_parser_next_key' provide
    366    * high-level operations to an AFM_Stream.  The rest of the
    367    * parser functions should use them without accessing the
    368    * AFM_Stream directly.
    369    */
    370 
    371   FT_LOCAL_DEF( FT_Int )
    372   afm_parser_read_vals( AFM_Parser  parser,
    373                         AFM_Value   vals,
    374                         FT_Int      n )
    375   {
    376     AFM_Stream  stream = parser->stream;
    377     char*       str;
    378     FT_Int      i;
    379 
    380 
    381     if ( n > AFM_MAX_ARGUMENTS )
    382       return 0;
    383 
    384     for ( i = 0; i < n; i++ )
    385     {
    386       FT_Offset  len;
    387       AFM_Value  val = vals + i;
    388 
    389 
    390       if ( val->type == AFM_VALUE_TYPE_STRING )
    391         str = afm_stream_read_string( stream );
    392       else
    393         str = afm_stream_read_one( stream );
    394 
    395       if ( !str )
    396         break;
    397 
    398       len = AFM_STREAM_KEY_LEN( stream, str );
    399 
    400       switch ( val->type )
    401       {
    402       case AFM_VALUE_TYPE_STRING:
    403       case AFM_VALUE_TYPE_NAME:
    404         {
    405           FT_Memory  memory = parser->memory;
    406           FT_Error   error;
    407 
    408 
    409           if ( !FT_QALLOC( val->u.s, len + 1 ) )
    410           {
    411             ft_memcpy( val->u.s, str, len );
    412             val->u.s[len] = '\0';
    413           }
    414         }
    415         break;
    416 
    417       case AFM_VALUE_TYPE_FIXED:
    418         val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
    419                                     (FT_Byte*)str + len, 0 );
    420         break;
    421 
    422       case AFM_VALUE_TYPE_INTEGER:
    423         val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
    424                                   (FT_Byte*)str + len );
    425         break;
    426 
    427       case AFM_VALUE_TYPE_BOOL:
    428         val->u.b = FT_BOOL( len == 4                      &&
    429                             !ft_strncmp( str, "true", 4 ) );
    430         break;
    431 
    432       case AFM_VALUE_TYPE_INDEX:
    433         if ( parser->get_index )
    434           val->u.i = parser->get_index( str, len, parser->user_data );
    435         else
    436           val->u.i = 0;
    437         break;
    438       }
    439     }
    440 
    441     return i;
    442   }
    443 
    444 
    445   FT_LOCAL_DEF( char* )
    446   afm_parser_next_key( AFM_Parser  parser,
    447                        FT_Bool     line,
    448                        FT_Offset*  len )
    449   {
    450     AFM_Stream  stream = parser->stream;
    451     char*       key    = NULL;  /* make stupid compiler happy */
    452 
    453 
    454     if ( line )
    455     {
    456       while ( 1 )
    457       {
    458         /* skip current line */
    459         if ( !AFM_STATUS_EOL( stream ) )
    460           afm_stream_read_string( stream );
    461 
    462         stream->status = AFM_STREAM_STATUS_NORMAL;
    463         key = afm_stream_read_one( stream );
    464 
    465         /* skip empty line */
    466         if ( !key                      &&
    467              !AFM_STATUS_EOF( stream ) &&
    468              AFM_STATUS_EOL( stream )  )
    469           continue;
    470 
    471         break;
    472       }
    473     }
    474     else
    475     {
    476       while ( 1 )
    477       {
    478         /* skip current column */
    479         while ( !AFM_STATUS_EOC( stream ) )
    480           afm_stream_read_one( stream );
    481 
    482         stream->status = AFM_STREAM_STATUS_NORMAL;
    483         key = afm_stream_read_one( stream );
    484 
    485         /* skip empty column */
    486         if ( !key                      &&
    487              !AFM_STATUS_EOF( stream ) &&
    488              AFM_STATUS_EOC( stream )  )
    489           continue;
    490 
    491         break;
    492       }
    493     }
    494 
    495     if ( len )
    496       *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key )
    497                      : 0;
    498 
    499     return key;
    500   }
    501 
    502 
    503   static AFM_Token
    504   afm_tokenize( const char*  key,
    505                 FT_Offset    len )
    506   {
    507     int  n;
    508 
    509 
    510     for ( n = 0; n < N_AFM_TOKENS; n++ )
    511     {
    512       if ( *( afm_key_table[n] ) == *key )
    513       {
    514         for ( ; n < N_AFM_TOKENS; n++ )
    515         {
    516           if ( *( afm_key_table[n] ) != *key )
    517             return AFM_TOKEN_UNKNOWN;
    518 
    519           if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
    520             return (AFM_Token) n;
    521         }
    522       }
    523     }
    524 
    525     return AFM_TOKEN_UNKNOWN;
    526   }
    527 
    528 
    529   FT_LOCAL_DEF( FT_Error )
    530   afm_parser_init( AFM_Parser  parser,
    531                    FT_Memory   memory,
    532                    FT_Byte*    base,
    533                    FT_Byte*    limit )
    534   {
    535     AFM_Stream  stream = NULL;
    536     FT_Error    error;
    537 
    538 
    539     if ( FT_NEW( stream ) )
    540       return error;
    541 
    542     stream->cursor = stream->base = base;
    543     stream->limit  = limit;
    544 
    545     /* don't skip the first line during the first call */
    546     stream->status = AFM_STREAM_STATUS_EOL;
    547 
    548     parser->memory    = memory;
    549     parser->stream    = stream;
    550     parser->FontInfo  = NULL;
    551     parser->get_index = NULL;
    552 
    553     return FT_Err_Ok;
    554   }
    555 
    556 
    557   FT_LOCAL( void )
    558   afm_parser_done( AFM_Parser  parser )
    559   {
    560     FT_Memory  memory = parser->memory;
    561 
    562 
    563     FT_FREE( parser->stream );
    564   }
    565 
    566 
    567   static FT_Error
    568   afm_parser_read_int( AFM_Parser  parser,
    569                        FT_Int*     aint )
    570   {
    571     AFM_ValueRec  val;
    572 
    573 
    574     val.type = AFM_VALUE_TYPE_INTEGER;
    575 
    576     if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
    577     {
    578       *aint = val.u.i;
    579 
    580       return FT_Err_Ok;
    581     }
    582     else
    583       return FT_THROW( Syntax_Error );
    584   }
    585 
    586 
    587   static FT_Error
    588   afm_parse_track_kern( AFM_Parser  parser )
    589   {
    590     AFM_FontInfo   fi = parser->FontInfo;
    591     AFM_TrackKern  tk;
    592     char*          key;
    593     FT_Offset      len;
    594     int            n = -1;
    595     FT_Int         tmp;
    596 
    597 
    598     if ( afm_parser_read_int( parser, &tmp ) )
    599         goto Fail;
    600 
    601     if ( tmp < 0 )
    602       goto Fail;
    603 
    604     fi->NumTrackKern = (FT_UInt)tmp;
    605 
    606     if ( fi->NumTrackKern )
    607     {
    608       FT_Memory  memory = parser->memory;
    609       FT_Error   error;
    610 
    611 
    612       if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
    613         return error;
    614     }
    615 
    616     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    617     {
    618       AFM_ValueRec  shared_vals[5];
    619 
    620 
    621       switch ( afm_tokenize( key, len ) )
    622       {
    623       case AFM_TOKEN_TRACKKERN:
    624         n++;
    625 
    626         if ( n >= (int)fi->NumTrackKern )
    627           goto Fail;
    628 
    629         tk = fi->TrackKerns + n;
    630 
    631         shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
    632         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
    633         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
    634         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
    635         shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
    636         if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
    637           goto Fail;
    638 
    639         tk->degree     = shared_vals[0].u.i;
    640         tk->min_ptsize = shared_vals[1].u.f;
    641         tk->min_kern   = shared_vals[2].u.f;
    642         tk->max_ptsize = shared_vals[3].u.f;
    643         tk->max_kern   = shared_vals[4].u.f;
    644 
    645         break;
    646 
    647       case AFM_TOKEN_ENDTRACKKERN:
    648       case AFM_TOKEN_ENDKERNDATA:
    649       case AFM_TOKEN_ENDFONTMETRICS:
    650         fi->NumTrackKern = (FT_UInt)( n + 1 );
    651         return FT_Err_Ok;
    652 
    653       case AFM_TOKEN_UNKNOWN:
    654         break;
    655 
    656       default:
    657         goto Fail;
    658       }
    659     }
    660 
    661   Fail:
    662     return FT_THROW( Syntax_Error );
    663   }
    664 
    665 
    666 #undef  KERN_INDEX
    667 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
    668 
    669 
    670   /* compare two kerning pairs */
    671   FT_CALLBACK_DEF( int )
    672   afm_compare_kern_pairs( const void*  a,
    673                           const void*  b )
    674   {
    675     AFM_KernPair  kp1 = (AFM_KernPair)a;
    676     AFM_KernPair  kp2 = (AFM_KernPair)b;
    677 
    678     FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
    679     FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
    680 
    681 
    682     if ( index1 > index2 )
    683       return 1;
    684     else if ( index1 < index2 )
    685       return -1;
    686     else
    687       return 0;
    688   }
    689 
    690 
    691   static FT_Error
    692   afm_parse_kern_pairs( AFM_Parser  parser )
    693   {
    694     AFM_FontInfo  fi = parser->FontInfo;
    695     AFM_KernPair  kp;
    696     char*         key;
    697     FT_Offset     len;
    698     int           n = -1;
    699     FT_Int        tmp;
    700 
    701 
    702     if ( afm_parser_read_int( parser, &tmp ) )
    703       goto Fail;
    704 
    705     if ( tmp < 0 )
    706       goto Fail;
    707 
    708     fi->NumKernPair = (FT_UInt)tmp;
    709 
    710     if ( fi->NumKernPair )
    711     {
    712       FT_Memory  memory = parser->memory;
    713       FT_Error   error;
    714 
    715 
    716       if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
    717         return error;
    718     }
    719 
    720     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    721     {
    722       AFM_Token  token = afm_tokenize( key, len );
    723 
    724 
    725       switch ( token )
    726       {
    727       case AFM_TOKEN_KP:
    728       case AFM_TOKEN_KPX:
    729       case AFM_TOKEN_KPY:
    730         {
    731           FT_Int        r;
    732           AFM_ValueRec  shared_vals[4];
    733 
    734 
    735           n++;
    736 
    737           if ( n >= (int)fi->NumKernPair )
    738             goto Fail;
    739 
    740           kp = fi->KernPairs + n;
    741 
    742           shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
    743           shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
    744           shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
    745           shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
    746           r = afm_parser_read_vals( parser, shared_vals, 4 );
    747           if ( r < 3 )
    748             goto Fail;
    749 
    750           /* index values can't be negative */
    751           kp->index1 = shared_vals[0].u.u;
    752           kp->index2 = shared_vals[1].u.u;
    753           if ( token == AFM_TOKEN_KPY )
    754           {
    755             kp->x = 0;
    756             kp->y = shared_vals[2].u.i;
    757           }
    758           else
    759           {
    760             kp->x = shared_vals[2].u.i;
    761             kp->y = ( token == AFM_TOKEN_KP && r == 4 )
    762                       ? shared_vals[3].u.i : 0;
    763           }
    764         }
    765         break;
    766 
    767       case AFM_TOKEN_ENDKERNPAIRS:
    768       case AFM_TOKEN_ENDKERNDATA:
    769       case AFM_TOKEN_ENDFONTMETRICS:
    770         fi->NumKernPair = (FT_UInt)( n + 1 );
    771         ft_qsort( fi->KernPairs, fi->NumKernPair,
    772                   sizeof ( AFM_KernPairRec ),
    773                   afm_compare_kern_pairs );
    774         return FT_Err_Ok;
    775 
    776       case AFM_TOKEN_UNKNOWN:
    777         break;
    778 
    779       default:
    780         goto Fail;
    781       }
    782     }
    783 
    784   Fail:
    785     return FT_THROW( Syntax_Error );
    786   }
    787 
    788 
    789   static FT_Error
    790   afm_parse_kern_data( AFM_Parser  parser )
    791   {
    792     FT_Error   error;
    793     char*      key;
    794     FT_Offset  len;
    795 
    796 
    797     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    798     {
    799       switch ( afm_tokenize( key, len ) )
    800       {
    801       case AFM_TOKEN_STARTTRACKKERN:
    802         error = afm_parse_track_kern( parser );
    803         if ( error )
    804           return error;
    805         break;
    806 
    807       case AFM_TOKEN_STARTKERNPAIRS:
    808       case AFM_TOKEN_STARTKERNPAIRS0:
    809         error = afm_parse_kern_pairs( parser );
    810         if ( error )
    811           return error;
    812         break;
    813 
    814       case AFM_TOKEN_ENDKERNDATA:
    815       case AFM_TOKEN_ENDFONTMETRICS:
    816         return FT_Err_Ok;
    817 
    818       case AFM_TOKEN_UNKNOWN:
    819         break;
    820 
    821       default:
    822         goto Fail;
    823       }
    824     }
    825 
    826   Fail:
    827     return FT_THROW( Syntax_Error );
    828   }
    829 
    830 
    831   static FT_Error
    832   afm_parser_skip_section( AFM_Parser  parser,
    833                            FT_Int      n,
    834                            AFM_Token   end_section )
    835   {
    836     char*      key;
    837     FT_Offset  len;
    838 
    839 
    840     while ( n-- > 0 )
    841     {
    842       key = afm_parser_next_key( parser, 1, NULL );
    843       if ( !key )
    844         goto Fail;
    845     }
    846 
    847     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    848     {
    849       AFM_Token  token = afm_tokenize( key, len );
    850 
    851 
    852       if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
    853         return FT_Err_Ok;
    854     }
    855 
    856   Fail:
    857     return FT_THROW( Syntax_Error );
    858   }
    859 
    860 
    861   FT_LOCAL_DEF( FT_Error )
    862   afm_parser_parse( AFM_Parser  parser )
    863   {
    864     FT_Memory     memory = parser->memory;
    865     AFM_FontInfo  fi     = parser->FontInfo;
    866     FT_Error      error  = FT_ERR( Syntax_Error );
    867     char*         key;
    868     FT_Offset     len;
    869     FT_Int        metrics_sets = 0;
    870 
    871 
    872     if ( !fi )
    873       return FT_THROW( Invalid_Argument );
    874 
    875     key = afm_parser_next_key( parser, 1, &len );
    876     if ( !key || len != 16                              ||
    877          ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
    878       return FT_THROW( Unknown_File_Format );
    879 
    880     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    881     {
    882       AFM_ValueRec  shared_vals[4];
    883 
    884 
    885       switch ( afm_tokenize( key, len ) )
    886       {
    887       case AFM_TOKEN_METRICSSETS:
    888         if ( afm_parser_read_int( parser, &metrics_sets ) )
    889           goto Fail;
    890 
    891         if ( metrics_sets != 0 && metrics_sets != 2 )
    892         {
    893           error = FT_THROW( Unimplemented_Feature );
    894 
    895           goto Fail;
    896         }
    897         break;
    898 
    899       case AFM_TOKEN_ISCIDFONT:
    900         shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
    901         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    902           goto Fail;
    903 
    904         fi->IsCIDFont = shared_vals[0].u.b;
    905         break;
    906 
    907       case AFM_TOKEN_FONTBBOX:
    908         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    909         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
    910         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
    911         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
    912         if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
    913           goto Fail;
    914 
    915         fi->FontBBox.xMin = shared_vals[0].u.f;
    916         fi->FontBBox.yMin = shared_vals[1].u.f;
    917         fi->FontBBox.xMax = shared_vals[2].u.f;
    918         fi->FontBBox.yMax = shared_vals[3].u.f;
    919         break;
    920 
    921       case AFM_TOKEN_ASCENDER:
    922         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    923         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    924           goto Fail;
    925 
    926         fi->Ascender = shared_vals[0].u.f;
    927         break;
    928 
    929       case AFM_TOKEN_DESCENDER:
    930         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
    931         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
    932           goto Fail;
    933 
    934         fi->Descender = shared_vals[0].u.f;
    935         break;
    936 
    937       case AFM_TOKEN_STARTCHARMETRICS:
    938         {
    939           FT_Int  n = 0;
    940 
    941 
    942           if ( afm_parser_read_int( parser, &n ) )
    943             goto Fail;
    944 
    945           error = afm_parser_skip_section( parser, n,
    946                                            AFM_TOKEN_ENDCHARMETRICS );
    947           if ( error )
    948             return error;
    949         }
    950         break;
    951 
    952       case AFM_TOKEN_STARTKERNDATA:
    953         error = afm_parse_kern_data( parser );
    954         if ( error )
    955           goto Fail;
    956         /* fall through since we only support kern data */
    957 
    958       case AFM_TOKEN_ENDFONTMETRICS:
    959         return FT_Err_Ok;
    960 
    961       default:
    962         break;
    963       }
    964     }
    965 
    966   Fail:
    967     FT_FREE( fi->TrackKerns );
    968     fi->NumTrackKern = 0;
    969 
    970     FT_FREE( fi->KernPairs );
    971     fi->NumKernPair = 0;
    972 
    973     fi->IsCIDFont = 0;
    974 
    975     return error;
    976   }
    977 
    978 #else /* T1_CONFIG_OPTION_NO_AFM */
    979 
    980   /* ANSI C doesn't like empty source files */
    981   typedef int  _afm_parse_dummy;
    982 
    983 #endif /* T1_CONFIG_OPTION_NO_AFM */
    984 
    985 
    986 /* END */
    987