tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

afmparse.c (25277B)


      1 /****************************************************************************
      2 *
      3 * afmparse.c
      4 *
      5 *   AFM parser (body).
      6 *
      7 * Copyright (C) 2006-2025 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 */