1 /**************************************************************************** 2 * 3 * afmparse.c 4 * 5 * AFM parser (body). 6 * 7 * Copyright (C) 2006-2023 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 #include <freetype/freetype.h> 19 #include <freetype/internal/ftdebug.h> 20 #include <freetype/internal/psaux.h> 21 22 #ifndef T1_CONFIG_OPTION_NO_AFM 23 24 #include "afmparse.h" 25 #include "psconv.h" 26 27 #include "psauxerr.h" 28 29 30 /************************************************************************** 31 * 32 * The macro FT_COMPONENT is used in trace mode. It is an implicit 33 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 34 * messages during execution. 35 */ 36 #undef FT_COMPONENT 37 #define FT_COMPONENT afmparse 38 39 40 /************************************************************************** 41 * 42 * AFM_Stream 43 * 44 * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. 45 * 46 */ 47 48 enum 49 { 50 AFM_STREAM_STATUS_NORMAL, 51 AFM_STREAM_STATUS_EOC, 52 AFM_STREAM_STATUS_EOL, 53 AFM_STREAM_STATUS_EOF 54 }; 55 56 57 typedef struct AFM_StreamRec_ 58 { 59 FT_Byte* cursor; 60 FT_Byte* base; 61 FT_Byte* limit; 62 63 FT_Int status; 64 65 } AFM_StreamRec; 66 67 68 #ifndef EOF 69 #define EOF -1 70 #endif 71 72 73 /* this works because empty lines are ignored */ 74 #define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' ) 75 76 #define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' ) 77 #define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) 78 79 /* column separator; there is no `column' in the spec actually */ 80 #define AFM_IS_SEP( ch ) ( (ch) == ';' ) 81 82 #define AFM_GETC() \ 83 ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ 84 : EOF ) 85 86 #define AFM_STREAM_KEY_BEGIN( stream ) \ 87 (char*)( (stream)->cursor - 1 ) 88 89 #define AFM_STREAM_KEY_LEN( stream, key ) \ 90 (FT_Offset)( (char*)(stream)->cursor - key - 1 ) 91 92 #define AFM_STATUS_EOC( stream ) \ 93 ( (stream)->status >= AFM_STREAM_STATUS_EOC ) 94 95 #define AFM_STATUS_EOL( stream ) \ 96 ( (stream)->status >= AFM_STREAM_STATUS_EOL ) 97 98 #define AFM_STATUS_EOF( stream ) \ 99 ( (stream)->status >= AFM_STREAM_STATUS_EOF ) 100 101 102 static int afm_stream_skip_spaces(AFM_Stream stream)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* afm_stream_read_one(AFM_Stream stream)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* afm_stream_read_string(AFM_Stream stream)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 ) afm_parser_read_vals(AFM_Parser parser,AFM_Value vals,FT_Int n)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* ) afm_parser_next_key(AFM_Parser parser,FT_Bool line,FT_Offset * len)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 afm_tokenize(const char * key,FT_Offset len)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 ) afm_parser_init(AFM_Parser parser,FT_Memory memory,FT_Byte * base,FT_Byte * limit)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 ) afm_parser_done(AFM_Parser parser)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 afm_parser_read_int(AFM_Parser parser,FT_Int * aint)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 afm_parse_track_kern(AFM_Parser parser)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 ) afm_compare_kern_pairs(const void * a,const void * b)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 afm_parse_kern_pairs(AFM_Parser parser)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 afm_parse_kern_data(AFM_Parser parser)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 afm_parser_skip_section(AFM_Parser parser,FT_Int n,AFM_Token end_section)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 ) afm_parser_parse(AFM_Parser parser)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 */ 1095