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