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