"Fossies" - the Fresh Open Source Software Archive

Member "SDL2_ttf-2.20.2/external/freetype/src/psaux/afmparse.c" (25 May 2022, 25299 Bytes) of package /linux/misc/SDL2_ttf-2.20.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "afmparse.c" see the Fossies "Dox" file reference documentation.

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