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