LCOV - code coverage report
Current view: top level - vcl/generic/fontmanager - parseAFM.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 354 603 58.7 %
Date: 2015-06-13 12:38:46 Functions: 15 17 88.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11