Branch data 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 [ + - ]: 216452583 : int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
111 : 39002292 : void ungetChar()
112 : : {
113 [ + - ]: 39002292 : if( m_nPos > 0 )
114 : 39002292 : m_nPos--;
115 : 39002292 : }
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 : 4327 : FileInputStream::FileInputStream( const char* pFilename ) :
124 : : m_pMemory( NULL ),
125 : : m_nPos( 0 ),
126 : 4327 : m_nLen( 0 )
127 : : {
128 : : struct stat aStat;
129 [ + - ][ + - ]: 4327 : if( ! stat( pFilename, &aStat ) &&
[ + - ][ + - ]
130 : : S_ISREG( aStat.st_mode ) &&
131 : : aStat.st_size > 0
132 : : )
133 : : {
134 [ + - ]: 4327 : FILE* fp = fopen( pFilename, "r" );
135 [ + - ]: 4327 : if( fp )
136 : : {
137 : 4327 : m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
138 [ + - ]: 4327 : m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
139 [ + - ]: 4327 : fclose( fp );
140 : : }
141 : : }
142 : 4327 : }
143 : :
144 : 4327 : FileInputStream::~FileInputStream()
145 : : {
146 : 4327 : rtl_freeMemory( m_pMemory );
147 : 4327 : }
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 : 38976664 : 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 [ + + ]: 92792099 : while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
276 : : ;
277 : :
278 : 38976664 : idx = 0;
279 [ + - ][ + + ]: 161364785 : while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
[ + - ][ + + ]
280 : : {
281 : 122388121 : ident[idx++] = ch;
282 : 122388121 : ch = stream->getChar();
283 : : }
284 : :
285 [ - + ][ # # ]: 38976664 : if (ch == -1 && idx < 1) return ((char *)NULL);
286 [ + - ][ + - ]: 38976664 : if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
[ + - ]
287 [ - + ]: 38976664 : if (idx < 1 ) ident[idx++] = ch; /* single-character token */
288 : 38976664 : ident[idx] = 0;
289 : 38976664 : rLen = idx;
290 : :
291 : 38976664 : 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 : 25628 : static char *linetoken( FileInputStream* stream )
304 : : {
305 : : static char ident[MAX_NAME]; /* storage buffer for keywords */
306 : : int ch, idx;
307 : :
308 [ + + ][ - + ]: 51256 : while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
[ + + ]
309 : :
310 : 25628 : idx = 0;
311 [ + - ][ + + ]: 1246735 : while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
[ + - ][ + - ]
[ + + ]
312 : : {
313 : 1221107 : ident[idx++] = ch;
314 : 1221107 : ch = stream->getChar();
315 : : } /* while */
316 : :
317 : 25628 : stream->ungetChar();
318 : 25628 : ident[idx] = 0;
319 : :
320 : 25628 : 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 : 12128819 : static inline enum parseKey recognize( register char* ident, int len)
337 : : {
338 : 12128819 : const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
339 [ + - ]: 12128819 : 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 : 4327 : static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
366 : : {
367 : 4327 : bool cont = true, save = (gfi != NULL);
368 : 4327 : int error = ok;
369 : : char *keyword;
370 : 4327 : int direction = -1;
371 : : int tokenlen;
372 : :
373 [ + + ]: 98208 : while (cont)
374 : : {
375 : 93881 : keyword = token(fp, tokenlen);
376 : :
377 [ - + ]: 93881 : 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 [ - + ]: 93881 : 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 [ + + + + : 93881 : switch(recognize(keyword, tokenlen))
+ + + + +
+ + + + +
+ + - + +
+ - - - -
- - - - +
+ - - - ]
403 : : {
404 : : case STARTFONTMETRICS:
405 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
406 : 4327 : gfi->afmVersion = strdup( keyword );
407 : 4327 : break;
408 : : case COMMENT:
409 : 12647 : keyword = linetoken(fp);
410 : 12647 : break;
411 : : case FONTNAME:
412 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
413 : 4327 : gfi->fontName = strdup( keyword );
414 : 4327 : break;
415 : : case ENCODINGSCHEME:
416 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
417 : 4327 : gfi->encodingScheme = strdup( keyword );
418 : 4327 : break;
419 : : case FULLNAME:
420 [ + - ]: 4327 : if ((keyword = linetoken(fp)) != NULL)
421 : 4327 : gfi->fullName = strdup( keyword );
422 : 4327 : break;
423 : : case FAMILYNAME:
424 [ + - ]: 4327 : if ((keyword = linetoken(fp)) != NULL)
425 : 4327 : gfi->familyName = strdup( keyword );
426 : 4327 : break;
427 : : case WEIGHT:
428 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
429 : 4327 : gfi->weight = strdup( keyword );
430 : 4327 : break;
431 : : case ITALICANGLE:
432 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
433 [ + - ]: 4327 : gfi->italicAngle = StringToDouble( keyword );
434 : 4327 : break;
435 : : case ISFIXEDPITCH:
436 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
437 : : {
438 [ + + ]: 4327 : if (MATCH(keyword, False))
439 : 3875 : gfi->isFixedPitch = 0;
440 : : else
441 : 452 : gfi->isFixedPitch = 1;
442 : : }
443 : 4327 : break;
444 : : case UNDERLINEPOSITION:
445 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
446 : 4327 : gfi->underlinePosition = atoi(keyword);
447 : 4327 : break;
448 : : case UNDERLINETHICKNESS:
449 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
450 : 4327 : gfi->underlineThickness = atoi(keyword);
451 : 4327 : break;
452 : : case VERSION:
453 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
454 : 4327 : gfi->version = strdup( keyword );
455 : 4327 : break;
456 : : case NOTICE:
457 [ + - ]: 4327 : if ((keyword = linetoken(fp)) != NULL)
458 : 4327 : gfi->notice = strdup( keyword );
459 : 4327 : break;
460 : : case FONTBBOX:
461 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
462 : 4327 : gfi->fontBBox.llx = atoi(keyword);
463 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
464 : 4327 : gfi->fontBBox.lly = atoi(keyword);
465 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
466 : 4327 : gfi->fontBBox.urx = atoi(keyword);
467 [ + - ]: 4327 : if ((keyword = token(fp,tokenlen)) != NULL)
468 : 4327 : gfi->fontBBox.ury = atoi(keyword);
469 : 4327 : break;
470 : : case CAPHEIGHT:
471 [ + - ]: 4203 : if ((keyword = token(fp,tokenlen)) != NULL)
472 : 4203 : gfi->capHeight = atoi(keyword);
473 : 4203 : break;
474 : : case XHEIGHT:
475 [ + - ]: 4203 : if ((keyword = token(fp,tokenlen)) != NULL)
476 : 4203 : gfi->xHeight = atoi(keyword);
477 : 4203 : 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 [ + - ]: 4203 : if ((keyword = token(fp,tokenlen)) != NULL)
484 : 4203 : gfi->descender = atoi(keyword);
485 : 4203 : break;
486 : : case ASCENT:
487 : : case ASCENDER:
488 [ + - ]: 4203 : if ((keyword = token(fp,tokenlen)) != NULL)
489 : 4203 : gfi->ascender = atoi(keyword);
490 : 4203 : break;
491 : : case STARTCHARMETRICS:
492 : 4327 : cont = false;
493 : 4327 : 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 : 1922 : keyword=token(fp,tokenlen); //ignore
522 : 1922 : break;
523 : : case STDVW:
524 : 1922 : keyword=token(fp,tokenlen); //ignore
525 : 1922 : 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 : 4327 : 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 : 138 : reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
670 : : {
671 : 138 : char *p_tmpmetrics = NULL;
672 : :
673 [ + - ][ - + ]: 138 : if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
674 : 0 : return storageProblem;
675 : :
676 [ - + ]: 138 : if (*p_oldcount == n_newcount)
677 : 0 : return ok;
678 : :
679 : 138 : p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
680 [ - + ]: 138 : if (p_tmpmetrics == NULL)
681 : 0 : return storageProblem;
682 : :
683 [ - + ]: 138 : 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 : 138 : *pp_fontmetrics = p_tmpmetrics;
691 : 138 : *p_oldcount = n_newcount;
692 : :
693 : 138 : 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 : 4327 : static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
724 : : {
725 : 4327 : bool cont = true, firstTime = true;
726 : 4327 : int error = ok, count = 0, tokenlen;
727 : 4327 : register CharMetricInfo *temp = fi->cmi;
728 : : register char *keyword;
729 : :
730 [ + + ]: 7429242 : while (cont)
731 : : {
732 : 7424915 : keyword = token(fp,tokenlen);
733 [ - + ]: 7424915 : if (keyword == NULL)
734 : : {
735 : 0 : error = earlyEOF;
736 : 0 : break; /* get out of loop */
737 : : }
738 [ - + - - : 7424915 : switch(recognize(keyword,tokenlen))
- + + + +
+ - - - ]
739 : : {
740 : : case COMMENT:
741 : 0 : keyword = linetoken(fp);
742 : 0 : break;
743 : : case CODE:
744 [ - + ]: 1849787 : 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 [ + - ]: 1849787 : if (count < fi->numOfChars)
752 : : {
753 [ + + ]: 1849787 : if (firstTime) firstTime = false;
754 : 1845460 : else temp++;
755 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
756 : 1849787 : temp->code = atoi(keyword);
757 [ + - ][ - + ]: 1849787 : if (fi->gfi && fi->gfi->charwidth)
758 : 0 : temp->wx = fi->gfi->charwidth;
759 : 1849787 : count++;
760 : : }
761 : : else
762 : : {
763 : 0 : error = parseError;
764 : 0 : cont = false;
765 : : }
766 : 1849787 : 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 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
803 : 1849787 : temp->wx = atoi(keyword);
804 : 1849787 : break;
805 : : case CHARNAME:
806 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
807 : 1849787 : temp->name = (char *)strdup(keyword);
808 : 1849787 : break;
809 : : case CHARBBOX:
810 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
811 : 1849787 : temp->charBBox.llx = atoi(keyword);
812 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
813 : 1849787 : temp->charBBox.lly = atoi(keyword);
814 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
815 : 1849787 : temp->charBBox.urx = atoi(keyword);
816 [ + - ]: 1849787 : if ((keyword = token(fp,tokenlen)) != NULL)
817 : 1849787 : temp->charBBox.ury = atoi(keyword);
818 : 1849787 : break;
819 : : case LIGATURE: {
820 : 21440 : Ligature **tail = &(temp->ligs);
821 : 21440 : Ligature *node = *tail;
822 : :
823 [ + + ]: 21440 : if (*tail != NULL)
824 : : {
825 [ - + ]: 4054 : while (node->next != NULL)
826 : 0 : node = node->next;
827 : 4054 : tail = &(node->next);
828 : : }
829 : :
830 : 21440 : *tail = (Ligature *) calloc(1, sizeof(Ligature));
831 [ + - ]: 21440 : if ((keyword = token(fp,tokenlen)) != NULL)
832 : 21440 : (*tail)->succ = (char *)strdup(keyword);
833 [ + - ]: 21440 : if ((keyword = token(fp,tokenlen)) != NULL)
834 : 21440 : (*tail)->lig = (char *)strdup(keyword);
835 : 21440 : break; }
836 : : case ENDCHARMETRICS:
837 : 4327 : cont = false;
838 : 4327 : 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 [ + - ][ + + ]: 4327 : if ((error == ok) && (count != fi->numOfChars))
855 : : error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
856 : 138 : count, sizeof(CharMetricInfo) );
857 : :
858 [ + - ][ - + ]: 4327 : if ((error == ok) && (count != fi->numOfChars))
859 : 0 : error = parseError;
860 : :
861 : 4327 : 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 : 3806 : static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
991 : : {
992 : 3806 : bool cont = true, save = (fi->pkd != NULL);
993 : 3806 : int pos = 0, error = ok, pcount = 0, tokenlen;
994 : : register char *keyword;
995 : :
996 [ + + ]: 4598084 : while (cont)
997 : : {
998 : 4594278 : keyword = token(fp,tokenlen);
999 : :
1000 [ - + ]: 4594278 : if (keyword == NULL)
1001 : : {
1002 : 0 : error = earlyEOF;
1003 : 0 : break; /* get out of loop */
1004 : : }
1005 [ - + ]: 4594278 : 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 [ - - + + : 4594278 : 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 [ - + ]: 4590472 : if (!(pcount < fi->numOfPairs))
1055 : : {
1056 : : reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
1057 : 0 : enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
1058 : : }
1059 [ + - ]: 4590472 : if (pcount < fi->numOfPairs)
1060 : : {
1061 [ + - ]: 4590472 : if ((keyword = token(fp,tokenlen)) != NULL)
1062 : 4590472 : fi->pkd[pos].name1 = strdup( keyword );
1063 [ + - ]: 4590472 : if ((keyword = token(fp,tokenlen)) != NULL)
1064 : 4590472 : fi->pkd[pos].name2 = strdup( keyword );
1065 [ + - ]: 4590472 : if ((keyword = token(fp,tokenlen)) != NULL)
1066 : 4590472 : fi->pkd[pos++].xamt = atoi(keyword);
1067 : 4590472 : pcount++;
1068 : : }
1069 : : else
1070 : : {
1071 : 0 : error = parseError;
1072 : 0 : cont = false;
1073 : : }
1074 : 4590472 : break;
1075 : : case ENDKERNPAIRS:
1076 : : case ENDKERNDATA:
1077 : 3806 : cont = false;
1078 : 3806 : 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 [ + - ][ - + ]: 3806 : if ((error == ok) && (pcount != fi->numOfPairs))
1091 : : error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
1092 : 0 : pcount, sizeof(PairKernData) );
1093 : :
1094 [ + - ][ - + ]: 3806 : if (error == ok && pcount != fi->numOfPairs)
1095 : 0 : error = parseError;
1096 : :
1097 : 3806 : 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 : 4327 : int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
1268 : : {
1269 [ + - ]: 4327 : FileInputStream aFile( pFilename );
1270 : :
1271 : 4327 : int code = ok; /* return code from each of the parsing routines */
1272 : 4327 : 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 : 4327 : (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
1279 [ - + ]: 4327 : if ((*fi) == NULL) {error = storageProblem; return(error);}
1280 : :
1281 [ + - ]: 4327 : if (flags & P_G)
1282 : : {
1283 : 4327 : (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
1284 [ - + ]: 4327 : 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 [ + - ]: 4327 : code = parseGlobals(&aFile, (*fi)->gfi);
1290 : :
1291 [ - + ]: 4327 : 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 [ + - ][ + - ]: 4327 : if ((code != normalEOF) && (code != earlyEOF))
1302 : : {
1303 [ + - ]: 4327 : if ((keyword = token(&aFile,tokenlen)) != NULL)
1304 : 4327 : (*fi)->numOfChars = atoi(keyword);
1305 [ + - ]: 4327 : if (flags & (P_M ^ P_W))
1306 : : {
1307 : : (*fi)->cmi = (CharMetricInfo *)
1308 : 4327 : calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
1309 [ - + ]: 4327 : if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
1310 : 4327 : 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 [ + - ][ - + ]: 4327 : 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 [ + + ][ + - ]: 20072 : while ((code != normalEOF) && (code != earlyEOF))
[ + + ]
1337 : : {
1338 : 15745 : keyword = token(&aFile,tokenlen);
1339 [ - + ]: 15745 : 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 [ + + - + : 15745 : switch(recognize(keyword,tokenlen))
- + - - ]
1347 : : {
1348 : : case STARTKERNDATA:
1349 : 3806 : break;
1350 : : case ENDKERNDATA:
1351 : 3806 : 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 : 3806 : keyword = token(&aFile,tokenlen);
1369 [ + - ][ + - ]: 3806 : if ((flags & P_P) && keyword)
1370 : : {
1371 : 3806 : (*fi)->numOfPairs = atoi(keyword);
1372 : : (*fi)->pkd = (PairKernData *)
1373 : 3806 : calloc((*fi)->numOfPairs, sizeof(PairKernData));
1374 [ - + ]: 3806 : if ((*fi)->pkd == NULL)
1375 : : {
1376 : 0 : error = storageProblem;
1377 : 0 : return(error);
1378 : : }
1379 : : } /* if */
1380 : 3806 : code = parsePairKernData(&aFile, *fi);
1381 : 3806 : 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 : 4327 : code = normalEOF;
1399 : 4327 : 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 [ + - ][ - + ]: 15745 : if ((error != earlyEOF) && (code < 0)) error = code;
1410 : :
1411 : : } /* while */
1412 : :
1413 [ + - ][ - + ]: 4327 : if ((error != earlyEOF) && (code < 0)) error = code;
1414 : :
1415 : 4327 : return(error);
1416 : :
1417 : : } /* parseFile */
1418 : :
1419 : : void
1420 : 4327 : freeFontInfo (FontInfo *fi)
1421 : : {
1422 : : int i;
1423 : :
1424 [ + - ]: 4327 : if (fi->gfi)
1425 : : {
1426 : 4327 : free (fi->gfi->afmVersion);
1427 : 4327 : free (fi->gfi->fontName);
1428 : 4327 : free (fi->gfi->fullName);
1429 : 4327 : free (fi->gfi->familyName);
1430 : 4327 : free (fi->gfi->weight);
1431 : 4327 : free (fi->gfi->version);
1432 : 4327 : free (fi->gfi->notice);
1433 : 4327 : free (fi->gfi->encodingScheme);
1434 : 4327 : free (fi->gfi);
1435 : : }
1436 : :
1437 : 4327 : free (fi->cwi);
1438 : :
1439 [ + - ]: 4327 : if (fi->cmi)
1440 : : {
1441 [ + + ]: 1854114 : for (i = 0; i < fi->numOfChars; i++)
1442 : : {
1443 : : Ligature *ligs;
1444 : 1849787 : free (fi->cmi[i].name);
1445 : 1849787 : ligs = fi->cmi[i].ligs;
1446 [ + + ]: 1871227 : while (ligs)
1447 : : {
1448 : : Ligature *tmp;
1449 : 21440 : tmp = ligs;
1450 : 21440 : ligs = ligs->next;
1451 : 21440 : free (tmp->succ);
1452 : 21440 : free (tmp->lig);
1453 : 21440 : free (tmp);
1454 : : }
1455 : : }
1456 : 4327 : free (fi->cmi);
1457 : : }
1458 : :
1459 : 4327 : free (fi->tkd);
1460 : :
1461 [ + + ]: 4327 : if (fi->pkd)
1462 : : {
1463 [ + + ]: 4594278 : for ( i = 0; i < fi->numOfPairs; i++)
1464 : : {
1465 : 4590472 : free (fi->pkd[i].name1);
1466 : 4590472 : free (fi->pkd[i].name2);
1467 : : }
1468 : 3806 : free (fi->pkd);
1469 : : }
1470 : :
1471 [ - + ]: 4327 : 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 : 4327 : free (fi);
1486 : 4327 : }
1487 : :
1488 : : } // namspace
1489 : :
1490 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|