3 1. FontInfo has become AFM_AFM_Font_info to avoid namespace collisions.
4 2. Version is a linetoken because Bitstream Charter has a space in the version.
5 3. Added some necessary #include headers.
6 4. Added AFM_ prefixes to error codes.
7 5. Made it recognize both '\n' and '\r' as line terminators. Sheesh!
8 6. Stopped buffer overflows in token and linetoken.
10 Raph Levien <raph@acm.org> writing on 4 Oct 1998, updating 21 Oct 1998
13 1. parseFileFree function.
14 2. Leak fix in parseFile.
16 Morten Welinder <terra@diku.dk> September 1999.
21 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
23 * This file may be freely copied and redistributed as long as:
24 * 1) This entire notice continues to be included in the file,
25 * 2) If the file has been modified in any way, a notice of such
26 * modification is conspicuously indicated.
28 * PostScript, Display PostScript, and Adobe are registered trademarks of
29 * Adobe Systems Incorporated.
31 * ************************************************************************
32 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
33 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
34 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
35 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
36 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
37 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
39 * ************************************************************************
44 * This file is used in conjuction with the parseAFM.h header file.
45 * This file contains several procedures that are used to parse AFM
46 * files. It is intended to work with an application program that needs
47 * font metric information. The program can be used as is by making a
48 * procedure call to "parseFile" (passing in the expected parameters)
49 * and having it fill in a data structure with the data from the
50 * AFM file, or an application developer may wish to customize this
53 * There is also a file, parseAFMclient.c, that is a sample application
54 * showing how to call the "parseFile" procedure and how to use the data
55 * after "parseFile" has returned.
57 * Please read the comments in parseAFM.h and parseAFMclient.c.
60 * original: DSM Thu Oct 20 17:39:59 PDT 1988
61 * modified: DSM Mon Jul 3 14:17:50 PDT 1989
62 * - added 'storageProblem' return code
63 * - fixed bug of not allocating extra byte for string duplication
65 * modified: DSM Tue Apr 3 11:18:34 PDT 1990
66 * - added free (ident) at end of parseFile routine
67 * modified: DSM Tue Jun 19 10:16:29 PDT 1990
68 * - changed (width == 250) to (width = 250) in initializeArray
77 #include "parse-afm.hh"
79 #define lineterm EOL /* line terminating character */
80 #define lineterm_alt '\r' /* alternative line terminating character */
81 #define normalEOF 1 /* return code from parsing routines used only */
83 #define Space "space" /* used in string comparison to look for the width */
84 /* of the space character to init the widths array */
85 #define False "false" /* used in string comparison to check the value of */
86 /* boolean keys (e.g. IsFixedPitch) */
88 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
92 /*************************** GLOBALS ***********************/
94 static char *ident
= NULL
; /* storage buffer for keywords */
97 /* "shorts" for fast case statement
98 * The values of each of these enumerated items correspond to an entry in the
99 * table of strings defined below. Therefore, if you add a new string as
100 * new keyword into the keyStrings table, you must also add a corresponding
101 * parseKey AND it MUST be in the same position!
103 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
104 * keywords must be placed in lexicographical order, below. [Therefore, the
105 * enumerated items are not necessarily in lexicographical order, depending
106 * on the name chosen. BUT, they must be placed in the same position as the
107 * corresponding key string.] The NOPE shall remain in the last position,
108 * since it does not correspond to any key string, and it is used in the
109 * "recognize" procedure to calculate how many possible keys there are.
113 ASCENDER
, CHARBBOX
, CODE
, COMPCHAR
, CAPHEIGHT
, COMMENT
,
114 DESCENDER
, ENCODINGSCHEME
, ENDCHARMETRICS
, ENDCOMPOSITES
,
115 ENDFONTMETRICS
, ENDKERNDATA
, ENDKERNPAIRS
, ENDTRACKKERN
,
116 FAMILYNAME
, FONTBBOX
, FONTNAME
, FULLNAME
, ISFIXEDPITCH
,
117 ITALICANGLE
, KERNPAIR
, KERNPAIRXAMT
, LIGATURE
, CHARNAME
,
118 NOTICE
, COMPCHARPIECE
, STARTCHARMETRICS
, STARTCOMPOSITES
,
119 STARTFONTMETRICS
, STARTKERNDATA
, STARTKERNPAIRS
,
120 STARTTRACKKERN
, TRACKKERN
, UNDERLINEPOSITION
,
121 UNDERLINETHICKNESS
, VERSION
, XYWIDTH
, XWIDTH
, WEIGHT
, XHEIGHT
,
124 /* keywords for the system:
125 * This a table of all of the current strings that are vaild AFM keys.
126 * Each entry can be referenced by the appropriate parseKey value (an
127 * enumerated data type defined above). If you add a new keyword here,
128 * a corresponding parseKey MUST be added to the enumerated data type
129 * defined above, AND it MUST be added in the same position as the
130 * string is in this table.
132 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
133 * must be placed in lexicographical order. And, NULL should remain at the
137 static char *keyStrings
[] = {
138 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
139 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
140 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
141 "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
142 "ItalicAngle", "KP", "KPX", "L", "N",
143 "Notice", "PCC", "StartCharMetrics", "StartComposites",
144 "StartFontMetrics", "StartKernData", "StartKernPairs",
145 "StartTrackKern", "TrackKern", "UnderlinePosition",
146 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
149 /*************************** PARSING ROUTINES **************/
151 /*************************** token *************************/
153 /* A "AFM File Conventions" tokenizer. That means that it will
154 * return the next token delimited by white space. See also
155 * the `linetoken' routine, which does a similar thing but
156 * reads all tokens until the next end-of-line.
159 static char *token (FILE *stream
)
163 /* skip over white space */
164 while ((ch
= fgetc (stream
)) == ' ' || ch
== lineterm
||
165 ch
== lineterm_alt
||
166 ch
== ',' || ch
== '\t' || ch
== ';');
169 while (idx
< MAX_NAME
- 1 &&
170 ch
!= EOF
&& ch
!= ' ' && ch
!= lineterm
&& ch
!= lineterm_alt
171 && ch
!= '\t' && ch
!= ':' && ch
!= ';')
177 if (ch
== EOF
&& idx
< 1) return ((char *)NULL
);
178 if (idx
>= 1 && ch
!= ':' ) ungetc (ch
, stream
);
179 if (idx
< 1 ) ident
[idx
++] = ch
; /* single-character token */
182 return (ident
); /* returns pointer to the token */
187 /*************************** linetoken *************************/
189 /* "linetoken" will get read all tokens until the EOL character from
190 * the given stream. This is used to get any arguments that can be
191 * more than one word (like Comment lines and FullName).
194 static char *linetoken (FILE *stream
)
198 while ((ch
= fgetc (stream
)) == ' ' || ch
== '\t' );
201 while (idx
< MAX_NAME
- 1 &&
202 ch
!= EOF
&& ch
!= lineterm
&& ch
!= lineterm_alt
)
211 return (ident
); /* returns pointer to the token */
216 /*************************** recognize *************************/
218 /* This function tries to match a string to a known list of
219 * valid AFM entries (check the keyStrings array above).
220 * "ident" contains everything from white space through the
221 * next space, tab, or ":" character.
223 * The algorithm is a standard Knuth binary search.
226 static enum parseKey
recognize ( register char *ident
)
228 int lower
= 0, upper
= (int) NOPE
, midpoint
, cmpvalue
;
231 while ((upper
>= lower
) && !found
)
233 midpoint
= (lower
+ upper
)/2;
234 if (keyStrings
[midpoint
] == NULL
) break;
235 cmpvalue
= strncmp (ident
, keyStrings
[midpoint
], MAX_NAME
);
236 if (cmpvalue
== 0) found
= TRUE
;
237 else if (cmpvalue
< 0) upper
= midpoint
- 1;
238 else lower
= midpoint
+ 1;
241 if (found
) return (enum parseKey
) midpoint
;
247 /************************* parseGlobals *****************************/
249 /* This function is called by "parseFile". It will parse the AFM File
250 * up to the "StartCharMetrics" keyword, which essentially marks the
251 * end of the Global Font Information and the beginning of the character
252 * metrics information.
254 * If the caller of "parseFile" specified that it wanted the Global
255 * Font Information (as defined by the "AFM File Specification"
256 * document), then that information will be stored in the returned
259 * Any Global Font Information entries that are not found in a
260 * given file, will have the usual default initialization value
261 * for its type (i.e. entries of type int will be 0, etc).
263 * This function returns an error code specifying whether there was
264 * a premature EOF or a parsing error. This return value is used by
265 * parseFile to determine if there is more file to parse.
268 static BOOL
parseGlobals (FILE *fp
, register AFM_GlobalFontInfo
*gfi
)
270 BOOL cont
= TRUE
, save
= (gfi
!= NULL
);
272 register char *keyword
;
276 keyword
= token (fp
);
279 /* Have reached an early and unexpected EOF. */
280 /* Set flag and stop parsing */
282 error
= AFM_earlyEOF
;
283 break; /* get out of loop */
286 /* get tokens until the end of the Global Font info section */
287 /* without saving any of the data */
288 switch (recognize (keyword
))
290 case STARTCHARMETRICS
:
301 /* otherwise parse entire global font info section, */
302 /* saving the data */
303 switch (recognize (keyword
))
305 case STARTFONTMETRICS
:
306 keyword
= token (fp
);
307 gfi
->afmVersion
= (char *) malloc (strlen (keyword
) + 1);
308 strcpy (gfi
->afmVersion
, keyword
);
311 keyword
= linetoken (fp
);
314 keyword
= token (fp
);
315 gfi
->fontName
= (char *) malloc (strlen (keyword
) + 1);
316 strcpy (gfi
->fontName
, keyword
);
319 keyword
= token (fp
);
320 gfi
->encodingScheme
= (char *)
321 malloc (strlen (keyword
) + 1);
322 strcpy (gfi
->encodingScheme
, keyword
);
325 keyword
= linetoken (fp
);
326 gfi
->fullName
= (char *) malloc (strlen (keyword
) + 1);
327 strcpy (gfi
->fullName
, keyword
);
330 keyword
= linetoken (fp
);
331 gfi
->familyName
= (char *) malloc (strlen (keyword
) + 1);
332 strcpy (gfi
->familyName
, keyword
);
335 keyword
= token (fp
);
336 gfi
->weight
= (char *) malloc (strlen (keyword
) + 1);
337 strcpy (gfi
->weight
, keyword
);
340 keyword
= token (fp
);
341 gfi
->italicAngle
= atof (keyword
);
342 if (errno
== ERANGE
) error
= AFM_parseError
;
345 keyword
= token (fp
);
346 if (MATCH (keyword
, False
))
347 gfi
->isFixedPitch
= 0;
349 gfi
->isFixedPitch
= 1;
351 case UNDERLINEPOSITION
:
352 keyword
= token (fp
);
353 gfi
->underlinePosition
= atoi (keyword
);
355 case UNDERLINETHICKNESS
:
356 keyword
= token (fp
);
357 gfi
->underlineThickness
= atoi (keyword
);
360 keyword
= linetoken (fp
);
361 gfi
->version
= (char *) malloc (strlen (keyword
) + 1);
362 strcpy (gfi
->version
, keyword
);
365 keyword
= linetoken (fp
);
366 gfi
->notice
= (char *) malloc (strlen (keyword
) + 1);
367 strcpy (gfi
->notice
, keyword
);
370 keyword
= token (fp
);
371 gfi
->fontBBox
.llx
= atoi (keyword
);
372 keyword
= token (fp
);
373 gfi
->fontBBox
.lly
= atoi (keyword
);
374 keyword
= token (fp
);
375 gfi
->fontBBox
.urx
= atoi (keyword
);
376 keyword
= token (fp
);
377 gfi
->fontBBox
.ury
= atoi (keyword
);
380 keyword
= token (fp
);
381 gfi
->capHeight
= atoi (keyword
);
384 keyword
= token (fp
);
385 gfi
->xHeight
= atoi (keyword
);
388 keyword
= token (fp
);
389 gfi
->descender
= atoi (keyword
);
392 keyword
= token (fp
);
393 gfi
->ascender
= atoi (keyword
);
395 case STARTCHARMETRICS
:
404 error
= AFM_parseError
;
415 /************************* initializeArray ************************/
417 /* Unmapped character codes are (at Adobe Systems) assigned the
418 * width of the space character (if one exists) else they get the
419 * value of 250 ems. This function initializes all entries in the
420 * char widths array to have this value. Then any mapped character
421 * codes will be replaced with the width of the appropriate character
422 * when parsing the character metric section.
424 * This function parses the Character Metrics Section looking
425 * for a space character (by comparing character names). If found,
426 * the width of the space character will be used to initialize the
427 * values in the array of character widths.
429 * Before returning, the position of the read/write pointer of the
430 * file is reset to be where it was upon entering this function.
433 static int initializeArray (FILE *fp
, register int *cwi
)
435 BOOL cont
= TRUE
, found
= FALSE
;
436 long opos
= ftell (fp
);
437 int code
= 0, width
= 0, i
= 0, error
= 0;
438 register char *keyword
;
442 keyword
= token (fp
);
445 error
= AFM_earlyEOF
;
446 break; /* get out of loop */
448 switch (recognize (keyword
))
451 keyword
= linetoken (fp
);
454 code
= atoi (token (fp
));
457 width
= atoi (token (fp
));
460 keyword
= token (fp
);
461 if (MATCH (keyword
, Space
))
476 error
= AFM_parseError
;
484 for (i
= 0; i
< 256; ++i
)
491 } /* initializeArray */
494 /************************* parseCharWidths **************************/
496 /* This function is called by "parseFile". It will parse the AFM File
497 * up to the "EndCharMetrics" keyword. It will save the character
498 * width info (as opposed to all of the character metric information)
499 * if requested by the caller of parseFile. Otherwise, it will just
500 * parse through the section without saving any information.
502 * If data is to be saved, parseCharWidths is passed in a pointer
503 * to an array of widths that has already been initialized by the
504 * standard value for unmapped character codes. This function parses
505 * the Character Metrics section only storing the width information
506 * for the encoded characters into the array using the character code
507 * as the index into that array.
509 * This function returns an error code specifying whether there was
510 * a premature EOF or a parsing error. This return value is used by
511 * parseFile to determine if there is more file to parse.
514 static int parseCharWidths (FILE *fp
, register int *cwi
)
516 BOOL cont
= TRUE
, save
= (cwi
!= NULL
);
517 int pos
= 0, error
= AFM_ok
;
518 register char *keyword
;
522 keyword
= token (fp
);
523 /* Have reached an early and unexpected EOF. */
524 /* Set flag and stop parsing */
527 error
= AFM_earlyEOF
;
528 break; /* get out of loop */
531 /* get tokens until the end of the Char Metrics section without */
532 /* saving any of the data*/
533 switch (recognize (keyword
))
546 /* otherwise parse entire char metrics section, saving */
547 /* only the char x-width info */
548 switch (recognize (keyword
))
551 keyword
= linetoken (fp
);
554 keyword
= token (fp
);
555 pos
= atoi (keyword
);
558 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
559 keyword
= token (fp
); keyword
= token (fp
); /* eat values */
560 error
= AFM_parseError
;
563 keyword
= token (fp
);
564 if (pos
>= 0) /* ignore unmapped chars */
565 cwi
[pos
] = atoi (keyword
);
574 case CHARNAME
: /* eat values (so doesn't cause AFM_parseError) */
575 keyword
= token (fp
);
578 keyword
= token (fp
); keyword
= token (fp
);
579 keyword
= token (fp
); keyword
= token (fp
);
582 keyword
= token (fp
); keyword
= token (fp
);
586 error
= AFM_parseError
;
593 } /* parseCharWidths */
596 /************************* parseCharMetrics ************************/
598 /* This function is called by parseFile if the caller of parseFile
599 * requested that all character metric information be saved
600 * (as opposed to only the character width information).
602 * parseCharMetrics is passed in a pointer to an array of records
603 * to hold information on a per character basis. This function
604 * parses the Character Metrics section storing all character
605 * metric information for the ALL characters (mapped and unmapped)
608 * This function returns an error code specifying whether there was
609 * a premature EOF or a parsing error. This return value is used by
610 * parseFile to determine if there is more file to parse.
613 static int parseCharMetrics (FILE *fp
, register AFM_Font_info
*fi
)
615 BOOL cont
= TRUE
, firstTime
= TRUE
;
616 int error
= AFM_ok
, count
= 0;
617 register AFM_CharMetricInfo
*temp
= fi
->cmi
;
618 register char *keyword
;
622 keyword
= token (fp
);
625 error
= AFM_earlyEOF
;
626 break; /* get out of loop */
628 switch (recognize (keyword
))
631 keyword
= linetoken (fp
);
634 if (count
< fi
->numOfChars
)
636 if (firstTime
) firstTime
= FALSE
;
638 temp
->code
= atoi (token (fp
));
643 error
= AFM_parseError
;
648 temp
->wx
= atoi (token (fp
));
649 temp
->wy
= atoi (token (fp
));
652 temp
->wx
= atoi (token (fp
));
655 keyword
= token (fp
);
656 temp
->name
= (char *) malloc (strlen (keyword
) + 1);
657 strcpy (temp
->name
, keyword
);
660 temp
->charBBox
.llx
= atoi (token (fp
));
661 temp
->charBBox
.lly
= atoi (token (fp
));
662 temp
->charBBox
.urx
= atoi (token (fp
));
663 temp
->charBBox
.ury
= atoi (token (fp
));
666 AFM_Ligature
**tail
= & (temp
->ligs
);
667 AFM_Ligature
*node
= *tail
;
671 while (node
->next
!= NULL
)
673 tail
= & (node
->next
);
676 *tail
= (AFM_Ligature
*) calloc (1, sizeof (AFM_Ligature
));
677 keyword
= token (fp
);
678 (*tail
)->succ
= (char *) malloc (strlen (keyword
) + 1);
679 strcpy ((*tail
)->succ
, keyword
);
680 keyword
= token (fp
);
681 (*tail
)->lig
= (char *) malloc (strlen (keyword
) + 1);
682 strcpy ((*tail
)->lig
, keyword
);
693 error
= AFM_parseError
;
698 if ((error
== AFM_ok
) && (count
!= fi
->numOfChars
))
699 error
= AFM_parseError
;
703 } /* parseCharMetrics */
707 /************************* parseAFM_TrackKernData ***********************/
709 /* This function is called by "parseFile". It will parse the AFM File
710 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
711 * track kerning data if requested by the caller of parseFile.
713 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
714 * If data is to be saved, the FontInfo record will already contain
715 * a valid pointer to storage for the track kerning data.
717 * This function returns an error code specifying whether there was
718 * a premature EOF or a parsing error. This return value is used by
719 * parseFile to determine if there is more file to parse.
722 static int parseAFM_TrackKernData (FILE *fp
, register AFM_Font_info
*fi
)
724 BOOL cont
= TRUE
, save
= (fi
->tkd
!= NULL
);
725 int pos
= 0, error
= AFM_ok
, tcount
= 0;
726 register char *keyword
;
730 keyword
= token (fp
);
734 error
= AFM_earlyEOF
;
735 break; /* get out of loop */
738 /* get tokens until the end of the Track Kerning Data */
739 /* section without saving any of the data */
740 switch (recognize (keyword
))
754 /* otherwise parse entire Track Kerning Data section, */
755 /* saving the data */
756 switch (recognize (keyword
))
759 keyword
= linetoken (fp
);
762 if (tcount
< fi
->numOfTracks
)
764 keyword
= token (fp
);
765 fi
->tkd
[pos
].degree
= atoi (keyword
);
766 keyword
= token (fp
);
767 fi
->tkd
[pos
].minPtSize
= atof (keyword
);
768 if (errno
== ERANGE
) error
= AFM_parseError
;
769 keyword
= token (fp
);
770 fi
->tkd
[pos
].minKernAmt
= atof (keyword
);
771 if (errno
== ERANGE
) error
= AFM_parseError
;
772 keyword
= token (fp
);
773 fi
->tkd
[pos
].maxPtSize
= atof (keyword
);
774 if (errno
== ERANGE
) error
= AFM_parseError
;
775 keyword
= token (fp
);
776 fi
->tkd
[pos
++].maxKernAmt
= atof (keyword
);
777 if (errno
== ERANGE
) error
= AFM_parseError
;
782 error
= AFM_parseError
;
796 error
= AFM_parseError
;
801 if (error
== AFM_ok
&& tcount
!= fi
->numOfTracks
)
802 error
= AFM_parseError
;
806 } /* parseAFM_TrackKernData */
809 /************************* parseAFM_PairKernData ************************/
811 /* This function is called by "parseFile". It will parse the AFM File
812 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
813 * the pair kerning data if requested by the caller of parseFile.
815 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
816 * If data is to be saved, the FontInfo record will already contain
817 * a valid pointer to storage for the pair kerning data.
819 * This function returns an error code specifying whether there was
820 * a premature EOF or a parsing error. This return value is used by
821 * parseFile to determine if there is more file to parse.
824 static int parseAFM_PairKernData (FILE *fp
, register AFM_Font_info
*fi
)
826 BOOL cont
= TRUE
, save
= (fi
->pkd
!= NULL
);
827 int pos
= 0, error
= AFM_ok
, pcount
= 0;
828 register char *keyword
;
832 keyword
= token (fp
);
836 error
= AFM_earlyEOF
;
837 break; /* get out of loop */
840 /* get tokens until the end of the Pair Kerning Data */
841 /* section without saving any of the data */
842 switch (recognize (keyword
))
856 /* otherwise parse entire Pair Kerning Data section, */
857 /* saving the data */
858 switch (recognize (keyword
))
861 keyword
= linetoken (fp
);
864 if (pcount
< fi
->numOfPairs
)
866 keyword
= token (fp
);
867 fi
->pkd
[pos
].name1
= (char *)
868 malloc (strlen (keyword
) + 1);
869 strcpy (fi
->pkd
[pos
].name1
, keyword
);
870 keyword
= token (fp
);
871 fi
->pkd
[pos
].name2
= (char *)
872 malloc (strlen (keyword
) + 1);
873 strcpy (fi
->pkd
[pos
].name2
, keyword
);
874 keyword
= token (fp
);
875 fi
->pkd
[pos
].xamt
= atoi (keyword
);
876 keyword
= token (fp
);
877 fi
->pkd
[pos
++].yamt
= atoi (keyword
);
882 error
= AFM_parseError
;
887 if (pcount
< fi
->numOfPairs
)
889 keyword
= token (fp
);
890 fi
->pkd
[pos
].name1
= (char *)
891 malloc (strlen (keyword
) + 1);
892 strcpy (fi
->pkd
[pos
].name1
, keyword
);
893 keyword
= token (fp
);
894 fi
->pkd
[pos
].name2
= (char *)
895 malloc (strlen (keyword
) + 1);
896 strcpy (fi
->pkd
[pos
].name2
, keyword
);
897 keyword
= token (fp
);
898 fi
->pkd
[pos
++].xamt
= atoi (keyword
);
903 error
= AFM_parseError
;
917 error
= AFM_parseError
;
922 if (error
== AFM_ok
&& pcount
!= fi
->numOfPairs
)
923 error
= AFM_parseError
;
927 } /* parseAFM_PairKernData */
930 /************************* parseAFM_CompCharData **************************/
932 /* This function is called by "parseFile". It will parse the AFM File
933 * up to the "EndComposites" keyword. It will save the composite
934 * character data if requested by the caller of parseFile.
936 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
937 * a boolean representing if the data should be saved.
939 * This function will create the appropriate amount of storage for
940 * the composite character data and store a pointer to the storage
941 * in the FontInfo record.
943 * This function returns an error code specifying whether there was
944 * a premature EOF or a parsing error. This return value is used by
945 * parseFile to determine if there is more file to parse.
948 static int parseAFM_CompCharData (FILE *fp
, register AFM_Font_info
*fi
)
950 BOOL cont
= TRUE
, firstTime
= TRUE
, save
= (fi
->ccd
!= NULL
);
951 int pos
= 0, j
= 0, error
= AFM_ok
, ccount
= 0, pcount
= 0;
952 register char *keyword
;
956 keyword
= token (fp
);
958 /* Have reached an early and unexpected EOF. */
959 /* Set flag and stop parsing */
961 error
= AFM_earlyEOF
;
962 break; /* get out of loop */
964 if (ccount
> fi
->numOfComps
)
966 error
= AFM_parseError
;
967 break; /* get out of loop */
970 /* get tokens until the end of the Composite Character info */
971 /* section without saving any of the data */
972 switch (recognize (keyword
))
985 /* otherwise parse entire Composite Character info section, */
986 /* saving the data */
987 switch (recognize (keyword
))
990 keyword
= linetoken (fp
);
993 if (ccount
< fi
->numOfComps
)
995 keyword
= token (fp
);
996 if (pcount
!= fi
->ccd
[pos
].numOfPieces
)
997 error
= AFM_parseError
;
999 if (firstTime
) firstTime
= FALSE
;
1001 fi
->ccd
[pos
].ccName
= (char *)
1002 malloc (strlen (keyword
) + 1);
1003 strcpy (fi
->ccd
[pos
].ccName
, keyword
);
1004 keyword
= token (fp
);
1005 fi
->ccd
[pos
].numOfPieces
= atoi (keyword
);
1006 fi
->ccd
[pos
].pieces
= (AFM_Pcc
*)
1007 calloc (fi
->ccd
[pos
].numOfPieces
, sizeof (AFM_Pcc
));
1013 error
= AFM_parseError
;
1018 if (pcount
< fi
->ccd
[pos
].numOfPieces
)
1020 keyword
= token (fp
);
1021 fi
->ccd
[pos
].pieces
[j
].AFM_PccName
= (char *)
1022 malloc (strlen (keyword
) + 1);
1023 strcpy (fi
->ccd
[pos
].pieces
[j
].AFM_PccName
, keyword
);
1024 keyword
= token (fp
);
1025 fi
->ccd
[pos
].pieces
[j
].deltax
= atoi (keyword
);
1026 keyword
= token (fp
);
1027 fi
->ccd
[pos
].pieces
[j
++].deltay
= atoi (keyword
);
1031 error
= AFM_parseError
;
1036 case ENDFONTMETRICS
:
1042 error
= AFM_parseError
;
1047 if (error
== AFM_ok
&& ccount
!= fi
->numOfComps
)
1048 error
= AFM_parseError
;
1052 } /* parseAFM_CompCharData */
1057 /*************************** 'PUBLIC' FUNCTION ********************/
1060 /*************************** parseFile *****************************/
1062 /* parseFile is the only 'public' procedure available. It is called
1063 * from an application wishing to get information from an AFM file.
1064 * The caller of this function is responsible for locating and opening
1065 * an AFM file and handling all errors associated with that task.
1067 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1068 * to a (FontInfo *) variable (for which storage will be allocated and
1069 * the data requested filled in), and a mask specifying which
1070 * data from the AFM File should be saved in the FontInfo structure.
1072 * The file will be parsed and the requested data will be stored in
1073 * a record of type FontInfo (refer to ParseAFM.h).
1075 * parseFile returns an error code as defined in parseAFM.h.
1077 * The position of the read/write pointer associated with the file
1078 * pointer upon return of this function is undefined.
1081 extern int AFM_parseFile (FILE *fp
, AFM_Font_info
**fi
, int flags
)
1084 int code
= AFM_ok
; /* return code from each of the parsing routines */
1085 int error
= AFM_ok
; /* used as the return code from this function */
1087 register char *keyword
; /* used to store a token */
1090 /* storage data for the global variable ident */
1092 ident
= (char *) calloc (MAX_NAME
, sizeof (char));
1093 if (ident
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1095 (*fi
) = (AFM_Font_info
*) calloc (1, sizeof (AFM_Font_info
));
1096 if ((*fi
) == NULL
) {error
= AFM_storageProblem
; return (error
);}
1100 (*fi
)->gfi
= (AFM_GlobalFontInfo
*) calloc (1, sizeof (AFM_GlobalFontInfo
));
1101 if ((*fi
)->gfi
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1104 /* The AFM File begins with Global Font Information. This section */
1105 /* will be parsed whether or not information should be saved. */
1106 code
= parseGlobals (fp
, (*fi
)->gfi
);
1108 if (code
< 0) error
= code
;
1110 /* The Global Font Information is followed by the Character Metrics */
1111 /* section. Which procedure is used to parse this section depends on */
1112 /* how much information should be saved. If all of the metrics info */
1113 /* is wanted, parseCharMetrics is called. If only the character widths */
1114 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1115 /* be called in the case that no character data is to be saved, just */
1116 /* to parse through the section. */
1118 if ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1120 (*fi
)->numOfChars
= atoi (token (fp
));
1121 if (flags
& (P_M
^ P_W
))
1123 (*fi
)->cmi
= (AFM_CharMetricInfo
*)
1124 calloc ((*fi
)->numOfChars
, sizeof (AFM_CharMetricInfo
));
1125 if ((*fi
)->cmi
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1126 code
= parseCharMetrics (fp
, *fi
);
1132 (*fi
)->cwi
= (int *) calloc (256, sizeof (int));
1133 if ((*fi
)->cwi
== NULL
)
1135 error
= AFM_storageProblem
;
1139 /* parse section regardless */
1140 code
= parseCharWidths (fp
, (*fi
)->cwi
);
1144 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1146 /* The remaining sections of the AFM are optional. This code will */
1147 /* look at the next keyword in the file to determine what section */
1148 /* is next, and then allocate the appropriate amount of storage */
1149 /* for the data (if the data is to be saved) and call the */
1150 /* appropriate parsing routine to parse the section. */
1152 while ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1154 keyword
= token (fp
);
1155 if (keyword
== NULL
)
1156 /* Have reached an early and unexpected EOF. */
1157 /* Set flag and stop parsing */
1159 code
= AFM_earlyEOF
;
1160 break; /* get out of loop */
1162 switch (recognize (keyword
))
1168 case STARTTRACKKERN
:
1169 keyword
= token (fp
);
1172 (*fi
)->numOfTracks
= atoi (keyword
);
1173 (*fi
)->tkd
= (AFM_TrackKernData
*)
1174 calloc ((*fi
)->numOfTracks
, sizeof (AFM_TrackKernData
));
1175 if ((*fi
)->tkd
== NULL
)
1177 error
= AFM_storageProblem
;
1181 code
= parseAFM_TrackKernData (fp
, *fi
);
1183 case STARTKERNPAIRS
:
1184 keyword
= token (fp
);
1187 (*fi
)->numOfPairs
= atoi (keyword
);
1188 (*fi
)->pkd
= (AFM_PairKernData
*)
1189 calloc ((*fi
)->numOfPairs
, sizeof (AFM_PairKernData
));
1190 if ((*fi
)->pkd
== NULL
)
1192 error
= AFM_storageProblem
;
1196 code
= parseAFM_PairKernData (fp
, *fi
);
1198 case STARTCOMPOSITES
:
1199 keyword
= token (fp
);
1202 (*fi
)->numOfComps
= atoi (keyword
);
1203 (*fi
)->ccd
= (AFM_CompCharData
*)
1204 calloc ((*fi
)->numOfComps
, sizeof (AFM_CompCharData
));
1205 if ((*fi
)->ccd
== NULL
)
1207 error
= AFM_storageProblem
;
1211 code
= parseAFM_CompCharData (fp
, *fi
);
1213 case ENDFONTMETRICS
:
1218 code
= AFM_parseError
;
1222 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1226 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1228 if (ident
!= NULL
) { free (ident
); ident
= NULL
; }
1236 AFM_free (AFM_Font_info
*fi
)
1239 free (fi
->gfi
->afmVersion
);
1240 free (fi
->gfi
->fontName
);
1241 free (fi
->gfi
->fullName
);
1242 free (fi
->gfi
->familyName
);
1243 free (fi
->gfi
->weight
);
1244 free (fi
->gfi
->version
);
1245 free (fi
->gfi
->notice
);
1246 free (fi
->gfi
->encodingScheme
);
1250 /* This contains just scalars. */
1255 for (i
= 0; i
< fi
->numOfChars
; i
++) {
1256 free (fi
->cmi
[i
].name
);
1257 while (fi
->cmi
[i
].ligs
) {
1259 tmp
= fi
->cmi
[i
].ligs
;
1263 fi
->cmi
[i
].ligs
= fi
->cmi
[i
].ligs
->next
;
1269 /* This contains just scalars. */
1274 for (i
= 0; i
< fi
->numOfPairs
; i
++) {
1275 free (fi
->pkd
[i
].name1
);
1276 free (fi
->pkd
[i
].name2
);
1283 for (i
= 0; i
< fi
->numOfComps
; i
++) {
1284 free (fi
->ccd
[i
].ccName
);
1285 for (j
= 0; j
< fi
->ccd
[i
].numOfPieces
; j
++) {
1286 free (fi
->ccd
[i
].pieces
[j
].AFM_PccName
);
1288 free (fi
->ccd
[i
].pieces
);