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