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