misc/libfreetype/src/psaux/afmparse.c
changeset 9431 0f5961910e27
parent 9357 a501f5ec7b34
parent 9429 7a97a554ac80
child 9433 f0a8ac191839
--- a/misc/libfreetype/src/psaux/afmparse.c	Tue Jul 16 11:14:27 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,964 +0,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  afmparse.c                                                             */
-/*                                                                         */
-/*    AFM parser (body).                                                   */
-/*                                                                         */
-/*  Copyright 2006, 2007, 2008, 2009, 2010 by                              */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/***************************************************************************/
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_INTERNAL_POSTSCRIPT_AUX_H
-
-#include "afmparse.h"
-#include "psconv.h"
-
-#include "psauxerr.h"
-
-
-/***************************************************************************/
-/*                                                                         */
-/*    AFM_Stream                                                           */
-/*                                                                         */
-/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.  */
-/*                                                                         */
-/*                                                                         */
-
-  enum
-  {
-    AFM_STREAM_STATUS_NORMAL,
-    AFM_STREAM_STATUS_EOC,
-    AFM_STREAM_STATUS_EOL,
-    AFM_STREAM_STATUS_EOF
-  };
-
-
-  typedef struct  AFM_StreamRec_
-  {
-    FT_Byte*  cursor;
-    FT_Byte*  base;
-    FT_Byte*  limit;
-
-    FT_Int    status;
-
-  } AFM_StreamRec;
-
-
-#ifndef EOF
-#define EOF -1
-#endif
-
-
-  /* this works because empty lines are ignored */
-#define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )
-
-#define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
-#define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )
-
-  /* column separator; there is no `column' in the spec actually */
-#define AFM_IS_SEP( ch )      ( (ch) == ';' )
-
-#define AFM_GETC()                                                       \
-          ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
-                                                   : EOF )
-
-#define AFM_STREAM_KEY_BEGIN( stream )    \
-          (char*)( (stream)->cursor - 1 )
-
-#define AFM_STREAM_KEY_LEN( stream, key )       \
-          ( (char*)(stream)->cursor - key - 1 )
-
-#define AFM_STATUS_EOC( stream ) \
-          ( (stream)->status >= AFM_STREAM_STATUS_EOC )
-
-#define AFM_STATUS_EOL( stream ) \
-          ( (stream)->status >= AFM_STREAM_STATUS_EOL )
-
-#define AFM_STATUS_EOF( stream ) \
-          ( (stream)->status >= AFM_STREAM_STATUS_EOF )
-
-
-  static int
-  afm_stream_skip_spaces( AFM_Stream  stream )
-  {
-    int  ch = 0;  /* make stupid compiler happy */
-
-
-    if ( AFM_STATUS_EOC( stream ) )
-      return ';';
-
-    while ( 1 )
-    {
-      ch = AFM_GETC();
-      if ( !AFM_IS_SPACE( ch ) )
-        break;
-    }
-
-    if ( AFM_IS_NEWLINE( ch ) )
-      stream->status = AFM_STREAM_STATUS_EOL;
-    else if ( AFM_IS_SEP( ch ) )
-      stream->status = AFM_STREAM_STATUS_EOC;
-    else if ( AFM_IS_EOF( ch ) )
-      stream->status = AFM_STREAM_STATUS_EOF;
-
-    return ch;
-  }
-
-
-  /* read a key or value in current column */
-  static char*
-  afm_stream_read_one( AFM_Stream  stream )
-  {
-    char*  str;
-    int    ch;
-
-
-    afm_stream_skip_spaces( stream );
-    if ( AFM_STATUS_EOC( stream ) )
-      return NULL;
-
-    str = AFM_STREAM_KEY_BEGIN( stream );
-
-    while ( 1 )
-    {
-      ch = AFM_GETC();
-      if ( AFM_IS_SPACE( ch ) )
-        break;
-      else if ( AFM_IS_NEWLINE( ch ) )
-      {
-        stream->status = AFM_STREAM_STATUS_EOL;
-        break;
-      }
-      else if ( AFM_IS_SEP( ch ) )
-      {
-        stream->status = AFM_STREAM_STATUS_EOC;
-        break;
-      }
-      else if ( AFM_IS_EOF( ch ) )
-      {
-        stream->status = AFM_STREAM_STATUS_EOF;
-        break;
-      }
-    }
-
-    return str;
-  }
-
-
-  /* read a string (i.e., read to EOL) */
-  static char*
-  afm_stream_read_string( AFM_Stream  stream )
-  {
-    char*  str;
-    int    ch;
-
-
-    afm_stream_skip_spaces( stream );
-    if ( AFM_STATUS_EOL( stream ) )
-      return NULL;
-
-    str = AFM_STREAM_KEY_BEGIN( stream );
-
-    /* scan to eol */
-    while ( 1 )
-    {
-      ch = AFM_GETC();
-      if ( AFM_IS_NEWLINE( ch ) )
-      {
-        stream->status = AFM_STREAM_STATUS_EOL;
-        break;
-      }
-      else if ( AFM_IS_EOF( ch ) )
-      {
-        stream->status = AFM_STREAM_STATUS_EOF;
-        break;
-      }
-    }
-
-    return str;
-  }
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /*    AFM_Parser                                                         */
-  /*                                                                       */
-  /*                                                                       */
-
-  /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
-  typedef enum  AFM_Token_
-  {
-    AFM_TOKEN_ASCENDER,
-    AFM_TOKEN_AXISLABEL,
-    AFM_TOKEN_AXISTYPE,
-    AFM_TOKEN_B,
-    AFM_TOKEN_BLENDAXISTYPES,
-    AFM_TOKEN_BLENDDESIGNMAP,
-    AFM_TOKEN_BLENDDESIGNPOSITIONS,
-    AFM_TOKEN_C,
-    AFM_TOKEN_CC,
-    AFM_TOKEN_CH,
-    AFM_TOKEN_CAPHEIGHT,
-    AFM_TOKEN_CHARWIDTH,
-    AFM_TOKEN_CHARACTERSET,
-    AFM_TOKEN_CHARACTERS,
-    AFM_TOKEN_DESCENDER,
-    AFM_TOKEN_ENCODINGSCHEME,
-    AFM_TOKEN_ENDAXIS,
-    AFM_TOKEN_ENDCHARMETRICS,
-    AFM_TOKEN_ENDCOMPOSITES,
-    AFM_TOKEN_ENDDIRECTION,
-    AFM_TOKEN_ENDFONTMETRICS,
-    AFM_TOKEN_ENDKERNDATA,
-    AFM_TOKEN_ENDKERNPAIRS,
-    AFM_TOKEN_ENDTRACKKERN,
-    AFM_TOKEN_ESCCHAR,
-    AFM_TOKEN_FAMILYNAME,
-    AFM_TOKEN_FONTBBOX,
-    AFM_TOKEN_FONTNAME,
-    AFM_TOKEN_FULLNAME,
-    AFM_TOKEN_ISBASEFONT,
-    AFM_TOKEN_ISCIDFONT,
-    AFM_TOKEN_ISFIXEDPITCH,
-    AFM_TOKEN_ISFIXEDV,
-    AFM_TOKEN_ITALICANGLE,
-    AFM_TOKEN_KP,
-    AFM_TOKEN_KPH,
-    AFM_TOKEN_KPX,
-    AFM_TOKEN_KPY,
-    AFM_TOKEN_L,
-    AFM_TOKEN_MAPPINGSCHEME,
-    AFM_TOKEN_METRICSSETS,
-    AFM_TOKEN_N,
-    AFM_TOKEN_NOTICE,
-    AFM_TOKEN_PCC,
-    AFM_TOKEN_STARTAXIS,
-    AFM_TOKEN_STARTCHARMETRICS,
-    AFM_TOKEN_STARTCOMPOSITES,
-    AFM_TOKEN_STARTDIRECTION,
-    AFM_TOKEN_STARTFONTMETRICS,
-    AFM_TOKEN_STARTKERNDATA,
-    AFM_TOKEN_STARTKERNPAIRS,
-    AFM_TOKEN_STARTKERNPAIRS0,
-    AFM_TOKEN_STARTKERNPAIRS1,
-    AFM_TOKEN_STARTTRACKKERN,
-    AFM_TOKEN_STDHW,
-    AFM_TOKEN_STDVW,
-    AFM_TOKEN_TRACKKERN,
-    AFM_TOKEN_UNDERLINEPOSITION,
-    AFM_TOKEN_UNDERLINETHICKNESS,
-    AFM_TOKEN_VV,
-    AFM_TOKEN_VVECTOR,
-    AFM_TOKEN_VERSION,
-    AFM_TOKEN_W,
-    AFM_TOKEN_W0,
-    AFM_TOKEN_W0X,
-    AFM_TOKEN_W0Y,
-    AFM_TOKEN_W1,
-    AFM_TOKEN_W1X,
-    AFM_TOKEN_W1Y,
-    AFM_TOKEN_WX,
-    AFM_TOKEN_WY,
-    AFM_TOKEN_WEIGHT,
-    AFM_TOKEN_WEIGHTVECTOR,
-    AFM_TOKEN_XHEIGHT,
-    N_AFM_TOKENS,
-    AFM_TOKEN_UNKNOWN
-
-  } AFM_Token;
-
-
-  static const char*  const afm_key_table[N_AFM_TOKENS] =
-  {
-    "Ascender",
-    "AxisLabel",
-    "AxisType",
-    "B",
-    "BlendAxisTypes",
-    "BlendDesignMap",
-    "BlendDesignPositions",
-    "C",
-    "CC",
-    "CH",
-    "CapHeight",
-    "CharWidth",
-    "CharacterSet",
-    "Characters",
-    "Descender",
-    "EncodingScheme",
-    "EndAxis",
-    "EndCharMetrics",
-    "EndComposites",
-    "EndDirection",
-    "EndFontMetrics",
-    "EndKernData",
-    "EndKernPairs",
-    "EndTrackKern",
-    "EscChar",
-    "FamilyName",
-    "FontBBox",
-    "FontName",
-    "FullName",
-    "IsBaseFont",
-    "IsCIDFont",
-    "IsFixedPitch",
-    "IsFixedV",
-    "ItalicAngle",
-    "KP",
-    "KPH",
-    "KPX",
-    "KPY",
-    "L",
-    "MappingScheme",
-    "MetricsSets",
-    "N",
-    "Notice",
-    "PCC",
-    "StartAxis",
-    "StartCharMetrics",
-    "StartComposites",
-    "StartDirection",
-    "StartFontMetrics",
-    "StartKernData",
-    "StartKernPairs",
-    "StartKernPairs0",
-    "StartKernPairs1",
-    "StartTrackKern",
-    "StdHW",
-    "StdVW",
-    "TrackKern",
-    "UnderlinePosition",
-    "UnderlineThickness",
-    "VV",
-    "VVector",
-    "Version",
-    "W",
-    "W0",
-    "W0X",
-    "W0Y",
-    "W1",
-    "W1X",
-    "W1Y",
-    "WX",
-    "WY",
-    "Weight",
-    "WeightVector",
-    "XHeight"
-  };
-
-
-  /*
-   * `afm_parser_read_vals' and `afm_parser_next_key' provide
-   * high-level operations to an AFM_Stream.  The rest of the
-   * parser functions should use them without accessing the
-   * AFM_Stream directly.
-   */
-
-  FT_LOCAL_DEF( FT_Int )
-  afm_parser_read_vals( AFM_Parser  parser,
-                        AFM_Value   vals,
-                        FT_UInt     n )
-  {
-    AFM_Stream  stream = parser->stream;
-    char*       str;
-    FT_UInt     i;
-
-
-    if ( n > AFM_MAX_ARGUMENTS )
-      return 0;
-
-    for ( i = 0; i < n; i++ )
-    {
-      FT_Offset  len;
-      AFM_Value  val = vals + i;
-
-
-      if ( val->type == AFM_VALUE_TYPE_STRING )
-        str = afm_stream_read_string( stream );
-      else
-        str = afm_stream_read_one( stream );
-
-      if ( !str )
-        break;
-
-      len = AFM_STREAM_KEY_LEN( stream, str );
-
-      switch ( val->type )
-      {
-      case AFM_VALUE_TYPE_STRING:
-      case AFM_VALUE_TYPE_NAME:
-        {
-          FT_Memory  memory = parser->memory;
-          FT_Error   error;
-
-
-          if ( !FT_QALLOC( val->u.s, len + 1 ) )
-          {
-            ft_memcpy( val->u.s, str, len );
-            val->u.s[len] = '\0';
-          }
-        }
-        break;
-
-      case AFM_VALUE_TYPE_FIXED:
-        val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
-                                    (FT_Byte*)str + len, 0 );
-        break;
-
-      case AFM_VALUE_TYPE_INTEGER:
-        val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
-                                  (FT_Byte*)str + len );
-        break;
-
-      case AFM_VALUE_TYPE_BOOL:
-        val->u.b = FT_BOOL( len == 4                      &&
-                            !ft_strncmp( str, "true", 4 ) );
-        break;
-
-      case AFM_VALUE_TYPE_INDEX:
-        if ( parser->get_index )
-          val->u.i = parser->get_index( str, len, parser->user_data );
-        else
-          val->u.i = 0;
-        break;
-      }
-    }
-
-    return i;
-  }
-
-
-  FT_LOCAL_DEF( char* )
-  afm_parser_next_key( AFM_Parser  parser,
-                       FT_Bool     line,
-                       FT_Offset*  len )
-  {
-    AFM_Stream  stream = parser->stream;
-    char*       key    = 0;  /* make stupid compiler happy */
-
-
-    if ( line )
-    {
-      while ( 1 )
-      {
-        /* skip current line */
-        if ( !AFM_STATUS_EOL( stream ) )
-          afm_stream_read_string( stream );
-
-        stream->status = AFM_STREAM_STATUS_NORMAL;
-        key = afm_stream_read_one( stream );
-
-        /* skip empty line */
-        if ( !key                      &&
-             !AFM_STATUS_EOF( stream ) &&
-             AFM_STATUS_EOL( stream )  )
-          continue;
-
-        break;
-      }
-    }
-    else
-    {
-      while ( 1 )
-      {
-        /* skip current column */
-        while ( !AFM_STATUS_EOC( stream ) )
-          afm_stream_read_one( stream );
-
-        stream->status = AFM_STREAM_STATUS_NORMAL;
-        key = afm_stream_read_one( stream );
-
-        /* skip empty column */
-        if ( !key                      &&
-             !AFM_STATUS_EOF( stream ) &&
-             AFM_STATUS_EOC( stream )  )
-          continue;
-
-        break;
-      }
-    }
-
-    if ( len )
-      *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key )
-                     : 0;
-
-    return key;
-  }
-
-
-  static AFM_Token
-  afm_tokenize( const char*  key,
-                FT_Offset    len )
-  {
-    int  n;
-
-
-    for ( n = 0; n < N_AFM_TOKENS; n++ )
-    {
-      if ( *( afm_key_table[n] ) == *key )
-      {
-        for ( ; n < N_AFM_TOKENS; n++ )
-        {
-          if ( *( afm_key_table[n] ) != *key )
-            return AFM_TOKEN_UNKNOWN;
-
-          if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
-            return (AFM_Token) n;
-        }
-      }
-    }
-
-    return AFM_TOKEN_UNKNOWN;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  afm_parser_init( AFM_Parser  parser,
-                   FT_Memory   memory,
-                   FT_Byte*    base,
-                   FT_Byte*    limit )
-  {
-    AFM_Stream  stream = NULL;
-    FT_Error    error;
-
-
-    if ( FT_NEW( stream ) )
-      return error;
-
-    stream->cursor = stream->base = base;
-    stream->limit  = limit;
-
-    /* don't skip the first line during the first call */
-    stream->status = AFM_STREAM_STATUS_EOL;
-
-    parser->memory    = memory;
-    parser->stream    = stream;
-    parser->FontInfo  = NULL;
-    parser->get_index = NULL;
-
-    return PSaux_Err_Ok;
-  }
-
-
-  FT_LOCAL( void )
-  afm_parser_done( AFM_Parser  parser )
-  {
-    FT_Memory  memory = parser->memory;
-
-
-    FT_FREE( parser->stream );
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  afm_parser_read_int( AFM_Parser  parser,
-                       FT_Int*     aint )
-  {
-    AFM_ValueRec  val;
-
-
-    val.type = AFM_VALUE_TYPE_INTEGER;
-
-    if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
-    {
-      *aint = val.u.i;
-
-      return PSaux_Err_Ok;
-    }
-    else
-      return PSaux_Err_Syntax_Error;
-  }
-
-
-  static FT_Error
-  afm_parse_track_kern( AFM_Parser  parser )
-  {
-    AFM_FontInfo   fi = parser->FontInfo;
-    AFM_TrackKern  tk;
-    char*          key;
-    FT_Offset      len;
-    int            n = -1;
-
-
-    if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
-        goto Fail;
-
-    if ( fi->NumTrackKern )
-    {
-      FT_Memory  memory = parser->memory;
-      FT_Error   error;
-
-
-      if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
-        return error;
-    }
-
-    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
-    {
-      AFM_ValueRec  shared_vals[5];
-
-
-      switch ( afm_tokenize( key, len ) )
-      {
-      case AFM_TOKEN_TRACKKERN:
-        n++;
-
-        if ( n >= fi->NumTrackKern )
-          goto Fail;
-
-        tk = fi->TrackKerns + n;
-
-        shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
-        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
-        if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
-          goto Fail;
-
-        tk->degree     = shared_vals[0].u.i;
-        tk->min_ptsize = shared_vals[1].u.f;
-        tk->min_kern   = shared_vals[2].u.f;
-        tk->max_ptsize = shared_vals[3].u.f;
-        tk->max_kern   = shared_vals[4].u.f;
-
-        /* is this correct? */
-        if ( tk->degree < 0 && tk->min_kern > 0 )
-          tk->min_kern = -tk->min_kern;
-        break;
-
-      case AFM_TOKEN_ENDTRACKKERN:
-      case AFM_TOKEN_ENDKERNDATA:
-      case AFM_TOKEN_ENDFONTMETRICS:
-        fi->NumTrackKern = n + 1;
-        return PSaux_Err_Ok;
-
-      case AFM_TOKEN_UNKNOWN:
-        break;
-
-      default:
-        goto Fail;
-      }
-    }
-
-  Fail:
-    return PSaux_Err_Syntax_Error;
-  }
-
-
-#undef  KERN_INDEX
-#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
-
-
-  /* compare two kerning pairs */
-  FT_CALLBACK_DEF( int )
-  afm_compare_kern_pairs( const void*  a,
-                          const void*  b )
-  {
-    AFM_KernPair  kp1 = (AFM_KernPair)a;
-    AFM_KernPair  kp2 = (AFM_KernPair)b;
-
-    FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
-    FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
-
-
-    if ( index1 > index2 )
-      return 1;
-    else if ( index1 < index2 )
-      return -1;
-    else
-      return 0;
-  }
-
-
-  static FT_Error
-  afm_parse_kern_pairs( AFM_Parser  parser )
-  {
-    AFM_FontInfo  fi = parser->FontInfo;
-    AFM_KernPair  kp;
-    char*         key;
-    FT_Offset     len;
-    int           n = -1;
-
-
-    if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
-      goto Fail;
-
-    if ( fi->NumKernPair )
-    {
-      FT_Memory  memory = parser->memory;
-      FT_Error   error;
-
-
-      if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
-        return error;
-    }
-
-    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
-    {
-      AFM_Token  token = afm_tokenize( key, len );
-
-
-      switch ( token )
-      {
-      case AFM_TOKEN_KP:
-      case AFM_TOKEN_KPX:
-      case AFM_TOKEN_KPY:
-        {
-          FT_Int        r;
-          AFM_ValueRec  shared_vals[4];
-
-
-          n++;
-
-          if ( n >= fi->NumKernPair )
-            goto Fail;
-
-          kp = fi->KernPairs + n;
-
-          shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
-          shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
-          shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
-          shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
-          r = afm_parser_read_vals( parser, shared_vals, 4 );
-          if ( r < 3 )
-            goto Fail;
-
-          kp->index1 = shared_vals[0].u.i;
-          kp->index2 = shared_vals[1].u.i;
-          if ( token == AFM_TOKEN_KPY )
-          {
-            kp->x = 0;
-            kp->y = shared_vals[2].u.i;
-          }
-          else
-          {
-            kp->x = shared_vals[2].u.i;
-            kp->y = ( token == AFM_TOKEN_KP && r == 4 )
-                      ? shared_vals[3].u.i : 0;
-          }
-        }
-        break;
-
-      case AFM_TOKEN_ENDKERNPAIRS:
-      case AFM_TOKEN_ENDKERNDATA:
-      case AFM_TOKEN_ENDFONTMETRICS:
-        fi->NumKernPair = n + 1;
-        ft_qsort( fi->KernPairs, fi->NumKernPair,
-                  sizeof( AFM_KernPairRec ),
-                  afm_compare_kern_pairs );
-        return PSaux_Err_Ok;
-
-      case AFM_TOKEN_UNKNOWN:
-        break;
-
-      default:
-        goto Fail;
-      }
-    }
-
-  Fail:
-    return PSaux_Err_Syntax_Error;
-  }
-
-
-  static FT_Error
-  afm_parse_kern_data( AFM_Parser  parser )
-  {
-    FT_Error   error;
-    char*      key;
-    FT_Offset  len;
-
-
-    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
-    {
-      switch ( afm_tokenize( key, len ) )
-      {
-      case AFM_TOKEN_STARTTRACKKERN:
-        error = afm_parse_track_kern( parser );
-        if ( error )
-          return error;
-        break;
-
-      case AFM_TOKEN_STARTKERNPAIRS:
-      case AFM_TOKEN_STARTKERNPAIRS0:
-        error = afm_parse_kern_pairs( parser );
-        if ( error )
-          return error;
-        break;
-
-      case AFM_TOKEN_ENDKERNDATA:
-      case AFM_TOKEN_ENDFONTMETRICS:
-        return PSaux_Err_Ok;
-
-      case AFM_TOKEN_UNKNOWN:
-        break;
-
-      default:
-        goto Fail;
-      }
-    }
-
-  Fail:
-    return PSaux_Err_Syntax_Error;
-  }
-
-
-  static FT_Error
-  afm_parser_skip_section( AFM_Parser  parser,
-                           FT_UInt     n,
-                           AFM_Token   end_section )
-  {
-    char*      key;
-    FT_Offset  len;
-
-
-    while ( n-- > 0 )
-    {
-      key = afm_parser_next_key( parser, 1, NULL );
-      if ( !key )
-        goto Fail;
-    }
-
-    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
-    {
-      AFM_Token  token = afm_tokenize( key, len );
-
-
-      if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
-        return PSaux_Err_Ok;
-    }
-
-  Fail:
-    return PSaux_Err_Syntax_Error;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  afm_parser_parse( AFM_Parser  parser )
-  {
-    FT_Memory     memory = parser->memory;
-    AFM_FontInfo  fi     = parser->FontInfo;
-    FT_Error      error  = PSaux_Err_Syntax_Error;
-    char*         key;
-    FT_Offset     len;
-    FT_Int        metrics_sets = 0;
-
-
-    if ( !fi )
-      return PSaux_Err_Invalid_Argument;
-
-    key = afm_parser_next_key( parser, 1, &len );
-    if ( !key || len != 16                              ||
-         ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
-      return PSaux_Err_Unknown_File_Format;
-
-    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
-    {
-      AFM_ValueRec  shared_vals[4];
-
-
-      switch ( afm_tokenize( key, len ) )
-      {
-      case AFM_TOKEN_METRICSSETS:
-        if ( afm_parser_read_int( parser, &metrics_sets ) )
-          goto Fail;
-
-        if ( metrics_sets != 0 && metrics_sets != 2 )
-        {
-          error = PSaux_Err_Unimplemented_Feature;
-
-          goto Fail;
-        }
-        break;
-
-      case AFM_TOKEN_ISCIDFONT:
-        shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
-        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
-          goto Fail;
-
-        fi->IsCIDFont = shared_vals[0].u.b;
-        break;
-
-      case AFM_TOKEN_FONTBBOX:
-        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
-        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
-        if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
-          goto Fail;
-
-        fi->FontBBox.xMin = shared_vals[0].u.f;
-        fi->FontBBox.yMin = shared_vals[1].u.f;
-        fi->FontBBox.xMax = shared_vals[2].u.f;
-        fi->FontBBox.yMax = shared_vals[3].u.f;
-        break;
-
-      case AFM_TOKEN_ASCENDER:
-        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
-        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
-          goto Fail;
-
-        fi->Ascender = shared_vals[0].u.f;
-        break;
-
-      case AFM_TOKEN_DESCENDER:
-        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
-        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
-          goto Fail;
-
-        fi->Descender = shared_vals[0].u.f;
-        break;
-
-      case AFM_TOKEN_STARTCHARMETRICS:
-        {
-          FT_Int  n = 0;
-
-
-          if ( afm_parser_read_int( parser, &n ) )
-            goto Fail;
-
-          error = afm_parser_skip_section( parser, n,
-                                           AFM_TOKEN_ENDCHARMETRICS );
-          if ( error )
-            return error;
-        }
-        break;
-
-      case AFM_TOKEN_STARTKERNDATA:
-        error = afm_parse_kern_data( parser );
-        if ( error )
-          goto Fail;
-        /* fall through since we only support kern data */
-
-      case AFM_TOKEN_ENDFONTMETRICS:
-        return PSaux_Err_Ok;
-
-      default:
-        break;
-      }
-    }
-
-  Fail:
-    FT_FREE( fi->TrackKerns );
-    fi->NumTrackKern = 0;
-
-    FT_FREE( fi->KernPairs );
-    fi->NumKernPair = 0;
-
-    fi->IsCIDFont = 0;
-
-    return error;
-  }
-
-
-/* END */