summaryrefslogtreecommitdiff
path: root/vcl/unx/source/fontmanager/parseAFM.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/source/fontmanager/parseAFM.cxx')
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.cxx1577
1 files changed, 1577 insertions, 0 deletions
diff --git a/vcl/unx/source/fontmanager/parseAFM.cxx b/vcl/unx/source/fontmanager/parseAFM.cxx
new file mode 100644
index 000000000000..e1a33b4d1b5d
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.cxx
@@ -0,0 +1,1577 @@
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - performance increase:
+ * - fread file in one pass
+ * - replace file io by buffer access
+ * 10/20/2005 pl - performance increase:
+ * - use one table lookup in token() routine
+ * instead of many conditions
+ * - return token length in toke() routine
+ * - use hash lookup instead of binary search
+ * in recognize() routine
+ */
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <math.h>
+
+#include "parseAFM.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "rtl/alloc.h"
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+/* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+/* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+/* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+namespace psp {
+
+class FileInputStream
+{
+ char* m_pMemory;
+ unsigned int m_nPos;
+ unsigned int m_nLen;
+ public:
+ FileInputStream( const char* pFilename );
+ ~FileInputStream();
+
+ int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
+ void ungetChar()
+ {
+ if( m_nPos > 0 )
+ m_nPos--;
+ }
+ unsigned int tell() const { return m_nPos; }
+ void seek( unsigned int nPos )
+ // NOTE: do not check input data since only results of tell()
+ // get seek()ed in this file
+ { m_nPos = nPos; }
+};
+
+FileInputStream::FileInputStream( const char* pFilename ) :
+ m_pMemory( NULL ),
+ m_nPos( 0 ),
+ m_nLen( 0 )
+{
+ struct stat aStat;
+ if( ! stat( pFilename, &aStat ) &&
+ S_ISREG( aStat.st_mode ) &&
+ aStat.st_size > 0
+ )
+ {
+ FILE* fp = fopen( pFilename, "r" );
+ if( fp )
+ {
+ m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
+ m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
+ fclose( fp );
+ }
+ }
+}
+
+FileInputStream::~FileInputStream()
+{
+ rtl_freeMemory( m_pMemory );
+}
+
+/*************************** GLOBALS ***********************/
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+// some metrics have Ascent, Descent instead Ascender, Descender or Em
+// which is not allowed per afm spcification, but let us handle
+// this gently
+enum parseKey {
+ ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT,
+ DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE
+};
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM file Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+// token white space is ' ', '\n', '\r', ',', '\t', ';'
+static const bool is_white_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, true, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, false, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+// token delimiters are ' ', '\n', '\r', '\t', ':', ';'
+static const bool is_delimiter_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, false, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, true, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+static char *token( FileInputStream* stream, int& rLen )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+
+ int ch, idx;
+
+ /* skip over white space */
+ // relies on EOF = -1
+ while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
+ ;
+
+ idx = 0;
+ while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ }
+
+ if (ch == -1 && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+ rLen = idx;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken( FileInputStream* stream )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+ int ch, idx;
+
+ while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
+
+ idx = 0;
+ while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ } /* while */
+
+ stream->ungetChar();
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+#include "afm_hash.cpp"
+
+static inline enum parseKey recognize( register char* ident, int len)
+{
+ const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
+ return pEntry ? pEntry->eKey : NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM file Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
+{
+ bool cont = true, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+ int direction = -1;
+ int tokenlen;
+
+ while (cont)
+ {
+ keyword = token(fp, tokenlen);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword, tokenlen))
+ {
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword, tokenlen))
+ {
+ case STARTFONTMETRICS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->afmVersion = strdup( keyword );
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontName = strdup( keyword );
+ break;
+ case ENCODINGSCHEME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->encodingScheme = strdup( keyword );
+ break;
+ case FULLNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->fullName = strdup( keyword );
+ break;
+ case FAMILYNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->familyName = strdup( keyword );
+ break;
+ case WEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->weight = strdup( keyword );
+ break;
+ case ITALICANGLE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->italicAngle = StringToDouble( keyword );
+ break;
+ case ISFIXEDPITCH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ }
+ break;
+ case UNDERLINEPOSITION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->version = strdup( keyword );
+ break;
+ case NOTICE:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->notice = strdup( keyword );
+ break;
+ case FONTBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = -atoi(keyword);
+ break;
+ case DESCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENT:
+ case ASCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case EM:
+ // skip one token
+ keyword = token(fp,tokenlen);
+ break;
+ case STARTDIRECTION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ direction = atoi(keyword);
+ break; /* ignore this for now */
+ case ENDDIRECTION:
+ break; /* ignore this for now */
+ case MAPPINGSCHEME:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case ISBASEFONT:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERSET:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDHW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDVW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case CHARWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (direction == 0)
+ gfi->charwidth = atoi(keyword);
+ }
+ keyword = token(fp,tokenlen);
+ /* ignore y-width for now */
+ break;
+ case METRICSSETS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+#if 0
+/************************* initializeArray ************************/
+
+/* Unmapped character codes are (at Adobe Systems) assigned the
+ * width of the space character (if one exists) else they get the
+ * value of 250 ems. This function initializes all entries in the
+ * char widths array to have this value. Then any mapped character
+ * codes will be replaced with the width of the appropriate character
+ * when parsing the character metric section.
+
+ * This function parses the Character Metrics Section looking
+ * for a space character (by comparing character names). If found,
+ * the width of the space character will be used to initialize the
+ * values in the array of character widths.
+ *
+ * Before returning, the position of the read/write pointer of the
+ * FileInputStream is reset to be where it was upon entering this function.
+ */
+
+static int initializeArray( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, found = false;
+ unsigned int opos = fp->tell();
+ int code = 0, width = 0, i = 0, error = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ code = atoi(keyword);
+ break;
+ case CODEHEX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword,"<%x>", &code);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ width = atoi(keyword);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case CHARNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ if (MATCH(keyword, Space))
+ {
+ cont = false;
+ found = true;
+ }
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (!found)
+ width = 250;
+
+ for (i = 0; i < 256; ++i)
+ cwi[i] = width;
+
+ fp->seek(opos);
+
+ return(error);
+
+} /* initializeArray */
+#endif
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, save = (cwi != NULL);
+ int pos = 0, error = ok, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword,tokenlen))
+ {
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */
+ error = parseError;
+ break;
+ case CODEHEX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword, "<%x>", &pos);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp,tokenlen);
+ break;
+ case CHARBBOX:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case LIGATURE:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/*
+ * number of char metrics is almost allways inaccurate, so be gentle and try to
+ * adapt our internal storage by adjusting the allocated list
+ */
+
+static int
+reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
+{
+ char *p_tmpmetrics = NULL;
+
+ if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
+ return storageProblem;
+
+ if (*p_oldcount == n_newcount)
+ return ok;
+
+ p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
+ if (p_tmpmetrics == NULL)
+ return storageProblem;
+
+ if ( n_newcount > *p_oldcount )
+ {
+ char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount;
+ int n_inimetrics = n_size * (n_newcount - *p_oldcount);
+ memset( p_inimetrics, 0, n_inimetrics );
+ }
+
+ *pp_fontmetrics = p_tmpmetrics;
+ *p_oldcount = n_newcount;
+
+ return ok;
+}
+
+static unsigned int
+enlargeCount( unsigned int n_oldcount )
+{
+ unsigned int n_newcount = n_oldcount + n_oldcount / 5;
+ if (n_oldcount == n_newcount )
+ n_newcount = n_oldcount + 5;
+
+ return n_newcount;
+}
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true;
+ int error = ok, count = 0, tokenlen;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (!(count < fi->numOfChars))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = false;
+ else temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->code = atoi(keyword);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case CODEHEX:
+ if (!(count < fi->numOfChars ))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars) {
+ if (firstTime)
+ firstTime = false;
+ else
+ temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword,"<%x>", &temp->code);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case XYWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wy = atoi(keyword);
+ break;
+ case X0WIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case CHARNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->name = (char *)strdup(keyword);
+ break;
+ case CHARBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.ury = atoi(keyword);
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->succ = (char *)strdup(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->lig = (char *)strdup(keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = false;;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
+ count, sizeof(CharMetricInfo) );
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (!(tcount < fi->numOfTracks))
+ {
+ reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ enlargeCount(fi->numOfTracks), sizeof(TrackKernData) );
+ }
+
+ if (tcount < fi->numOfTracks)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].degree = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minKernAmt = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].maxPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos++].maxKernAmt = StringToDouble(keyword);
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ tcount, sizeof(TrackKernData) );
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].xamt = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (pcount != fi->numOfPairs))
+ error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ pcount, sizeof(PairKernData) );
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case COMMENT:
+ case COMPCHAR:
+ keyword = linetoken(fp);
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (!(ccount < fi->numOfComps))
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp,tokenlen);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = false;
+ else pos++;
+ fi->ccd[pos].ccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].pccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ ccount, sizeof(CompCharData) );
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a filename pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM file should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
+{
+ FileInputStream aFile( pFilename );
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+ int tokenlen;
+
+ register char *keyword; /* used to store a token */
+
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM file begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(&aFile, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ if ((keyword = token(&aFile,tokenlen)) != NULL)
+ (*fi)->numOfChars = atoi(keyword);
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(&aFile, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(&aFile, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(&aFile,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_T) && keyword)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(&aFile, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_P) && keyword)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(&aFile, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_C) && keyword)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(&aFile, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case COMMENT:
+ linetoken(&aFile);
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ return(error);
+
+} /* parseFile */
+
+void
+freeFontInfo (FontInfo *fi)
+{
+ int i, j;
+
+ if (fi->gfi)
+ {
+ free (fi->gfi->afmVersion);
+ free (fi->gfi->fontName);
+ free (fi->gfi->fullName);
+ free (fi->gfi->familyName);
+ free (fi->gfi->weight);
+ free (fi->gfi->version);
+ free (fi->gfi->notice);
+ free (fi->gfi->encodingScheme);
+ free (fi->gfi);
+ }
+
+ free (fi->cwi);
+
+ if (fi->cmi)
+ {
+ for (i = 0; i < fi->numOfChars; i++)
+ {
+ Ligature *ligs;
+ free (fi->cmi[i].name);
+ ligs = fi->cmi[i].ligs;
+ while (ligs)
+ {
+ Ligature *tmp;
+ tmp = ligs;
+ ligs = ligs->next;
+ free (tmp->succ);
+ free (tmp->lig);
+ free (tmp);
+ }
+ }
+ free (fi->cmi);
+ }
+
+ free (fi->tkd);
+
+ if (fi->pkd)
+ {
+ for ( i = 0; i < fi->numOfPairs; i++)
+ {
+ free (fi->pkd[i].name1);
+ free (fi->pkd[i].name2);
+ }
+ free (fi->pkd);
+ }
+
+ if (fi->ccd)
+ {
+ for (i = 0; i < fi->numOfComps; i++)
+ {
+ free (fi->ccd[i].ccName);
+ for (j = 0; j < fi->ccd[i].numOfPieces; j++)
+ free (fi->ccd[i].pieces[j].pccName);
+
+ free (fi->ccd[i].pieces);
+ }
+ free (fi->ccd);
+ }
+
+ free (fi);
+}
+
+} // namspace