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