1 /* 2 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved. 3 * 4 * This file may be freely copied and redistributed as long as: 5 * 1) This entire notice continues to be included in the file, 6 * 2) If the file has been modified in any way, a notice of such 7 * modification is conspicuously indicated. 8 * 9 * PostScript, Display PostScript, and Adobe are registered trademarks of 10 * Adobe Systems Incorporated. 11 * 12 * ************************************************************************ 13 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT 14 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS 15 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR 16 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY 17 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, 18 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 20 * ************************************************************************ 21 */ 22 23 /* 24 * Changes made for OpenOffice.org 25 * 26 * 10/24/2000 pl - changed code to compile with c++-compilers 27 * - added namespace to avoid symbol clashes 28 * - replaced BOOL by bool 29 * - added function to free space allocated by parseFile 30 * 10/26/2000 pl - added additional keys 31 * - added ability to parse slightly broken files 32 * - added charwidth member to GlobalFontInfo 33 * 04/26/2001 pl - added OpenOffice header 34 * 10/19/2005 pl - performance increase: 35 * - fread file in one pass 36 * - replace file io by buffer access 37 * 10/20/2005 pl - performance increase: 38 * - use one table lookup in token() routine 39 * instead of many conditions 40 * - return token length in toke() routine 41 * - use hash lookup instead of binary search 42 * in recognize() routine 43 */ 44 45 // MARKER(update_precomp.py): autogen include statement, do not remove 46 #include "precompiled_vcl.hxx" 47 48 /* parseAFM.c 49 * 50 * This file is used in conjunction with the parseAFM.h header file. 51 * This file contains several procedures that are used to parse AFM 52 * files. It is intended to work with an application program that needs 53 * font metric information. The program can be used as is by making a 54 * procedure call to "parseFile" (passing in the expected parameters) 55 * and having it fill in a data structure with the data from the 56 * AFM file, or an application developer may wish to customize this 57 * code. 58 * 59 * There is also a file, parseAFMclient.c, that is a sample application 60 * showing how to call the "parseFile" procedure and how to use the data 61 * after "parseFile" has returned. 62 * 63 * Please read the comments in parseAFM.h and parseAFMclient.c. 64 * 65 * History: 66 * original: DSM Thu Oct 20 17:39:59 PDT 1988 67 * modified: DSM Mon Jul 3 14:17:50 PDT 1989 68 * - added 'storageProblem' return code 69 * - fixed bug of not allocating extra byte for string duplication 70 * - fixed typos 71 * modified: DSM Tue Apr 3 11:18:34 PDT 1990 72 * - added free(ident) at end of parseFile routine 73 * modified: DSM Tue Jun 19 10:16:29 PDT 1990 74 * - changed (width == 250) to (width = 250) in initializeArray 75 */ 76 77 #include <stdio.h> 78 #include <string.h> 79 #include <stdlib.h> 80 #include <errno.h> 81 #include <sys/file.h> 82 #include <sys/stat.h> 83 #include <math.h> 84 85 #include "parseAFM.hxx" 86 #include "vcl/strhelper.hxx" 87 88 #include "rtl/alloc.h" 89 90 #define lineterm EOL /* line terminating character */ 91 #define normalEOF 1 /* return code from parsing routines used only */ 92 /* in this module */ 93 #define Space "space" /* used in string comparison to look for the width */ 94 /* of the space character to init the widths array */ 95 #define False "false" /* used in string comparison to check the value of */ 96 /* boolean keys (e.g. IsFixedPitch) */ 97 98 #define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0) 99 100 namespace psp { 101 102 class FileInputStream 103 { 104 char* m_pMemory; 105 unsigned int m_nPos; 106 unsigned int m_nLen; 107 public: 108 FileInputStream( const char* pFilename ); 109 ~FileInputStream(); 110 111 int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; } 112 void ungetChar() 113 { 114 if( m_nPos > 0 ) 115 m_nPos--; 116 } 117 unsigned int tell() const { return m_nPos; } 118 void seek( unsigned int nPos ) 119 // NOTE: do not check input data since only results of tell() 120 // get seek()ed in this file 121 { m_nPos = nPos; } 122 }; 123 124 FileInputStream::FileInputStream( const char* pFilename ) : 125 m_pMemory( NULL ), 126 m_nPos( 0 ), 127 m_nLen( 0 ) 128 { 129 struct stat aStat; 130 if( ! stat( pFilename, &aStat ) && 131 S_ISREG( aStat.st_mode ) && 132 aStat.st_size > 0 133 ) 134 { 135 FILE* fp = fopen( pFilename, "r" ); 136 if( fp ) 137 { 138 m_pMemory = (char*)rtl_allocateMemory( aStat.st_size ); 139 m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp ); 140 fclose( fp ); 141 } 142 } 143 } 144 145 FileInputStream::~FileInputStream() 146 { 147 rtl_freeMemory( m_pMemory ); 148 } 149 150 /*************************** GLOBALS ***********************/ 151 /* "shorts" for fast case statement 152 * The values of each of these enumerated items correspond to an entry in the 153 * table of strings defined below. Therefore, if you add a new string as 154 * new keyword into the keyStrings table, you must also add a corresponding 155 * parseKey AND it MUST be in the same position! 156 * 157 * IMPORTANT: since the sorting algorithm is a binary search, the strings of 158 * keywords must be placed in lexicographical order, below. [Therefore, the 159 * enumerated items are not necessarily in lexicographical order, depending 160 * on the name chosen. BUT, they must be placed in the same position as the 161 * corresponding key string.] The NOPE shall remain in the last position, 162 * since it does not correspond to any key string, and it is used in the 163 * "recognize" procedure to calculate how many possible keys there are. 164 */ 165 166 // some metrics have Ascent, Descent instead Ascender, Descender or Em 167 // which is not allowed per afm spcification, but let us handle 168 // this gently 169 enum parseKey { 170 ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT, 171 DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION, 172 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, 173 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH, 174 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME, 175 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION, 176 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, 177 STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION, 178 UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT, 179 NOPE 180 }; 181 182 /*************************** PARSING ROUTINES **************/ 183 184 /*************************** token *************************/ 185 186 /* A "AFM file Conventions" tokenizer. That means that it will 187 * return the next token delimited by white space. See also 188 * the `linetoken' routine, which does a similar thing but 189 * reads all tokens until the next end-of-line. 190 */ 191 192 // token white space is ' ', '\n', '\r', ',', '\t', ';' 193 static const bool is_white_Array[ 256 ] = 194 { false, false, false, false, false, false, false, false, // 0-7 195 false, true, true, false, false, true, false, false, // 8-15 196 false, false, false, false, false, false, false, false, // 16-23 197 false, false, false, false, false, false, false, false, // 24-31 198 true, false, false, false, false, false, false, false, // 32-39 199 false, false, false, false, true, false, false, false, // 40-47 200 false, false, false, false, false, false, false, false, // 48-55 201 false, false, false, true, false, false, false, false, // 56-63 202 203 false, false, false, false, false, false, false, false, // 64 - 204 false, false, false, false, false, false, false, false, 205 false, false, false, false, false, false, false, false, 206 false, false, false, false, false, false, false, false, 207 false, false, false, false, false, false, false, false, 208 false, false, false, false, false, false, false, false, 209 false, false, false, false, false, false, false, false, 210 false, false, false, false, false, false, false, false, // 127 211 212 false, false, false, false, false, false, false, false, // 128 - 213 false, false, false, false, false, false, false, false, 214 false, false, false, false, false, false, false, false, 215 false, false, false, false, false, false, false, false, 216 false, false, false, false, false, false, false, false, 217 false, false, false, false, false, false, false, false, 218 false, false, false, false, false, false, false, false, 219 false, false, false, false, false, false, false, false, // 191 220 221 false, false, false, false, false, false, false, false, // 192 - 222 false, false, false, false, false, false, false, false, 223 false, false, false, false, false, false, false, false, 224 false, false, false, false, false, false, false, false, 225 false, false, false, false, false, false, false, false, 226 false, false, false, false, false, false, false, false, 227 false, false, false, false, false, false, false, false, 228 false, false, false, false, false, false, false, false, // 255 229 }; 230 // token delimiters are ' ', '\n', '\r', '\t', ':', ';' 231 static const bool is_delimiter_Array[ 256 ] = 232 { false, false, false, false, false, false, false, false, // 0-7 233 false, true, true, false, false, true, false, false, // 8-15 234 false, false, false, false, false, false, false, false, // 16-23 235 false, false, false, false, false, false, false, false, // 24-31 236 true, false, false, false, false, false, false, false, // 32-39 237 false, false, false, false, false, false, false, false, // 40-47 238 false, false, false, false, false, false, false, false, // 48-55 239 false, false, true, true, false, false, false, false, // 56-63 240 241 false, false, false, false, false, false, false, false, // 64 - 242 false, false, false, false, false, false, false, false, 243 false, false, false, false, false, false, false, false, 244 false, false, false, false, false, false, false, false, 245 false, false, false, false, false, false, false, false, 246 false, false, false, false, false, false, false, false, 247 false, false, false, false, false, false, false, false, 248 false, false, false, false, false, false, false, false, // 127 249 250 false, false, false, false, false, false, false, false, // 128 - 251 false, false, false, false, false, false, false, false, 252 false, false, false, false, false, false, false, false, 253 false, false, false, false, false, false, false, false, 254 false, false, false, false, false, false, false, false, 255 false, false, false, false, false, false, false, false, 256 false, false, false, false, false, false, false, false, 257 false, false, false, false, false, false, false, false, // 191 258 259 false, false, false, false, false, false, false, false, // 192 - 260 false, false, false, false, false, false, false, false, 261 false, false, false, false, false, false, false, false, 262 false, false, false, false, false, false, false, false, 263 false, false, false, false, false, false, false, false, 264 false, false, false, false, false, false, false, false, 265 false, false, false, false, false, false, false, false, 266 false, false, false, false, false, false, false, false, // 255 267 }; 268 static char *token( FileInputStream* stream, int& rLen ) 269 { 270 static char ident[MAX_NAME]; /* storage buffer for keywords */ 271 272 int ch, idx; 273 274 /* skip over white space */ 275 // relies on EOF = -1 276 while( is_white_Array[ (ch = stream->getChar()) & 255 ] ) 277 ; 278 279 idx = 0; 280 while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 ) 281 { 282 ident[idx++] = ch; 283 ch = stream->getChar(); 284 } 285 286 if (ch == -1 && idx < 1) return ((char *)NULL); 287 if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar(); 288 if (idx < 1 ) ident[idx++] = ch; /* single-character token */ 289 ident[idx] = 0; 290 rLen = idx; 291 292 return(ident); /* returns pointer to the token */ 293 294 } /* token */ 295 296 297 /*************************** linetoken *************************/ 298 299 /* "linetoken" will get read all tokens until the EOL character from 300 * the given stream. This is used to get any arguments that can be 301 * more than one word (like Comment lines and FullName). 302 */ 303 304 static char *linetoken( FileInputStream* stream ) 305 { 306 static char ident[MAX_NAME]; /* storage buffer for keywords */ 307 int ch, idx; 308 309 while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ; 310 311 idx = 0; 312 while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 ) 313 { 314 ident[idx++] = ch; 315 ch = stream->getChar(); 316 } /* while */ 317 318 stream->ungetChar(); 319 ident[idx] = 0; 320 321 return(ident); /* returns pointer to the token */ 322 323 } /* linetoken */ 324 325 326 /*************************** recognize *************************/ 327 328 /* This function tries to match a string to a known list of 329 * valid AFM entries (check the keyStrings array above). 330 * "ident" contains everything from white space through the 331 * next space, tab, or ":" character. 332 * 333 * The algorithm is a standard Knuth binary search. 334 */ 335 #include "afm_hash.cpp" 336 337 static inline enum parseKey recognize( register char* ident, int len) 338 { 339 const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len ); 340 return pEntry ? pEntry->eKey : NOPE; 341 342 } /* recognize */ 343 344 345 /************************* parseGlobals *****************************/ 346 347 /* This function is called by "parseFile". It will parse the AFM file 348 * up to the "StartCharMetrics" keyword, which essentially marks the 349 * end of the Global Font Information and the beginning of the character 350 * metrics information. 351 * 352 * If the caller of "parseFile" specified that it wanted the Global 353 * Font Information (as defined by the "AFM file Specification" 354 * document), then that information will be stored in the returned 355 * data structure. 356 * 357 * Any Global Font Information entries that are not found in a 358 * given file, will have the usual default initialization value 359 * for its type (i.e. entries of type int will be 0, etc). 360 * 361 * This function returns an error code specifying whether there was 362 * a premature EOF or a parsing error. This return value is used by 363 * parseFile to determine if there is more file to parse. 364 */ 365 366 static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi ) 367 { 368 bool cont = true, save = (gfi != NULL); 369 int error = ok; 370 register char *keyword; 371 int direction = -1; 372 int tokenlen; 373 374 while (cont) 375 { 376 keyword = token(fp, tokenlen); 377 378 if (keyword == NULL) 379 /* Have reached an early and unexpected EOF. */ 380 /* Set flag and stop parsing */ 381 { 382 error = earlyEOF; 383 break; /* get out of loop */ 384 } 385 if (!save) 386 /* get tokens until the end of the Global Font info section */ 387 /* without saving any of the data */ 388 switch (recognize(keyword, tokenlen)) 389 { 390 case STARTCHARMETRICS: 391 cont = false; 392 break; 393 case ENDFONTMETRICS: 394 cont = false; 395 error = normalEOF; 396 break; 397 default: 398 break; 399 } /* switch */ 400 else 401 /* otherwise parse entire global font info section, */ 402 /* saving the data */ 403 switch(recognize(keyword, tokenlen)) 404 { 405 case STARTFONTMETRICS: 406 if ((keyword = token(fp,tokenlen)) != NULL) 407 gfi->afmVersion = strdup( keyword ); 408 break; 409 case COMMENT: 410 keyword = linetoken(fp); 411 break; 412 case FONTNAME: 413 if ((keyword = token(fp,tokenlen)) != NULL) 414 gfi->fontName = strdup( keyword ); 415 break; 416 case ENCODINGSCHEME: 417 if ((keyword = token(fp,tokenlen)) != NULL) 418 gfi->encodingScheme = strdup( keyword ); 419 break; 420 case FULLNAME: 421 if ((keyword = linetoken(fp)) != NULL) 422 gfi->fullName = strdup( keyword ); 423 break; 424 case FAMILYNAME: 425 if ((keyword = linetoken(fp)) != NULL) 426 gfi->familyName = strdup( keyword ); 427 break; 428 case WEIGHT: 429 if ((keyword = token(fp,tokenlen)) != NULL) 430 gfi->weight = strdup( keyword ); 431 break; 432 case ITALICANGLE: 433 if ((keyword = token(fp,tokenlen)) != NULL) 434 gfi->italicAngle = StringToDouble( keyword ); 435 break; 436 case ISFIXEDPITCH: 437 if ((keyword = token(fp,tokenlen)) != NULL) 438 { 439 if (MATCH(keyword, False)) 440 gfi->isFixedPitch = 0; 441 else 442 gfi->isFixedPitch = 1; 443 } 444 break; 445 case UNDERLINEPOSITION: 446 if ((keyword = token(fp,tokenlen)) != NULL) 447 gfi->underlinePosition = atoi(keyword); 448 break; 449 case UNDERLINETHICKNESS: 450 if ((keyword = token(fp,tokenlen)) != NULL) 451 gfi->underlineThickness = atoi(keyword); 452 break; 453 case VERSION: 454 if ((keyword = token(fp,tokenlen)) != NULL) 455 gfi->version = strdup( keyword ); 456 break; 457 case NOTICE: 458 if ((keyword = linetoken(fp)) != NULL) 459 gfi->notice = strdup( keyword ); 460 break; 461 case FONTBBOX: 462 if ((keyword = token(fp,tokenlen)) != NULL) 463 gfi->fontBBox.llx = atoi(keyword); 464 if ((keyword = token(fp,tokenlen)) != NULL) 465 gfi->fontBBox.lly = atoi(keyword); 466 if ((keyword = token(fp,tokenlen)) != NULL) 467 gfi->fontBBox.urx = atoi(keyword); 468 if ((keyword = token(fp,tokenlen)) != NULL) 469 gfi->fontBBox.ury = atoi(keyword); 470 break; 471 case CAPHEIGHT: 472 if ((keyword = token(fp,tokenlen)) != NULL) 473 gfi->capHeight = atoi(keyword); 474 break; 475 case XHEIGHT: 476 if ((keyword = token(fp,tokenlen)) != NULL) 477 gfi->xHeight = atoi(keyword); 478 break; 479 case DESCENT: 480 if ((keyword = token(fp,tokenlen)) != NULL) 481 gfi->descender = -atoi(keyword); 482 break; 483 case DESCENDER: 484 if ((keyword = token(fp,tokenlen)) != NULL) 485 gfi->descender = atoi(keyword); 486 break; 487 case ASCENT: 488 case ASCENDER: 489 if ((keyword = token(fp,tokenlen)) != NULL) 490 gfi->ascender = atoi(keyword); 491 break; 492 case STARTCHARMETRICS: 493 cont = false; 494 break; 495 case ENDFONTMETRICS: 496 cont = false; 497 error = normalEOF; 498 break; 499 case EM: 500 // skip one token 501 keyword = token(fp,tokenlen); 502 break; 503 case STARTDIRECTION: 504 if ((keyword = token(fp,tokenlen)) != NULL) 505 direction = atoi(keyword); 506 break; /* ignore this for now */ 507 case ENDDIRECTION: 508 break; /* ignore this for now */ 509 case MAPPINGSCHEME: 510 keyword = token(fp,tokenlen); 511 break; /* ignore this for now */ 512 case CHARACTERS: 513 keyword = token(fp,tokenlen); 514 break; /* ignore this for now */ 515 case ISBASEFONT: 516 keyword = token(fp,tokenlen); 517 break; /* ignore this for now */ 518 case CHARACTERSET: 519 keyword=token(fp,tokenlen); //ignore 520 break; 521 case STDHW: 522 keyword=token(fp,tokenlen); //ignore 523 break; 524 case STDVW: 525 keyword=token(fp,tokenlen); //ignore 526 break; 527 case CHARWIDTH: 528 if ((keyword = token(fp,tokenlen)) != NULL) 529 { 530 if (direction == 0) 531 gfi->charwidth = atoi(keyword); 532 } 533 keyword = token(fp,tokenlen); 534 /* ignore y-width for now */ 535 break; 536 case METRICSSETS: 537 keyword = token(fp,tokenlen); 538 break; /* ignore this for now */ 539 case NOPE: 540 default: 541 error = parseError; 542 break; 543 } /* switch */ 544 } /* while */ 545 546 return(error); 547 548 } /* parseGlobals */ 549 550 551 #if 0 552 /************************* initializeArray ************************/ 553 554 /* Unmapped character codes are (at Adobe Systems) assigned the 555 * width of the space character (if one exists) else they get the 556 * value of 250 ems. This function initializes all entries in the 557 * char widths array to have this value. Then any mapped character 558 * codes will be replaced with the width of the appropriate character 559 * when parsing the character metric section. 560 561 * This function parses the Character Metrics Section looking 562 * for a space character (by comparing character names). If found, 563 * the width of the space character will be used to initialize the 564 * values in the array of character widths. 565 * 566 * Before returning, the position of the read/write pointer of the 567 * FileInputStream is reset to be where it was upon entering this function. 568 */ 569 570 static int initializeArray( FileInputStream* fp, register int* cwi) 571 { 572 bool cont = true, found = false; 573 unsigned int opos = fp->tell(); 574 int code = 0, width = 0, i = 0, error = 0, tokenlen; 575 register char *keyword; 576 577 while (cont) 578 { 579 keyword = token(fp,tokenlen); 580 if (keyword == NULL) 581 { 582 error = earlyEOF; 583 break; /* get out of loop */ 584 } 585 switch(recognize(keyword,tokenlen)) 586 { 587 case COMMENT: 588 keyword = linetoken(fp); 589 break; 590 case CODE: 591 if ((keyword = token(fp,tokenlen)) != NULL) 592 code = atoi(keyword); 593 break; 594 case CODEHEX: 595 if ((keyword = token(fp,tokenlen)) != NULL) 596 sscanf(keyword,"<%x>", &code); 597 break; 598 case XWIDTH: 599 if ((keyword = token(fp,tokenlen)) != NULL) 600 width = atoi(keyword); 601 break; 602 case X0WIDTH: 603 (void) token(fp,tokenlen); 604 break; 605 case CHARNAME: 606 if ((keyword = token(fp,tokenlen)) != NULL) 607 if (MATCH(keyword, Space)) 608 { 609 cont = false; 610 found = true; 611 } 612 break; 613 case ENDCHARMETRICS: 614 cont = false; 615 break; 616 case ENDFONTMETRICS: 617 cont = false; 618 error = normalEOF; 619 break; 620 case NOPE: 621 default: 622 error = parseError; 623 break; 624 } /* switch */ 625 } /* while */ 626 627 if (!found) 628 width = 250; 629 630 for (i = 0; i < 256; ++i) 631 cwi[i] = width; 632 633 fp->seek(opos); 634 635 return(error); 636 637 } /* initializeArray */ 638 #endif 639 640 /************************* parseCharWidths **************************/ 641 642 /* This function is called by "parseFile". It will parse the AFM file 643 * up to the "EndCharMetrics" keyword. It will save the character 644 * width info (as opposed to all of the character metric information) 645 * if requested by the caller of parseFile. Otherwise, it will just 646 * parse through the section without saving any information. 647 * 648 * If data is to be saved, parseCharWidths is passed in a pointer 649 * to an array of widths that has already been initialized by the 650 * standard value for unmapped character codes. This function parses 651 * the Character Metrics section only storing the width information 652 * for the encoded characters into the array using the character code 653 * as the index into that array. 654 * 655 * This function returns an error code specifying whether there was 656 * a premature EOF or a parsing error. This return value is used by 657 * parseFile to determine if there is more file to parse. 658 */ 659 660 static int parseCharWidths( FileInputStream* fp, register int* cwi) 661 { 662 bool cont = true, save = (cwi != NULL); 663 int pos = 0, error = ok, tokenlen; 664 register char *keyword; 665 666 while (cont) 667 { 668 keyword = token(fp,tokenlen); 669 /* Have reached an early and unexpected EOF. */ 670 /* Set flag and stop parsing */ 671 if (keyword == NULL) 672 { 673 error = earlyEOF; 674 break; /* get out of loop */ 675 } 676 if (!save) 677 /* get tokens until the end of the Char Metrics section without */ 678 /* saving any of the data*/ 679 switch (recognize(keyword,tokenlen)) 680 { 681 case ENDCHARMETRICS: 682 cont = false; 683 break; 684 case ENDFONTMETRICS: 685 cont = false; 686 error = normalEOF; 687 break; 688 default: 689 break; 690 } /* switch */ 691 else 692 /* otherwise parse entire char metrics section, saving */ 693 /* only the char x-width info */ 694 switch(recognize(keyword,tokenlen)) 695 { 696 case COMMENT: 697 keyword = linetoken(fp); 698 break; 699 case CODE: 700 if ((keyword = token(fp,tokenlen)) != NULL) 701 pos = atoi(keyword); 702 break; 703 case XYWIDTH: 704 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */ 705 keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */ 706 error = parseError; 707 break; 708 case CODEHEX: 709 if ((keyword = token(fp,tokenlen)) != NULL) 710 sscanf(keyword, "<%x>", &pos); 711 break; 712 case X0WIDTH: 713 (void) token(fp,tokenlen); 714 break; 715 case XWIDTH: 716 if ((keyword = token(fp,tokenlen)) != NULL) 717 if (pos >= 0) /* ignore unmapped chars */ 718 cwi[pos] = atoi(keyword); 719 break; 720 case ENDCHARMETRICS: 721 cont = false; 722 break; 723 case ENDFONTMETRICS: 724 cont = false; 725 error = normalEOF; 726 break; 727 case CHARNAME: /* eat values (so doesn't cause parseError) */ 728 keyword = token(fp,tokenlen); 729 break; 730 case CHARBBOX: 731 keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); 732 keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); 733 break; 734 case LIGATURE: 735 keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); 736 break; 737 case VVECTOR: 738 keyword = token(fp,tokenlen); 739 keyword = token(fp,tokenlen); 740 break; 741 case NOPE: 742 default: 743 error = parseError; 744 break; 745 } /* switch */ 746 } /* while */ 747 748 return(error); 749 750 } /* parseCharWidths */ 751 752 753 /* 754 * number of char metrics is almost allways inaccurate, so be gentle and try to 755 * adapt our internal storage by adjusting the allocated list 756 */ 757 758 static int 759 reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size ) 760 { 761 char *p_tmpmetrics = NULL; 762 763 if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL)) 764 return storageProblem; 765 766 if (*p_oldcount == n_newcount) 767 return ok; 768 769 p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size); 770 if (p_tmpmetrics == NULL) 771 return storageProblem; 772 773 if ( n_newcount > *p_oldcount ) 774 { 775 char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount; 776 int n_inimetrics = n_size * (n_newcount - *p_oldcount); 777 memset( p_inimetrics, 0, n_inimetrics ); 778 } 779 780 *pp_fontmetrics = p_tmpmetrics; 781 *p_oldcount = n_newcount; 782 783 return ok; 784 } 785 786 static unsigned int 787 enlargeCount( unsigned int n_oldcount ) 788 { 789 unsigned int n_newcount = n_oldcount + n_oldcount / 5; 790 if (n_oldcount == n_newcount ) 791 n_newcount = n_oldcount + 5; 792 793 return n_newcount; 794 } 795 796 /************************* parseCharMetrics ************************/ 797 798 /* This function is called by parseFile if the caller of parseFile 799 * requested that all character metric information be saved 800 * (as opposed to only the character width information). 801 * 802 * parseCharMetrics is passed in a pointer to an array of records 803 * to hold information on a per character basis. This function 804 * parses the Character Metrics section storing all character 805 * metric information for the ALL characters (mapped and unmapped) 806 * into the array. 807 * 808 * This function returns an error code specifying whether there was 809 * a premature EOF or a parsing error. This return value is used by 810 * parseFile to determine if there is more file to parse. 811 */ 812 813 static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi) 814 { 815 bool cont = true, firstTime = true; 816 int error = ok, count = 0, tokenlen; 817 register CharMetricInfo *temp = fi->cmi; 818 register char *keyword; 819 820 while (cont) 821 { 822 keyword = token(fp,tokenlen); 823 if (keyword == NULL) 824 { 825 error = earlyEOF; 826 break; /* get out of loop */ 827 } 828 switch(recognize(keyword,tokenlen)) 829 { 830 case COMMENT: 831 keyword = linetoken(fp); 832 break; 833 case CODE: 834 if (!(count < fi->numOfChars)) 835 { 836 reallocFontMetrics( (void**)&(fi->cmi), 837 &(fi->numOfChars), enlargeCount(fi->numOfChars), 838 sizeof(CharMetricInfo) ); 839 temp = &(fi->cmi[ count - 1 ]); 840 } 841 if (count < fi->numOfChars) 842 { 843 if (firstTime) firstTime = false; 844 else temp++; 845 if ((keyword = token(fp,tokenlen)) != NULL) 846 temp->code = atoi(keyword); 847 if (fi->gfi && fi->gfi->charwidth) 848 temp->wx = fi->gfi->charwidth; 849 count++; 850 } 851 else 852 { 853 error = parseError; 854 cont = false; 855 } 856 break; 857 case CODEHEX: 858 if (!(count < fi->numOfChars )) 859 { 860 reallocFontMetrics( (void**)&(fi->cmi), 861 &(fi->numOfChars), enlargeCount(fi->numOfChars), 862 sizeof(CharMetricInfo) ); 863 temp = &(fi->cmi[ count - 1 ]); 864 } 865 if (count < fi->numOfChars) { 866 if (firstTime) 867 firstTime = false; 868 else 869 temp++; 870 if ((keyword = token(fp,tokenlen)) != NULL) 871 sscanf(keyword,"<%x>", &temp->code); 872 if (fi->gfi && fi->gfi->charwidth) 873 temp->wx = fi->gfi->charwidth; 874 count++; 875 } 876 else { 877 error = parseError; 878 cont = false; 879 } 880 break; 881 case XYWIDTH: 882 if ((keyword = token(fp,tokenlen)) != NULL) 883 temp->wx = atoi(keyword); 884 if ((keyword = token(fp,tokenlen)) != NULL) 885 temp->wy = atoi(keyword); 886 break; 887 case X0WIDTH: 888 if ((keyword = token(fp,tokenlen)) != NULL) 889 temp->wx = atoi(keyword); 890 break; 891 case XWIDTH: 892 if ((keyword = token(fp,tokenlen)) != NULL) 893 temp->wx = atoi(keyword); 894 break; 895 case CHARNAME: 896 if ((keyword = token(fp,tokenlen)) != NULL) 897 temp->name = (char *)strdup(keyword); 898 break; 899 case CHARBBOX: 900 if ((keyword = token(fp,tokenlen)) != NULL) 901 temp->charBBox.llx = atoi(keyword); 902 if ((keyword = token(fp,tokenlen)) != NULL) 903 temp->charBBox.lly = atoi(keyword); 904 if ((keyword = token(fp,tokenlen)) != NULL) 905 temp->charBBox.urx = atoi(keyword); 906 if ((keyword = token(fp,tokenlen)) != NULL) 907 temp->charBBox.ury = atoi(keyword); 908 break; 909 case LIGATURE: { 910 Ligature **tail = &(temp->ligs); 911 Ligature *node = *tail; 912 913 if (*tail != NULL) 914 { 915 while (node->next != NULL) 916 node = node->next; 917 tail = &(node->next); 918 } 919 920 *tail = (Ligature *) calloc(1, sizeof(Ligature)); 921 if ((keyword = token(fp,tokenlen)) != NULL) 922 (*tail)->succ = (char *)strdup(keyword); 923 if ((keyword = token(fp,tokenlen)) != NULL) 924 (*tail)->lig = (char *)strdup(keyword); 925 break; } 926 case ENDCHARMETRICS: 927 cont = false;; 928 break; 929 case ENDFONTMETRICS: 930 cont = false; 931 error = normalEOF; 932 break; 933 case VVECTOR: 934 keyword = token(fp,tokenlen); 935 keyword = token(fp,tokenlen); 936 break; 937 case NOPE: 938 default: 939 error = parseError; 940 break; 941 } /* switch */ 942 } /* while */ 943 944 if ((error == ok) && (count != fi->numOfChars)) 945 error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars), 946 count, sizeof(CharMetricInfo) ); 947 948 if ((error == ok) && (count != fi->numOfChars)) 949 error = parseError; 950 951 return(error); 952 953 } /* parseCharMetrics */ 954 955 956 957 /************************* parseTrackKernData ***********************/ 958 959 /* This function is called by "parseFile". It will parse the AFM file 960 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the 961 * track kerning data if requested by the caller of parseFile. 962 * 963 * parseTrackKernData is passed in a pointer to the FontInfo record. 964 * If data is to be saved, the FontInfo record will already contain 965 * a valid pointer to storage for the track kerning data. 966 * 967 * This function returns an error code specifying whether there was 968 * a premature EOF or a parsing error. This return value is used by 969 * parseFile to determine if there is more file to parse. 970 */ 971 972 static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi) 973 { 974 bool cont = true, save = (fi->tkd != NULL); 975 int pos = 0, error = ok, tcount = 0, tokenlen; 976 register char *keyword; 977 978 while (cont) 979 { 980 keyword = token(fp,tokenlen); 981 982 if (keyword == NULL) 983 { 984 error = earlyEOF; 985 break; /* get out of loop */ 986 } 987 if (!save) 988 /* get tokens until the end of the Track Kerning Data */ 989 /* section without saving any of the data */ 990 switch(recognize(keyword,tokenlen)) 991 { 992 case ENDTRACKKERN: 993 case ENDKERNDATA: 994 cont = false; 995 break; 996 case ENDFONTMETRICS: 997 cont = false; 998 error = normalEOF; 999 break; 1000 default: 1001 break; 1002 } /* switch */ 1003 else 1004 /* otherwise parse entire Track Kerning Data section, */ 1005 /* saving the data */ 1006 switch(recognize(keyword,tokenlen)) 1007 { 1008 case COMMENT: 1009 keyword = linetoken(fp); 1010 break; 1011 case TRACKKERN: 1012 if (!(tcount < fi->numOfTracks)) 1013 { 1014 reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks), 1015 enlargeCount(fi->numOfTracks), sizeof(TrackKernData) ); 1016 } 1017 1018 if (tcount < fi->numOfTracks) 1019 { 1020 if ((keyword = token(fp,tokenlen)) != NULL) 1021 fi->tkd[pos].degree = atoi(keyword); 1022 if ((keyword = token(fp,tokenlen)) != NULL) 1023 fi->tkd[pos].minPtSize = StringToDouble(keyword); 1024 if ((keyword = token(fp,tokenlen)) != NULL) 1025 fi->tkd[pos].minKernAmt = StringToDouble(keyword); 1026 if ((keyword = token(fp,tokenlen)) != NULL) 1027 fi->tkd[pos].maxPtSize = StringToDouble(keyword); 1028 if ((keyword = token(fp,tokenlen)) != NULL) 1029 fi->tkd[pos++].maxKernAmt = StringToDouble(keyword); 1030 tcount++; 1031 } 1032 else 1033 { 1034 error = parseError; 1035 cont = false; 1036 } 1037 break; 1038 case ENDTRACKKERN: 1039 case ENDKERNDATA: 1040 cont = false; 1041 break; 1042 case ENDFONTMETRICS: 1043 cont = false; 1044 error = normalEOF; 1045 break; 1046 case NOPE: 1047 default: 1048 error = parseError; 1049 break; 1050 } /* switch */ 1051 } /* while */ 1052 1053 if (error == ok && tcount != fi->numOfTracks) 1054 error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks), 1055 tcount, sizeof(TrackKernData) ); 1056 1057 if (error == ok && tcount != fi->numOfTracks) 1058 error = parseError; 1059 1060 return(error); 1061 1062 } /* parseTrackKernData */ 1063 1064 1065 /************************* parsePairKernData ************************/ 1066 1067 /* This function is called by "parseFile". It will parse the AFM file 1068 * up to the "EndKernPairs" or "EndKernData" keywords. It will save 1069 * the pair kerning data if requested by the caller of parseFile. 1070 * 1071 * parsePairKernData is passed in a pointer to the FontInfo record. 1072 * If data is to be saved, the FontInfo record will already contain 1073 * a valid pointer to storage for the pair kerning data. 1074 * 1075 * This function returns an error code specifying whether there was 1076 * a premature EOF or a parsing error. This return value is used by 1077 * parseFile to determine if there is more file to parse. 1078 */ 1079 1080 static int parsePairKernData( FileInputStream* fp, register FontInfo* fi) 1081 { 1082 bool cont = true, save = (fi->pkd != NULL); 1083 int pos = 0, error = ok, pcount = 0, tokenlen; 1084 register char *keyword; 1085 1086 while (cont) 1087 { 1088 keyword = token(fp,tokenlen); 1089 1090 if (keyword == NULL) 1091 { 1092 error = earlyEOF; 1093 break; /* get out of loop */ 1094 } 1095 if (!save) 1096 /* get tokens until the end of the Pair Kerning Data */ 1097 /* section without saving any of the data */ 1098 switch(recognize(keyword,tokenlen)) 1099 { 1100 case ENDKERNPAIRS: 1101 case ENDKERNDATA: 1102 cont = false; 1103 break; 1104 case ENDFONTMETRICS: 1105 cont = false; 1106 error = normalEOF; 1107 break; 1108 default: 1109 break; 1110 } /* switch */ 1111 else 1112 /* otherwise parse entire Pair Kerning Data section, */ 1113 /* saving the data */ 1114 switch(recognize(keyword,tokenlen)) 1115 { 1116 case COMMENT: 1117 keyword = linetoken(fp); 1118 break; 1119 case KERNPAIR: 1120 if (!(pcount < fi->numOfPairs)) 1121 { 1122 reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), 1123 enlargeCount(fi->numOfPairs), sizeof(PairKernData) ); 1124 } 1125 if (pcount < fi->numOfPairs) 1126 { 1127 if ((keyword = token(fp,tokenlen)) != NULL) 1128 fi->pkd[pos].name1 = strdup( keyword ); 1129 if ((keyword = token(fp,tokenlen)) != NULL) 1130 fi->pkd[pos].name2 = strdup( keyword ); 1131 if ((keyword = token(fp,tokenlen)) != NULL) 1132 fi->pkd[pos].xamt = atoi(keyword); 1133 if ((keyword = token(fp,tokenlen)) != NULL) 1134 fi->pkd[pos++].yamt = atoi(keyword); 1135 pcount++; 1136 } 1137 else 1138 { 1139 error = parseError; 1140 cont = false; 1141 } 1142 break; 1143 case KERNPAIRXAMT: 1144 if (!(pcount < fi->numOfPairs)) 1145 { 1146 reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), 1147 enlargeCount(fi->numOfPairs), sizeof(PairKernData) ); 1148 } 1149 if (pcount < fi->numOfPairs) 1150 { 1151 if ((keyword = token(fp,tokenlen)) != NULL) 1152 fi->pkd[pos].name1 = strdup( keyword ); 1153 if ((keyword = token(fp,tokenlen)) != NULL) 1154 fi->pkd[pos].name2 = strdup( keyword ); 1155 if ((keyword = token(fp,tokenlen)) != NULL) 1156 fi->pkd[pos++].xamt = atoi(keyword); 1157 pcount++; 1158 } 1159 else 1160 { 1161 error = parseError; 1162 cont = false; 1163 } 1164 break; 1165 case ENDKERNPAIRS: 1166 case ENDKERNDATA: 1167 cont = false; 1168 break; 1169 case ENDFONTMETRICS: 1170 cont = false; 1171 error = normalEOF; 1172 break; 1173 case NOPE: 1174 default: 1175 error = parseError; 1176 break; 1177 } /* switch */ 1178 } /* while */ 1179 1180 if ((error == ok) && (pcount != fi->numOfPairs)) 1181 error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), 1182 pcount, sizeof(PairKernData) ); 1183 1184 if (error == ok && pcount != fi->numOfPairs) 1185 error = parseError; 1186 1187 return(error); 1188 1189 } /* parsePairKernData */ 1190 1191 1192 /************************* parseCompCharData **************************/ 1193 1194 /* This function is called by "parseFile". It will parse the AFM file 1195 * up to the "EndComposites" keyword. It will save the composite 1196 * character data if requested by the caller of parseFile. 1197 * 1198 * parseCompCharData is passed in a pointer to the FontInfo record, and 1199 * a boolean representing if the data should be saved. 1200 * 1201 * This function will create the appropriate amount of storage for 1202 * the composite character data and store a pointer to the storage 1203 * in the FontInfo record. 1204 * 1205 * This function returns an error code specifying whether there was 1206 * a premature EOF or a parsing error. This return value is used by 1207 * parseFile to determine if there is more file to parse. 1208 */ 1209 1210 static int parseCompCharData( FileInputStream* fp, register FontInfo* fi) 1211 { 1212 bool cont = true, firstTime = true, save = (fi->ccd != NULL); 1213 int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen; 1214 register char *keyword; 1215 1216 while (cont) 1217 { 1218 keyword = token(fp,tokenlen); 1219 if (keyword == NULL) 1220 /* Have reached an early and unexpected EOF. */ 1221 /* Set flag and stop parsing */ 1222 { 1223 error = earlyEOF; 1224 break; /* get out of loop */ 1225 } 1226 if (ccount > fi->numOfComps) 1227 { 1228 reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), 1229 enlargeCount(fi->numOfComps), sizeof(CompCharData) ); 1230 } 1231 if (ccount > fi->numOfComps) 1232 { 1233 error = parseError; 1234 break; /* get out of loop */ 1235 } 1236 if (!save) 1237 /* get tokens until the end of the Composite Character info */ 1238 /* section without saving any of the data */ 1239 switch(recognize(keyword,tokenlen)) 1240 { 1241 case ENDCOMPOSITES: 1242 cont = false; 1243 break; 1244 case ENDFONTMETRICS: 1245 cont = false; 1246 error = normalEOF; 1247 break; 1248 case COMMENT: 1249 case COMPCHAR: 1250 keyword = linetoken(fp); 1251 break; 1252 default: 1253 break; 1254 } /* switch */ 1255 else 1256 /* otherwise parse entire Composite Character info section, */ 1257 /* saving the data */ 1258 switch(recognize(keyword,tokenlen)) 1259 { 1260 case COMMENT: 1261 keyword = linetoken(fp); 1262 break; 1263 case COMPCHAR: 1264 if (!(ccount < fi->numOfComps)) 1265 { 1266 reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), 1267 enlargeCount(fi->numOfComps), sizeof(CompCharData) ); 1268 } 1269 if (ccount < fi->numOfComps) 1270 { 1271 keyword = token(fp,tokenlen); 1272 if (pcount != fi->ccd[pos].numOfPieces) 1273 error = parseError; 1274 pcount = 0; 1275 if (firstTime) firstTime = false; 1276 else pos++; 1277 fi->ccd[pos].ccName = strdup( keyword ); 1278 if ((keyword = token(fp,tokenlen)) != NULL) 1279 fi->ccd[pos].numOfPieces = atoi(keyword); 1280 fi->ccd[pos].pieces = (Pcc *) 1281 calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc)); 1282 j = 0; 1283 ccount++; 1284 } 1285 else 1286 { 1287 error = parseError; 1288 cont = false; 1289 } 1290 break; 1291 case COMPCHARPIECE: 1292 if (pcount < fi->ccd[pos].numOfPieces) 1293 { 1294 if ((keyword = token(fp,tokenlen)) != NULL) 1295 fi->ccd[pos].pieces[j].pccName = strdup( keyword ); 1296 if ((keyword = token(fp,tokenlen)) != NULL) 1297 fi->ccd[pos].pieces[j].deltax = atoi(keyword); 1298 if ((keyword = token(fp,tokenlen)) != NULL) 1299 fi->ccd[pos].pieces[j++].deltay = atoi(keyword); 1300 pcount++; 1301 } 1302 else 1303 error = parseError; 1304 break; 1305 case ENDCOMPOSITES: 1306 cont = false; 1307 break; 1308 case ENDFONTMETRICS: 1309 cont = false; 1310 error = normalEOF; 1311 break; 1312 case NOPE: 1313 default: 1314 error = parseError; 1315 break; 1316 } /* switch */ 1317 } /* while */ 1318 1319 if (error == ok && ccount != fi->numOfComps) 1320 reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), 1321 ccount, sizeof(CompCharData) ); 1322 1323 if (error == ok && ccount != fi->numOfComps) 1324 error = parseError; 1325 1326 return(error); 1327 1328 } /* parseCompCharData */ 1329 1330 1331 1332 1333 /*************************** 'PUBLIC' FUNCTION ********************/ 1334 1335 1336 /*************************** parseFile *****************************/ 1337 1338 /* parseFile is the only 'public' procedure available. It is called 1339 * from an application wishing to get information from an AFM file. 1340 * The caller of this function is responsible for locating and opening 1341 * an AFM file and handling all errors associated with that task. 1342 * 1343 * parseFile expects 3 parameters: a filename pointer, a pointer 1344 * to a (FontInfo *) variable (for which storage will be allocated and 1345 * the data requested filled in), and a mask specifying which 1346 * data from the AFM file should be saved in the FontInfo structure. 1347 * 1348 * The file will be parsed and the requested data will be stored in 1349 * a record of type FontInfo (refer to ParseAFM.h). 1350 * 1351 * parseFile returns an error code as defined in parseAFM.h. 1352 * 1353 * The position of the read/write pointer associated with the file 1354 * pointer upon return of this function is undefined. 1355 */ 1356 1357 int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags) 1358 { 1359 FileInputStream aFile( pFilename ); 1360 1361 int code = ok; /* return code from each of the parsing routines */ 1362 int error = ok; /* used as the return code from this function */ 1363 int tokenlen; 1364 1365 register char *keyword; /* used to store a token */ 1366 1367 1368 (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo)); 1369 if ((*fi) == NULL) {error = storageProblem; return(error);} 1370 1371 if (flags & P_G) 1372 { 1373 (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo)); 1374 if ((*fi)->gfi == NULL) {error = storageProblem; return(error);} 1375 } 1376 1377 /* The AFM file begins with Global Font Information. This section */ 1378 /* will be parsed whether or not information should be saved. */ 1379 code = parseGlobals(&aFile, (*fi)->gfi); 1380 1381 if (code < 0) error = code; 1382 1383 /* The Global Font Information is followed by the Character Metrics */ 1384 /* section. Which procedure is used to parse this section depends on */ 1385 /* how much information should be saved. If all of the metrics info */ 1386 /* is wanted, parseCharMetrics is called. If only the character widths */ 1387 /* is wanted, parseCharWidths is called. parseCharWidths will also */ 1388 /* be called in the case that no character data is to be saved, just */ 1389 /* to parse through the section. */ 1390 1391 if ((code != normalEOF) && (code != earlyEOF)) 1392 { 1393 if ((keyword = token(&aFile,tokenlen)) != NULL) 1394 (*fi)->numOfChars = atoi(keyword); 1395 if (flags & (P_M ^ P_W)) 1396 { 1397 (*fi)->cmi = (CharMetricInfo *) 1398 calloc((*fi)->numOfChars, sizeof(CharMetricInfo)); 1399 if ((*fi)->cmi == NULL) {error = storageProblem; return(error);} 1400 code = parseCharMetrics(&aFile, *fi); 1401 } 1402 else 1403 { 1404 if (flags & P_W) 1405 { 1406 (*fi)->cwi = (int *) calloc(256, sizeof(int)); 1407 if ((*fi)->cwi == NULL) 1408 { 1409 error = storageProblem; 1410 return(error); 1411 } 1412 } 1413 /* parse section regardless */ 1414 code = parseCharWidths(&aFile, (*fi)->cwi); 1415 } /* else */ 1416 } /* if */ 1417 1418 if ((error != earlyEOF) && (code < 0)) error = code; 1419 1420 /* The remaining sections of the AFM are optional. This code will */ 1421 /* look at the next keyword in the file to determine what section */ 1422 /* is next, and then allocate the appropriate amount of storage */ 1423 /* for the data (if the data is to be saved) and call the */ 1424 /* appropriate parsing routine to parse the section. */ 1425 1426 while ((code != normalEOF) && (code != earlyEOF)) 1427 { 1428 keyword = token(&aFile,tokenlen); 1429 if (keyword == NULL) 1430 /* Have reached an early and unexpected EOF. */ 1431 /* Set flag and stop parsing */ 1432 { 1433 code = earlyEOF; 1434 break; /* get out of loop */ 1435 } 1436 switch(recognize(keyword,tokenlen)) 1437 { 1438 case STARTKERNDATA: 1439 break; 1440 case ENDKERNDATA: 1441 break; 1442 case STARTTRACKKERN: 1443 keyword = token(&aFile,tokenlen); 1444 if ((flags & P_T) && keyword) 1445 { 1446 (*fi)->numOfTracks = atoi(keyword); 1447 (*fi)->tkd = (TrackKernData *) 1448 calloc((*fi)->numOfTracks, sizeof(TrackKernData)); 1449 if ((*fi)->tkd == NULL) 1450 { 1451 error = storageProblem; 1452 return(error); 1453 } 1454 } /* if */ 1455 code = parseTrackKernData(&aFile, *fi); 1456 break; 1457 case STARTKERNPAIRS: 1458 keyword = token(&aFile,tokenlen); 1459 if ((flags & P_P) && keyword) 1460 { 1461 (*fi)->numOfPairs = atoi(keyword); 1462 (*fi)->pkd = (PairKernData *) 1463 calloc((*fi)->numOfPairs, sizeof(PairKernData)); 1464 if ((*fi)->pkd == NULL) 1465 { 1466 error = storageProblem; 1467 return(error); 1468 } 1469 } /* if */ 1470 code = parsePairKernData(&aFile, *fi); 1471 break; 1472 case STARTCOMPOSITES: 1473 keyword = token(&aFile,tokenlen); 1474 if ((flags & P_C) && keyword) 1475 { 1476 (*fi)->numOfComps = atoi(keyword); 1477 (*fi)->ccd = (CompCharData *) 1478 calloc((*fi)->numOfComps, sizeof(CompCharData)); 1479 if ((*fi)->ccd == NULL) 1480 { 1481 error = storageProblem; 1482 return(error); 1483 } 1484 } /* if */ 1485 code = parseCompCharData(&aFile, *fi); 1486 break; 1487 case ENDFONTMETRICS: 1488 code = normalEOF; 1489 break; 1490 case COMMENT: 1491 linetoken(&aFile); 1492 break; 1493 case NOPE: 1494 default: 1495 code = parseError; 1496 break; 1497 } /* switch */ 1498 1499 if ((error != earlyEOF) && (code < 0)) error = code; 1500 1501 } /* while */ 1502 1503 if ((error != earlyEOF) && (code < 0)) error = code; 1504 1505 return(error); 1506 1507 } /* parseFile */ 1508 1509 void 1510 freeFontInfo (FontInfo *fi) 1511 { 1512 int i, j; 1513 1514 if (fi->gfi) 1515 { 1516 free (fi->gfi->afmVersion); 1517 free (fi->gfi->fontName); 1518 free (fi->gfi->fullName); 1519 free (fi->gfi->familyName); 1520 free (fi->gfi->weight); 1521 free (fi->gfi->version); 1522 free (fi->gfi->notice); 1523 free (fi->gfi->encodingScheme); 1524 free (fi->gfi); 1525 } 1526 1527 free (fi->cwi); 1528 1529 if (fi->cmi) 1530 { 1531 for (i = 0; i < fi->numOfChars; i++) 1532 { 1533 Ligature *ligs; 1534 free (fi->cmi[i].name); 1535 ligs = fi->cmi[i].ligs; 1536 while (ligs) 1537 { 1538 Ligature *tmp; 1539 tmp = ligs; 1540 ligs = ligs->next; 1541 free (tmp->succ); 1542 free (tmp->lig); 1543 free (tmp); 1544 } 1545 } 1546 free (fi->cmi); 1547 } 1548 1549 free (fi->tkd); 1550 1551 if (fi->pkd) 1552 { 1553 for ( i = 0; i < fi->numOfPairs; i++) 1554 { 1555 free (fi->pkd[i].name1); 1556 free (fi->pkd[i].name2); 1557 } 1558 free (fi->pkd); 1559 } 1560 1561 if (fi->ccd) 1562 { 1563 for (i = 0; i < fi->numOfComps; i++) 1564 { 1565 free (fi->ccd[i].ccName); 1566 for (j = 0; j < fi->ccd[i].numOfPieces; j++) 1567 free (fi->ccd[i].pieces[j].pccName); 1568 1569 free (fi->ccd[i].pieces); 1570 } 1571 free (fi->ccd); 1572 } 1573 1574 free (fi); 1575 } 1576 1577 } // namspace 1578