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