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 conjuction 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
getChar()111 int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
ungetChar()112 void ungetChar()
113 {
114 if( m_nPos > 0 )
115 m_nPos--;
116 }
tell() const117 unsigned int tell() const { return m_nPos; }
seek(unsigned int 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
FileInputStream(const char * pFilename)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
~FileInputStream()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 };
token(FileInputStream * stream,int & rLen)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
linetoken(FileInputStream * stream)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
recognize(register char * ident,int len)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
parseGlobals(FileInputStream * fp,register GlobalFontInfo * gfi)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
parseCharWidths(FileInputStream * fp,register int * cwi)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
reallocFontMetrics(void ** pp_fontmetrics,int * p_oldcount,int n_newcount,unsigned int n_size)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
enlargeCount(unsigned int n_oldcount)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
parseCharMetrics(FileInputStream * fp,register FontInfo * fi)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
parseTrackKernData(FileInputStream * fp,register FontInfo * fi)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
parsePairKernData(FileInputStream * fp,register FontInfo * fi)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
parseCompCharData(FileInputStream * fp,register FontInfo * fi)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
parseFile(const char * pFilename,FontInfo ** fi,FLAGS flags)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
freeFontInfo(FontInfo * fi)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