1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
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.
10 * PostScript, Display PostScript, and Adobe are registered trademarks of
11 * Adobe Systems Incorporated.
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 * ************************************************************************
25 * Changes made for OpenOffice.org
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
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
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.
61 * Please read the comments in parseAFM.h and parseAFMclient.c.
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
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
80 #include "parseAFM.hxx"
81 #include "vcl/strhelper.hxx"
83 #include "rtl/alloc.h"
85 #define lineterm EOL /* line terminating character */
86 #define normalEOF 1 /* return code from parsing routines used only */
88 #define False "false" /* used in string comparison to check the value of */
89 /* boolean keys (e.g. IsFixedPitch) */
91 #define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
101 FileInputStream( const char* pFilename
);
104 int getChar() { return (m_nPos
< m_nLen
) ? int(m_pMemory
[m_nPos
++]) : -1; }
112 FileInputStream::FileInputStream(const char* pFilename
)
117 FILE* fp
= fopen( pFilename
, "r" );
121 if (!fstat(fileno(fp
), &aStat
) && S_ISREG(aStat
.st_mode
) && aStat
.st_size
> 0)
123 m_pMemory
= static_cast<char*>(rtl_allocateMemory( aStat
.st_size
));
124 m_nLen
= (unsigned int)fread( m_pMemory
, 1, aStat
.st_size
, fp
);
130 FileInputStream::~FileInputStream()
132 rtl_freeMemory( m_pMemory
);
135 /*************************** GLOBALS ***********************/
136 /* "shorts" for fast case statement
137 * The values of each of these enumerated items correspond to an entry in the
138 * table of strings defined below. Therefore, if you add a new string as
139 * new keyword into the keyStrings table, you must also add a corresponding
140 * parseKey AND it MUST be in the same position!
142 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
143 * keywords must be placed in lexicographical order, below. [Therefore, the
144 * enumerated items are not necessarily in lexicographical order, depending
145 * on the name chosen. BUT, they must be placed in the same position as the
146 * corresponding key string.] The NOPE shall remain in the last position,
147 * since it does not correspond to any key string, and it is used in the
148 * "recognize" procedure to calculate how many possible keys there are.
151 // some metrics have Ascent, Descent instead Ascender, Descender or Em
152 // which is not allowed per afm spcification, but let us handle
155 ASCENDER
, ASCENT
, CHARBBOX
, CODE
, COMPCHAR
, CODEHEX
, CAPHEIGHT
, CHARWIDTH
, CHARACTERSET
, CHARACTERS
, COMMENT
,
156 DESCENDER
, DESCENT
, EM
, ENCODINGSCHEME
, ENDCHARMETRICS
, ENDCOMPOSITES
, ENDDIRECTION
,
157 ENDFONTMETRICS
, ENDKERNDATA
, ENDKERNPAIRS
, ENDTRACKKERN
,
158 FAMILYNAME
, FONTBBOX
, FONTNAME
, FULLNAME
, ISBASEFONT
, ISFIXEDPITCH
,
159 ITALICANGLE
, KERNPAIR
, KERNPAIRXAMT
, LIGATURE
, MAPPINGSCHEME
, METRICSSETS
, CHARNAME
,
160 NOTICE
, COMPCHARPIECE
, STARTCHARMETRICS
, STARTCOMPOSITES
, STARTDIRECTION
,
161 STARTFONTMETRICS
, STARTKERNDATA
, STARTKERNPAIRS
,
162 STARTTRACKKERN
, STDHW
, STDVW
, TRACKKERN
, UNDERLINEPOSITION
,
163 UNDERLINETHICKNESS
, VVECTOR
, VERSION
, XYWIDTH
, X0WIDTH
, XWIDTH
, WEIGHT
, XHEIGHT
,
167 /*************************** PARSING ROUTINES **************/
169 /*************************** token *************************/
171 /* A "AFM file Conventions" tokenizer. That means that it will
172 * return the next token delimited by white space. See also
173 * the `linetoken' routine, which does a similar thing but
174 * reads all tokens until the next end-of-line.
177 // token white space is ' ', '\n', '\r', ',', '\t', ';'
178 static const bool is_white_Array
[ 256 ] =
179 { false, false, false, false, false, false, false, false, // 0-7
180 false, true, true, false, false, true, false, false, // 8-15
181 false, false, false, false, false, false, false, false, // 16-23
182 false, false, false, false, false, false, false, false, // 24-31
183 true, false, false, false, false, false, false, false, // 32-39
184 false, false, false, false, true, false, false, false, // 40-47
185 false, false, false, false, false, false, false, false, // 48-55
186 false, false, false, true, false, false, false, false, // 56-63
188 false, false, false, false, false, false, false, false, // 64 -
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,
195 false, false, false, false, false, false, false, false, // 127
197 false, false, false, false, false, false, false, false, // 128 -
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,
204 false, false, false, false, false, false, false, false, // 191
206 false, false, false, false, false, false, false, false, // 192 -
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,
213 false, false, false, false, false, false, false, false, // 255
215 // token delimiters are ' ', '\n', '\r', '\t', ':', ';'
216 static const bool is_delimiter_Array
[ 256 ] =
217 { false, false, false, false, false, false, false, false, // 0-7
218 false, true, true, false, false, true, false, false, // 8-15
219 false, false, false, false, false, false, false, false, // 16-23
220 false, false, false, false, false, false, false, false, // 24-31
221 true, false, false, false, false, false, false, false, // 32-39
222 false, false, false, false, false, false, false, false, // 40-47
223 false, false, false, false, false, false, false, false, // 48-55
224 false, false, true, true, false, false, false, false, // 56-63
226 false, false, false, false, false, false, false, false, // 64 -
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,
233 false, false, false, false, false, false, false, false, // 127
235 false, false, false, false, false, false, false, false, // 128 -
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,
242 false, false, false, false, false, false, false, false, // 191
244 false, false, false, false, false, false, false, false, // 192 -
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,
251 false, false, false, false, false, false, false, false, // 255
253 static char *token( FileInputStream
* stream
, int& rLen
)
255 static char ident
[MAX_NAME
]; /* storage buffer for keywords */
259 /* skip over white space */
260 // relies on EOF = -1
261 while( is_white_Array
[ (ch
= stream
->getChar()) & 255 ] )
265 while( ch
!= -1 && ! is_delimiter_Array
[ ch
& 255 ] && idx
< MAX_NAME
-1 )
268 ch
= stream
->getChar();
271 if (ch
== -1 && idx
< 1) return ((char *)NULL
);
272 if (idx
>= 1 && ch
!= ':' && ch
!= -1) stream
->ungetChar();
273 if (idx
< 1 ) ident
[idx
++] = ch
; /* single-character token */
277 return ident
; /* returns pointer to the token */
281 /*************************** linetoken *************************/
283 /* "linetoken" will get read all tokens until the EOL character from
284 * the given stream. This is used to get any arguments that can be
285 * more than one word (like Comment lines and FullName).
288 static char *linetoken( FileInputStream
* stream
)
290 static char ident
[MAX_NAME
]; /* storage buffer for keywords */
293 while ((ch
= stream
->getChar()) == ' ' || ch
== '\t' ) ;
296 while (ch
!= -1 && ch
!= lineterm
&& ch
!= '\r' && idx
< MAX_NAME
-1 )
299 ch
= stream
->getChar();
305 return ident
; /* returns pointer to the token */
309 /*************************** recognize *************************/
311 /* This function tries to match a string to a known list of
312 * valid AFM entries (check the keyStrings array above).
313 * "ident" contains everything from white space through the
314 * next space, tab, or ":" character.
316 * The algorithm is a standard Knuth binary search.
318 #if defined __clang__
319 #if __has_warning("-Wdeprecated-register")
320 #pragma GCC diagnostic push
321 #pragma GCC diagnostic ignored "-Wdeprecated-register"
324 #include "afm_hash.hpp"
325 #if defined __clang__
326 #if __has_warning("-Wdeprecated-register")
327 #pragma GCC diagnostic pop
331 static inline enum parseKey
recognize( char* ident
, int len
)
333 const hash_entry
* pEntry
= AfmKeywordHash::in_word_set( ident
, len
);
334 return pEntry
? pEntry
->eKey
: NOPE
;
338 /************************* parseGlobals *****************************/
340 /* This function is called by "parseFile". It will parse the AFM file
341 * up to the "StartCharMetrics" keyword, which essentially marks the
342 * end of the Global Font Information and the beginning of the character
343 * metrics information.
345 * If the caller of "parseFile" specified that it wanted the Global
346 * Font Information (as defined by the "AFM file Specification"
347 * document), then that information will be stored in the returned
350 * Any Global Font Information entries that are not found in a
351 * given file, will have the usual default initialization value
352 * for its type (i.e. entries of type int will be 0, etc).
354 * This function returns an error code specifying whether there was
355 * a premature EOF or a parsing error. This return value is used by
356 * parseFile to determine if there is more file to parse.
359 static int parseGlobals( FileInputStream
* fp
, GlobalFontInfo
* gfi
)
361 bool cont
= true, save
= (gfi
!= NULL
);
368 char *keyword
= token(fp
, tokenlen
);
371 /* Have reached an early and unexpected EOF. */
372 /* Set flag and stop parsing */
375 break; /* get out of loop */
378 /* get tokens until the end of the Global Font info section */
379 /* without saving any of the data */
380 switch (recognize(keyword
, tokenlen
))
382 case STARTCHARMETRICS
:
393 /* otherwise parse entire global font info section, */
394 /* saving the data */
395 switch(recognize(keyword
, tokenlen
))
397 case STARTFONTMETRICS
:
398 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
399 gfi
->afmVersion
= strdup( keyword
);
405 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
406 gfi
->fontName
= strdup( keyword
);
409 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
410 gfi
->encodingScheme
= strdup( keyword
);
413 if ((keyword
= linetoken(fp
)) != NULL
)
414 gfi
->fullName
= strdup( keyword
);
417 if ((keyword
= linetoken(fp
)) != NULL
)
418 gfi
->familyName
= strdup( keyword
);
421 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
422 gfi
->weight
= strdup( keyword
);
425 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
426 gfi
->italicAngle
= StringToDouble( keyword
);
429 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
431 if (MATCH(keyword
, False
))
432 gfi
->isFixedPitch
= false;
434 gfi
->isFixedPitch
= true;
437 case UNDERLINEPOSITION
:
438 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
439 gfi
->underlinePosition
= atoi(keyword
);
441 case UNDERLINETHICKNESS
:
442 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
443 gfi
->underlineThickness
= atoi(keyword
);
446 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
447 gfi
->version
= strdup( keyword
);
450 if ((keyword
= linetoken(fp
)) != NULL
)
451 gfi
->notice
= strdup( keyword
);
454 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
455 gfi
->fontBBox
.llx
= atoi(keyword
);
456 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
457 gfi
->fontBBox
.lly
= atoi(keyword
);
458 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
459 gfi
->fontBBox
.urx
= atoi(keyword
);
460 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
461 gfi
->fontBBox
.ury
= atoi(keyword
);
464 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
465 gfi
->capHeight
= atoi(keyword
);
468 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
469 gfi
->xHeight
= atoi(keyword
);
472 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
473 gfi
->descender
= -atoi(keyword
);
476 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
477 gfi
->descender
= atoi(keyword
);
481 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
482 gfi
->ascender
= atoi(keyword
);
484 case STARTCHARMETRICS
:
496 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
497 direction
= atoi(keyword
);
498 break; /* ignore this for now */
500 break; /* ignore this for now */
503 break; /* ignore this for now */
506 break; /* ignore this for now */
509 break; /* ignore this for now */
511 token(fp
,tokenlen
); //ignore
514 token(fp
,tokenlen
); //ignore
517 token(fp
,tokenlen
); //ignore
520 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
523 gfi
->charwidth
= atoi(keyword
);
526 /* ignore y-width for now */
529 token(fp
,tokenlen
); /*eat token*/
530 break; /* ignore this for now */
542 /************************* parseCharWidths **************************/
544 /* This function is called by "parseFile". It will parse the AFM file
545 * up to the "EndCharMetrics" keyword. It will save the character
546 * width info (as opposed to all of the character metric information)
547 * if requested by the caller of parseFile. Otherwise, it will just
548 * parse through the section without saving any information.
550 * If data is to be saved, parseCharWidths is passed in a pointer
551 * to an array of widths that has already been initialized by the
552 * standard value for unmapped character codes. This function parses
553 * the Character Metrics section only storing the width information
554 * for the encoded characters into the array using the character code
555 * as the index into that array.
557 * This function returns an error code specifying whether there was
558 * a premature EOF or a parsing error. This return value is used by
559 * parseFile to determine if there is more file to parse.
562 static int parseCharWidths( FileInputStream
* fp
, int* cwi
)
564 bool cont
= true, save
= (cwi
!= NULL
);
565 int pos
= 0, error
= ok
, tokenlen
;
569 char *keyword
= token(fp
,tokenlen
);
570 /* Have reached an early and unexpected EOF. */
571 /* Set flag and stop parsing */
575 break; /* get out of loop */
578 /* get tokens until the end of the Char Metrics section without */
579 /* saving any of the data*/
580 switch (recognize(keyword
,tokenlen
))
593 /* otherwise parse entire char metrics section, saving */
594 /* only the char x-width info */
595 switch(recognize(keyword
,tokenlen
))
598 linetoken(fp
); /*eat token*/
601 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
605 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
606 token(fp
,tokenlen
); token(fp
,tokenlen
); /* eat values */
610 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
611 sscanf(keyword
, "<%x>", &pos
);
614 (void) token(fp
,tokenlen
);
617 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
618 if (pos
>= 0) /* ignore unmapped chars */
619 cwi
[pos
] = atoi(keyword
);
628 case CHARNAME
: /* eat values (so doesn't cause parseError) */
632 token(fp
,tokenlen
); token(fp
,tokenlen
);
633 token(fp
,tokenlen
); token(fp
,tokenlen
);
636 token(fp
,tokenlen
); token(fp
,tokenlen
);
639 token(fp
,tokenlen
); /*eat token*/
640 token(fp
,tokenlen
); /*eat token*/
651 } /* parseCharWidths */
654 * number of char metrics is almost always inaccurate, so be gentle and try to
655 * adapt our internal storage by adjusting the allocated list
659 reallocFontMetrics( void **pp_fontmetrics
, int *p_oldcount
, int n_newcount
, unsigned int n_size
)
661 char *p_tmpmetrics
= NULL
;
663 if ((pp_fontmetrics
== NULL
) || (*pp_fontmetrics
== NULL
))
664 return storageProblem
;
666 if (*p_oldcount
== n_newcount
)
669 p_tmpmetrics
= static_cast<char*>(realloc(*pp_fontmetrics
, n_newcount
* n_size
));
670 if (p_tmpmetrics
== NULL
)
671 return storageProblem
;
673 if ( n_newcount
> *p_oldcount
)
675 char *p_inimetrics
= p_tmpmetrics
+ n_size
* *p_oldcount
;
676 int n_inimetrics
= n_size
* (n_newcount
- *p_oldcount
);
677 memset( p_inimetrics
, 0, n_inimetrics
);
680 *pp_fontmetrics
= p_tmpmetrics
;
681 *p_oldcount
= n_newcount
;
687 enlargeCount( unsigned int n_oldcount
)
689 unsigned int n_newcount
= n_oldcount
+ n_oldcount
/ 5;
690 if (n_oldcount
== n_newcount
)
691 n_newcount
= n_oldcount
+ 5;
696 /************************* parseCharMetrics ************************/
698 /* This function is called by parseFile if the caller of parseFile
699 * requested that all character metric information be saved
700 * (as opposed to only the character width information).
702 * parseCharMetrics is passed in a pointer to an array of records
703 * to hold information on a per character basis. This function
704 * parses the Character Metrics section storing all character
705 * metric information for the ALL characters (mapped and unmapped)
708 * This function returns an error code specifying whether there was
709 * a premature EOF or a parsing error. This return value is used by
710 * parseFile to determine if there is more file to parse.
713 static int parseCharMetrics( FileInputStream
* fp
, FontInfo
* fi
)
715 bool cont
= true, firstTime
= true;
716 int error
= ok
, count
= 0, tokenlen
;
717 CharMetricInfo
*temp
= fi
->cmi
;
721 char *keyword
= token(fp
,tokenlen
);
725 break; /* get out of loop */
727 switch(recognize(keyword
,tokenlen
))
730 linetoken(fp
); /*eat token*/
733 if (!(count
< fi
->numOfChars
))
735 reallocFontMetrics( reinterpret_cast<void**>(&fi
->cmi
),
736 &(fi
->numOfChars
), enlargeCount(fi
->numOfChars
),
737 sizeof(CharMetricInfo
) );
738 temp
= &(fi
->cmi
[ count
- 1 ]);
740 if (count
< fi
->numOfChars
)
742 if (firstTime
) firstTime
= false;
744 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
745 temp
->code
= atoi(keyword
);
746 if (fi
->gfi
&& fi
->gfi
->charwidth
)
747 temp
->wx
= fi
->gfi
->charwidth
;
757 if (!(count
< fi
->numOfChars
))
759 reallocFontMetrics( reinterpret_cast<void**>(&fi
->cmi
),
760 &(fi
->numOfChars
), enlargeCount(fi
->numOfChars
),
761 sizeof(CharMetricInfo
) );
762 temp
= &(fi
->cmi
[ count
- 1 ]);
764 if (count
< fi
->numOfChars
) {
769 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
770 sscanf(keyword
,"<%x>", &temp
->code
);
771 if (fi
->gfi
&& fi
->gfi
->charwidth
)
772 temp
->wx
= fi
->gfi
->charwidth
;
781 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
782 temp
->wx
= atoi(keyword
);
783 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
784 temp
->wy
= atoi(keyword
);
787 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
788 temp
->wx
= atoi(keyword
);
791 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
792 temp
->wx
= atoi(keyword
);
795 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
796 temp
->name
= strdup(keyword
);
799 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
800 temp
->charBBox
.llx
= atoi(keyword
);
801 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
802 temp
->charBBox
.lly
= atoi(keyword
);
803 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
804 temp
->charBBox
.urx
= atoi(keyword
);
805 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
806 temp
->charBBox
.ury
= atoi(keyword
);
809 Ligature
**tail
= &(temp
->ligs
);
810 Ligature
*node
= *tail
;
814 while (node
->next
!= NULL
)
816 tail
= &(node
->next
);
819 *tail
= static_cast<Ligature
*>(calloc(1, sizeof(Ligature
)));
820 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
821 (*tail
)->succ
= strdup(keyword
);
822 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
823 (*tail
)->lig
= strdup(keyword
);
833 token(fp
,tokenlen
); /*eat token*/
834 token(fp
,tokenlen
); /*eat token*/
843 if ((error
== ok
) && (count
!= fi
->numOfChars
))
844 error
= reallocFontMetrics( reinterpret_cast<void**>(&fi
->cmi
), &(fi
->numOfChars
),
845 count
, sizeof(CharMetricInfo
) );
847 if ((error
== ok
) && (count
!= fi
->numOfChars
))
852 } /* parseCharMetrics */
854 /************************* parseTrackKernData ***********************/
856 /* This function is called by "parseFile". It will parse the AFM file
857 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
858 * track kerning data if requested by the caller of parseFile.
860 * parseTrackKernData is passed in a pointer to the FontInfo record.
861 * If data is to be saved, the FontInfo record will already contain
862 * a valid pointer to storage for the track kerning data.
864 * This function returns an error code specifying whether there was
865 * a premature EOF or a parsing error. This return value is used by
866 * parseFile to determine if there is more file to parse.
869 static int parseTrackKernData( FileInputStream
* fp
, FontInfo
* fi
)
871 bool cont
= true, save
= (fi
->tkd
!= NULL
);
872 int pos
= 0, error
= ok
, tcount
= 0, tokenlen
;
876 char *keyword
= token(fp
,tokenlen
);
881 break; /* get out of loop */
884 /* get tokens until the end of the Track Kerning Data */
885 /* section without saving any of the data */
886 switch(recognize(keyword
,tokenlen
))
900 /* otherwise parse entire Track Kerning Data section, */
901 /* saving the data */
902 switch(recognize(keyword
,tokenlen
))
905 linetoken(fp
); /*eat token*/
908 if (!(tcount
< fi
->numOfTracks
))
910 reallocFontMetrics( reinterpret_cast<void**>(&fi
->tkd
), &(fi
->numOfTracks
),
911 enlargeCount(fi
->numOfTracks
), sizeof(TrackKernData
) );
914 if (tcount
< fi
->numOfTracks
)
916 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
917 fi
->tkd
[pos
].degree
= atoi(keyword
);
918 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
919 fi
->tkd
[pos
].minPtSize
= StringToDouble(keyword
);
920 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
921 fi
->tkd
[pos
].minKernAmt
= StringToDouble(keyword
);
922 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
923 fi
->tkd
[pos
].maxPtSize
= StringToDouble(keyword
);
924 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
925 fi
->tkd
[pos
++].maxKernAmt
= StringToDouble(keyword
);
949 if (error
== ok
&& tcount
!= fi
->numOfTracks
)
950 error
= reallocFontMetrics( reinterpret_cast<void**>(&fi
->tkd
), &(fi
->numOfTracks
),
951 tcount
, sizeof(TrackKernData
) );
953 if (error
== ok
&& tcount
!= fi
->numOfTracks
)
958 } /* parseTrackKernData */
960 /************************* parsePairKernData ************************/
962 /* This function is called by "parseFile". It will parse the AFM file
963 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
964 * the pair kerning data if requested by the caller of parseFile.
966 * parsePairKernData is passed in a pointer to the FontInfo record.
967 * If data is to be saved, the FontInfo record will already contain
968 * a valid pointer to storage for the pair kerning data.
970 * This function returns an error code specifying whether there was
971 * a premature EOF or a parsing error. This return value is used by
972 * parseFile to determine if there is more file to parse.
975 static int parsePairKernData( FileInputStream
* fp
, FontInfo
* fi
)
977 bool cont
= true, save
= (fi
->pkd
!= NULL
);
978 int pos
= 0, error
= ok
, pcount
= 0, tokenlen
;
982 char *keyword
= token(fp
,tokenlen
);
987 break; /* get out of loop */
990 /* get tokens until the end of the Pair Kerning Data */
991 /* section without saving any of the data */
992 switch(recognize(keyword
,tokenlen
))
1006 /* otherwise parse entire Pair Kerning Data section, */
1007 /* saving the data */
1008 switch(recognize(keyword
,tokenlen
))
1011 linetoken(fp
); /*eat token*/
1014 if (!(pcount
< fi
->numOfPairs
))
1016 reallocFontMetrics( reinterpret_cast<void**>(&fi
->pkd
), &(fi
->numOfPairs
),
1017 enlargeCount(fi
->numOfPairs
), sizeof(PairKernData
) );
1019 if (pcount
< fi
->numOfPairs
)
1021 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1022 fi
->pkd
[pos
].name1
= strdup( keyword
);
1023 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1024 fi
->pkd
[pos
].name2
= strdup( keyword
);
1025 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1026 fi
->pkd
[pos
].xamt
= atoi(keyword
);
1027 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1028 fi
->pkd
[pos
++].yamt
= atoi(keyword
);
1038 if (!(pcount
< fi
->numOfPairs
))
1040 reallocFontMetrics( reinterpret_cast<void**>(&fi
->pkd
), &(fi
->numOfPairs
),
1041 enlargeCount(fi
->numOfPairs
), sizeof(PairKernData
) );
1043 if (pcount
< fi
->numOfPairs
)
1045 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1046 fi
->pkd
[pos
].name1
= strdup( keyword
);
1047 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1048 fi
->pkd
[pos
].name2
= strdup( keyword
);
1049 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1050 fi
->pkd
[pos
++].xamt
= atoi(keyword
);
1063 case ENDFONTMETRICS
:
1074 if ((error
== ok
) && (pcount
!= fi
->numOfPairs
))
1075 error
= reallocFontMetrics( reinterpret_cast<void**>(&fi
->pkd
), &(fi
->numOfPairs
),
1076 pcount
, sizeof(PairKernData
) );
1078 if (error
== ok
&& pcount
!= fi
->numOfPairs
)
1083 } /* parsePairKernData */
1085 /************************* parseCompCharData **************************/
1087 /* This function is called by "parseFile". It will parse the AFM file
1088 * up to the "EndComposites" keyword. It will save the composite
1089 * character data if requested by the caller of parseFile.
1091 * parseCompCharData is passed in a pointer to the FontInfo record, and
1092 * a boolean representing if the data should be saved.
1094 * This function will create the appropriate amount of storage for
1095 * the composite character data and store a pointer to the storage
1096 * in the FontInfo record.
1098 * This function returns an error code specifying whether there was
1099 * a premature EOF or a parsing error. This return value is used by
1100 * parseFile to determine if there is more file to parse.
1103 static int parseCompCharData( FileInputStream
* fp
, FontInfo
* fi
)
1105 bool cont
= true, firstTime
= true, save
= (fi
->ccd
!= NULL
);
1106 int pos
= 0, j
= 0, error
= ok
, ccount
= 0, pcount
= 0, tokenlen
;
1110 char *keyword
= token(fp
,tokenlen
);
1111 if (keyword
== NULL
)
1112 /* Have reached an early and unexpected EOF. */
1113 /* Set flag and stop parsing */
1116 break; /* get out of loop */
1118 if (ccount
> fi
->numOfComps
)
1120 reallocFontMetrics( reinterpret_cast<void**>(&fi
->ccd
), &(fi
->numOfComps
),
1121 enlargeCount(fi
->numOfComps
), sizeof(CompCharData
) );
1123 if (ccount
> fi
->numOfComps
)
1126 break; /* get out of loop */
1129 /* get tokens until the end of the Composite Character info */
1130 /* section without saving any of the data */
1131 switch(recognize(keyword
,tokenlen
))
1136 case ENDFONTMETRICS
:
1148 /* otherwise parse entire Composite Character info section, */
1149 /* saving the data */
1150 switch(recognize(keyword
,tokenlen
))
1153 linetoken(fp
); /*eat token*/
1156 if (!(ccount
< fi
->numOfComps
))
1158 reallocFontMetrics( reinterpret_cast<void**>(&fi
->ccd
), &(fi
->numOfComps
),
1159 enlargeCount(fi
->numOfComps
), sizeof(CompCharData
) );
1161 if (ccount
< fi
->numOfComps
)
1163 keyword
= token(fp
,tokenlen
);
1164 if (pcount
!= fi
->ccd
[pos
].numOfPieces
)
1167 if (firstTime
) firstTime
= false;
1169 fi
->ccd
[pos
].ccName
= strdup( keyword
);
1170 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1171 fi
->ccd
[pos
].numOfPieces
= atoi(keyword
);
1172 fi
->ccd
[pos
].pieces
= static_cast<Pcc
*>(
1173 calloc(fi
->ccd
[pos
].numOfPieces
, sizeof(Pcc
)));
1184 if (pcount
< fi
->ccd
[pos
].numOfPieces
)
1186 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1187 fi
->ccd
[pos
].pieces
[j
].pccName
= strdup( keyword
);
1188 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1189 fi
->ccd
[pos
].pieces
[j
].deltax
= atoi(keyword
);
1190 if ((keyword
= token(fp
,tokenlen
)) != NULL
)
1191 fi
->ccd
[pos
].pieces
[j
++].deltay
= atoi(keyword
);
1200 case ENDFONTMETRICS
:
1211 if (error
== ok
&& ccount
!= fi
->numOfComps
)
1212 reallocFontMetrics( reinterpret_cast<void**>(&fi
->ccd
), &(fi
->numOfComps
),
1213 ccount
, sizeof(CompCharData
) );
1215 if (error
== ok
&& ccount
!= fi
->numOfComps
)
1220 } /* parseCompCharData */
1222 /*************************** 'PUBLIC' FUNCTION ********************/
1224 /*************************** parseFile *****************************/
1226 /* parseFile is the only 'public' procedure available. It is called
1227 * from an application wishing to get information from an AFM file.
1228 * The caller of this function is responsible for locating and opening
1229 * an AFM file and handling all errors associated with that task.
1231 * parseFile expects 3 parameters: a filename pointer, a pointer
1232 * to a (FontInfo *) variable (for which storage will be allocated and
1233 * the data requested filled in), and a mask specifying which
1234 * data from the AFM file should be saved in the FontInfo structure.
1236 * The file will be parsed and the requested data will be stored in
1237 * a record of type FontInfo (refer to ParseAFM.h).
1239 * parseFile returns an error code as defined in parseAFM.h.
1241 * The position of the read/write pointer associated with the file
1242 * pointer upon return of this function is undefined.
1245 int parseFile( const char* pFilename
, FontInfo
** fi
, FLAGS flags
)
1247 FileInputStream
aFile( pFilename
);
1249 int code
= ok
; /* return code from each of the parsing routines */
1250 int error
= ok
; /* used as the return code from this function */
1253 char *keyword
; /* used to store a token */
1255 (*fi
) = static_cast<FontInfo
*>(calloc(1, sizeof(FontInfo
)));
1256 if ((*fi
) == NULL
) { error
= storageProblem
; return error
; }
1260 (*fi
)->gfi
= static_cast<GlobalFontInfo
*>(calloc(1, sizeof(GlobalFontInfo
)));
1261 if ((*fi
)->gfi
== NULL
) { error
= storageProblem
; return error
; }
1264 /* The AFM file begins with Global Font Information. This section */
1265 /* will be parsed whether or not information should be saved. */
1266 code
= parseGlobals(&aFile
, (*fi
)->gfi
);
1268 if (code
< 0) error
= code
;
1270 /* The Global Font Information is followed by the Character Metrics */
1271 /* section. Which procedure is used to parse this section depends on */
1272 /* how much information should be saved. If all of the metrics info */
1273 /* is wanted, parseCharMetrics is called. If only the character widths */
1274 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1275 /* be called in the case that no character data is to be saved, just */
1276 /* to parse through the section. */
1278 if ((code
!= normalEOF
) && (code
!= earlyEOF
))
1280 if ((keyword
= token(&aFile
,tokenlen
)) != NULL
)
1281 (*fi
)->numOfChars
= atoi(keyword
);
1282 if (flags
& (P_M
^ P_W
))
1284 (*fi
)->cmi
= static_cast<CharMetricInfo
*>(
1285 calloc((*fi
)->numOfChars
, sizeof(CharMetricInfo
)));
1286 if ((*fi
)->cmi
== NULL
) { error
= storageProblem
; return error
; }
1287 code
= parseCharMetrics(&aFile
, *fi
);
1293 (*fi
)->cwi
= static_cast<int *>(calloc(256, sizeof(int)));
1294 if ((*fi
)->cwi
== NULL
)
1296 error
= storageProblem
;
1300 /* parse section regardless */
1301 code
= parseCharWidths(&aFile
, (*fi
)->cwi
);
1305 if ((error
!= earlyEOF
) && (code
< 0)) error
= code
;
1307 /* The remaining sections of the AFM are optional. This code will */
1308 /* look at the next keyword in the file to determine what section */
1309 /* is next, and then allocate the appropriate amount of storage */
1310 /* for the data (if the data is to be saved) and call the */
1311 /* appropriate parsing routine to parse the section. */
1313 while ((code
!= normalEOF
) && (code
!= earlyEOF
))
1315 keyword
= token(&aFile
,tokenlen
);
1316 if (keyword
== NULL
)
1317 /* Have reached an early and unexpected EOF. */
1318 /* Set flag and stop parsing */
1321 break; /* get out of loop */
1323 switch(recognize(keyword
,tokenlen
))
1329 case STARTTRACKKERN
:
1330 keyword
= token(&aFile
,tokenlen
);
1331 if ((flags
& P_T
) && keyword
)
1333 (*fi
)->numOfTracks
= atoi(keyword
);
1334 (*fi
)->tkd
= static_cast<TrackKernData
*>(
1335 calloc((*fi
)->numOfTracks
, sizeof(TrackKernData
)));
1336 if ((*fi
)->tkd
== NULL
)
1338 error
= storageProblem
;
1342 code
= parseTrackKernData(&aFile
, *fi
);
1344 case STARTKERNPAIRS
:
1345 keyword
= token(&aFile
,tokenlen
);
1346 if ((flags
& P_P
) && keyword
)
1348 (*fi
)->numOfPairs
= atoi(keyword
);
1349 (*fi
)->pkd
= static_cast<PairKernData
*>(
1350 calloc((*fi
)->numOfPairs
, sizeof(PairKernData
)));
1351 if ((*fi
)->pkd
== NULL
)
1353 error
= storageProblem
;
1357 code
= parsePairKernData(&aFile
, *fi
);
1359 case STARTCOMPOSITES
:
1360 keyword
= token(&aFile
,tokenlen
);
1361 if ((flags
& P_C
) && keyword
)
1363 (*fi
)->numOfComps
= atoi(keyword
);
1364 (*fi
)->ccd
= static_cast<CompCharData
*>(
1365 calloc((*fi
)->numOfComps
, sizeof(CompCharData
)));
1366 if ((*fi
)->ccd
== NULL
)
1368 error
= storageProblem
;
1372 code
= parseCompCharData(&aFile
, *fi
);
1374 case ENDFONTMETRICS
:
1386 if ((error
!= earlyEOF
) && (code
< 0)) error
= code
;
1390 if ((error
!= earlyEOF
) && (code
< 0)) error
= code
;
1397 freeFontInfo (FontInfo
*fi
)
1403 free (fi
->gfi
->afmVersion
);
1404 free (fi
->gfi
->fontName
);
1405 free (fi
->gfi
->fullName
);
1406 free (fi
->gfi
->familyName
);
1407 free (fi
->gfi
->weight
);
1408 free (fi
->gfi
->version
);
1409 free (fi
->gfi
->notice
);
1410 free (fi
->gfi
->encodingScheme
);
1418 for (i
= 0; i
< fi
->numOfChars
; i
++)
1421 free (fi
->cmi
[i
].name
);
1422 ligs
= fi
->cmi
[i
].ligs
;
1440 for ( i
= 0; i
< fi
->numOfPairs
; i
++)
1442 free (fi
->pkd
[i
].name1
);
1443 free (fi
->pkd
[i
].name2
);
1450 for (i
= 0; i
< fi
->numOfComps
; i
++)
1452 free (fi
->ccd
[i
].ccName
);
1454 for (j
= 0; j
< fi
->ccd
[i
].numOfPieces
; j
++)
1455 free (fi
->ccd
[i
].pieces
[j
].pccName
);
1457 free (fi
->ccd
[i
].pieces
);
1467 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */