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
)
234 while ((upper
>= lower
) && !found
)
236 midpoint
= (lower
+ upper
)/2;
237 if (keyStrings
[midpoint
] == NULL
) break;
238 cmpvalue
= strncmp (ident
, keyStrings
[midpoint
], MAX_NAME
);
239 if (cmpvalue
== 0) found
= TRUE
;
240 else if (cmpvalue
< 0) upper
= midpoint
- 1;
241 else lower
= midpoint
+ 1;
244 if (found
) return (enum parseKey
) midpoint
;
250 /************************* parseGlobals *****************************/
252 /* This function is called by "parseFile". It will parse the AFM File
253 * up to the "StartCharMetrics" keyword, which essentially marks the
254 * end of the Global Font Information and the beginning of the character
255 * metrics information.
257 * If the caller of "parseFile" specified that it wanted the Global
258 * Font Information (as defined by the "AFM File Specification"
259 * document), then that information will be stored in the returned
262 * Any Global Font Information entries that are not found in a
263 * given file, will have the usual default initialization value
264 * for its type (i.e. entries of type int will be 0, etc).
266 * This function returns an error code specifying whether there was
267 * a premature EOF or a parsing error. This return value is used by
268 * parseFile to determine if there is more file to parse.
271 static BOOL
parseGlobals (FILE *fp
, register AFM_GlobalFontInfo
*gfi
)
273 BOOL cont
= TRUE
, save
= (gfi
!= NULL
);
275 register char *keyword
;
279 keyword
= token (fp
);
282 /* Have reached an early and unexpected EOF. */
283 /* Set flag and stop parsing */
285 error
= AFM_earlyEOF
;
286 break; /* get out of loop */
289 /* get tokens until the end of the Global Font info section */
290 /* without saving any of the data */
291 switch (recognize (keyword
))
293 case STARTCHARMETRICS
:
304 /* otherwise parse entire global font info section, */
305 /* saving the data */
306 switch (recognize (keyword
))
308 case STARTFONTMETRICS
:
309 keyword
= token (fp
);
310 gfi
->afmVersion
= (char *) malloc (strlen (keyword
) + 1);
311 strcpy (gfi
->afmVersion
, keyword
);
314 keyword
= linetoken (fp
);
317 keyword
= token (fp
);
318 gfi
->fontName
= (char *) malloc (strlen (keyword
) + 1);
319 strcpy (gfi
->fontName
, keyword
);
322 keyword
= token (fp
);
323 gfi
->encodingScheme
= (char *)
324 malloc (strlen (keyword
) + 1);
325 strcpy (gfi
->encodingScheme
, keyword
);
328 keyword
= linetoken (fp
);
329 gfi
->fullName
= (char *) malloc (strlen (keyword
) + 1);
330 strcpy (gfi
->fullName
, keyword
);
333 keyword
= linetoken (fp
);
334 gfi
->familyName
= (char *) malloc (strlen (keyword
) + 1);
335 strcpy (gfi
->familyName
, keyword
);
338 keyword
= token (fp
);
339 gfi
->weight
= (char *) malloc (strlen (keyword
) + 1);
340 strcpy (gfi
->weight
, keyword
);
343 keyword
= token (fp
);
344 gfi
->italicAngle
= atof (keyword
);
345 if (errno
== ERANGE
) error
= AFM_parseError
;
348 keyword
= token (fp
);
349 if (MATCH (keyword
, False
))
350 gfi
->isFixedPitch
= 0;
352 gfi
->isFixedPitch
= 1;
354 case UNDERLINEPOSITION
:
355 keyword
= token (fp
);
356 gfi
->underlinePosition
= atoi (keyword
);
358 case UNDERLINETHICKNESS
:
359 keyword
= token (fp
);
360 gfi
->underlineThickness
= atoi (keyword
);
363 keyword
= linetoken (fp
);
364 gfi
->version
= (char *) malloc (strlen (keyword
) + 1);
365 strcpy (gfi
->version
, keyword
);
368 keyword
= linetoken (fp
);
369 gfi
->notice
= (char *) malloc (strlen (keyword
) + 1);
370 strcpy (gfi
->notice
, keyword
);
373 keyword
= token (fp
);
374 gfi
->fontBBox
.llx
= atoi (keyword
);
375 keyword
= token (fp
);
376 gfi
->fontBBox
.lly
= atoi (keyword
);
377 keyword
= token (fp
);
378 gfi
->fontBBox
.urx
= atoi (keyword
);
379 keyword
= token (fp
);
380 gfi
->fontBBox
.ury
= atoi (keyword
);
383 keyword
= token (fp
);
384 gfi
->capHeight
= atoi (keyword
);
387 keyword
= token (fp
);
388 gfi
->xHeight
= atoi (keyword
);
391 keyword
= token (fp
);
392 gfi
->descender
= atoi (keyword
);
395 keyword
= token (fp
);
396 gfi
->ascender
= atoi (keyword
);
398 case STARTCHARMETRICS
:
407 error
= AFM_parseError
;
418 /************************* initializeArray ************************/
420 /* Unmapped character codes are (at Adobe Systems) assigned the
421 * width of the space character (if one exists) else they get the
422 * value of 250 ems. This function initializes all entries in the
423 * char widths array to have this value. Then any mapped character
424 * codes will be replaced with the width of the appropriate character
425 * when parsing the character metric section.
427 * This function parses the Character Metrics Section looking
428 * for a space character (by comparing character names). If found,
429 * the width of the space character will be used to initialize the
430 * values in the array of character widths.
432 * Before returning, the position of the read/write pointer of the
433 * file is reset to be where it was upon entering this function.
436 static int initializeArray (FILE *fp
, register int *cwi
)
438 BOOL cont
= TRUE
, found
= FALSE
;
439 long opos
= ftell (fp
);
440 int code
= 0, width
= 0, i
= 0, error
= 0;
441 register char *keyword
;
445 keyword
= token (fp
);
448 error
= AFM_earlyEOF
;
449 break; /* get out of loop */
451 switch (recognize (keyword
))
454 keyword
= linetoken (fp
);
457 code
= atoi (token (fp
));
460 width
= atoi (token (fp
));
463 keyword
= token (fp
);
464 if (MATCH (keyword
, Space
))
479 error
= AFM_parseError
;
487 for (i
= 0; i
< 256; ++i
)
494 } /* initializeArray */
497 /************************* parseCharWidths **************************/
499 /* This function is called by "parseFile". It will parse the AFM File
500 * up to the "EndCharMetrics" keyword. It will save the character
501 * width info (as opposed to all of the character metric information)
502 * if requested by the caller of parseFile. Otherwise, it will just
503 * parse through the section without saving any information.
505 * If data is to be saved, parseCharWidths is passed in a pointer
506 * to an array of widths that has already been initialized by the
507 * standard value for unmapped character codes. This function parses
508 * the Character Metrics section only storing the width information
509 * for the encoded characters into the array using the character code
510 * as the index into that array.
512 * This function returns an error code specifying whether there was
513 * a premature EOF or a parsing error. This return value is used by
514 * parseFile to determine if there is more file to parse.
517 static int parseCharWidths (FILE *fp
, register int *cwi
)
519 BOOL cont
= TRUE
, save
= (cwi
!= NULL
);
520 int pos
= 0, error
= AFM_ok
;
521 register char *keyword
;
525 keyword
= token (fp
);
526 /* Have reached an early and unexpected EOF. */
527 /* Set flag and stop parsing */
530 error
= AFM_earlyEOF
;
531 break; /* get out of loop */
534 /* get tokens until the end of the Char Metrics section without */
535 /* saving any of the data*/
536 switch (recognize (keyword
))
549 /* otherwise parse entire char metrics section, saving */
550 /* only the char x-width info */
551 switch (recognize (keyword
))
554 keyword
= linetoken (fp
);
557 keyword
= token (fp
);
558 pos
= atoi (keyword
);
561 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
562 keyword
= token (fp
); keyword
= token (fp
); /* eat values */
563 error
= AFM_parseError
;
566 keyword
= token (fp
);
567 if (pos
>= 0) /* ignore unmapped chars */
568 cwi
[pos
] = atoi (keyword
);
577 case CHARNAME
: /* eat values (so doesn't cause AFM_parseError) */
578 keyword
= token (fp
);
581 keyword
= token (fp
); keyword
= token (fp
);
582 keyword
= token (fp
); keyword
= token (fp
);
585 keyword
= token (fp
); keyword
= token (fp
);
589 error
= AFM_parseError
;
596 } /* parseCharWidths */
599 /************************* parseCharMetrics ************************/
601 /* This function is called by parseFile if the caller of parseFile
602 * requested that all character metric information be saved
603 * (as opposed to only the character width information).
605 * parseCharMetrics is passed in a pointer to an array of records
606 * to hold information on a per character basis. This function
607 * parses the Character Metrics section storing all character
608 * metric information for the ALL characters (mapped and unmapped)
611 * This function returns an error code specifying whether there was
612 * a premature EOF or a parsing error. This return value is used by
613 * parseFile to determine if there is more file to parse.
616 static int parseCharMetrics (FILE *fp
, register AFM_Font_info
*fi
)
618 BOOL cont
= TRUE
, firstTime
= TRUE
;
619 int error
= AFM_ok
, count
= 0;
620 register AFM_CharMetricInfo
*temp
= fi
->cmi
;
621 register char *keyword
;
625 keyword
= token (fp
);
628 error
= AFM_earlyEOF
;
629 break; /* get out of loop */
631 switch (recognize (keyword
))
634 keyword
= linetoken (fp
);
637 if (count
< fi
->numOfChars
)
639 if (firstTime
) firstTime
= FALSE
;
641 temp
->code
= atoi (token (fp
));
646 error
= AFM_parseError
;
651 temp
->wx
= atoi (token (fp
));
652 temp
->wy
= atoi (token (fp
));
655 temp
->wx
= atoi (token (fp
));
658 keyword
= token (fp
);
659 temp
->name
= (char *) malloc (strlen (keyword
) + 1);
660 strcpy (temp
->name
, keyword
);
663 temp
->charBBox
.llx
= atoi (token (fp
));
664 temp
->charBBox
.lly
= atoi (token (fp
));
665 temp
->charBBox
.urx
= atoi (token (fp
));
666 temp
->charBBox
.ury
= atoi (token (fp
));
669 AFM_Ligature
**tail
= & (temp
->ligs
);
670 AFM_Ligature
*node
= *tail
;
674 while (node
->next
!= NULL
)
676 tail
= & (node
->next
);
679 *tail
= (AFM_Ligature
*) calloc (1, sizeof (AFM_Ligature
));
680 keyword
= token (fp
);
681 (*tail
)->succ
= (char *) malloc (strlen (keyword
) + 1);
682 strcpy ((*tail
)->succ
, keyword
);
683 keyword
= token (fp
);
684 (*tail
)->lig
= (char *) malloc (strlen (keyword
) + 1);
685 strcpy ((*tail
)->lig
, keyword
);
696 error
= AFM_parseError
;
701 if ((error
== AFM_ok
) && (count
!= fi
->numOfChars
))
702 error
= AFM_parseError
;
706 } /* parseCharMetrics */
710 /************************* parseAFM_TrackKernData ***********************/
712 /* This function is called by "parseFile". It will parse the AFM File
713 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
714 * track kerning data if requested by the caller of parseFile.
716 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
717 * If data is to be saved, the FontInfo record will already contain
718 * a valid pointer to storage for the track kerning data.
720 * This function returns an error code specifying whether there was
721 * a premature EOF or a parsing error. This return value is used by
722 * parseFile to determine if there is more file to parse.
725 static int parseAFM_TrackKernData (FILE *fp
, register AFM_Font_info
*fi
)
727 BOOL cont
= TRUE
, save
= (fi
->tkd
!= NULL
);
728 int pos
= 0, error
= AFM_ok
, tcount
= 0;
729 register char *keyword
;
733 keyword
= token (fp
);
737 error
= AFM_earlyEOF
;
738 break; /* get out of loop */
741 /* get tokens until the end of the Track Kerning Data */
742 /* section without saving any of the data */
743 switch (recognize (keyword
))
757 /* otherwise parse entire Track Kerning Data section, */
758 /* saving the data */
759 switch (recognize (keyword
))
762 keyword
= linetoken (fp
);
765 if (tcount
< fi
->numOfTracks
)
767 keyword
= token (fp
);
768 fi
->tkd
[pos
].degree
= atoi (keyword
);
769 keyword
= token (fp
);
770 fi
->tkd
[pos
].minPtSize
= atof (keyword
);
771 if (errno
== ERANGE
) error
= AFM_parseError
;
772 keyword
= token (fp
);
773 fi
->tkd
[pos
].minKernAmt
= atof (keyword
);
774 if (errno
== ERANGE
) error
= AFM_parseError
;
775 keyword
= token (fp
);
776 fi
->tkd
[pos
].maxPtSize
= atof (keyword
);
777 if (errno
== ERANGE
) error
= AFM_parseError
;
778 keyword
= token (fp
);
779 fi
->tkd
[pos
++].maxKernAmt
= atof (keyword
);
780 if (errno
== ERANGE
) error
= AFM_parseError
;
785 error
= AFM_parseError
;
799 error
= AFM_parseError
;
804 if (error
== AFM_ok
&& tcount
!= fi
->numOfTracks
)
805 error
= AFM_parseError
;
809 } /* parseAFM_TrackKernData */
812 /************************* parseAFM_PairKernData ************************/
814 /* This function is called by "parseFile". It will parse the AFM File
815 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
816 * the pair kerning data if requested by the caller of parseFile.
818 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
819 * If data is to be saved, the FontInfo record will already contain
820 * a valid pointer to storage for the pair kerning data.
822 * This function returns an error code specifying whether there was
823 * a premature EOF or a parsing error. This return value is used by
824 * parseFile to determine if there is more file to parse.
827 static int parseAFM_PairKernData (FILE *fp
, register AFM_Font_info
*fi
)
829 BOOL cont
= TRUE
, save
= (fi
->pkd
!= NULL
);
830 int pos
= 0, error
= AFM_ok
, pcount
= 0;
831 register char *keyword
;
835 keyword
= token (fp
);
839 error
= AFM_earlyEOF
;
840 break; /* get out of loop */
843 /* get tokens until the end of the Pair Kerning Data */
844 /* section without saving any of the data */
845 switch (recognize (keyword
))
859 /* otherwise parse entire Pair Kerning Data section, */
860 /* saving the data */
861 switch (recognize (keyword
))
864 keyword
= linetoken (fp
);
867 if (pcount
< fi
->numOfPairs
)
869 keyword
= token (fp
);
870 fi
->pkd
[pos
].name1
= (char *)
871 malloc (strlen (keyword
) + 1);
872 strcpy (fi
->pkd
[pos
].name1
, keyword
);
873 keyword
= token (fp
);
874 fi
->pkd
[pos
].name2
= (char *)
875 malloc (strlen (keyword
) + 1);
876 strcpy (fi
->pkd
[pos
].name2
, keyword
);
877 keyword
= token (fp
);
878 fi
->pkd
[pos
].xamt
= atoi (keyword
);
879 keyword
= token (fp
);
880 fi
->pkd
[pos
++].yamt
= atoi (keyword
);
885 error
= AFM_parseError
;
890 if (pcount
< fi
->numOfPairs
)
892 keyword
= token (fp
);
893 fi
->pkd
[pos
].name1
= (char *)
894 malloc (strlen (keyword
) + 1);
895 strcpy (fi
->pkd
[pos
].name1
, keyword
);
896 keyword
= token (fp
);
897 fi
->pkd
[pos
].name2
= (char *)
898 malloc (strlen (keyword
) + 1);
899 strcpy (fi
->pkd
[pos
].name2
, keyword
);
900 keyword
= token (fp
);
901 fi
->pkd
[pos
++].xamt
= atoi (keyword
);
906 error
= AFM_parseError
;
920 error
= AFM_parseError
;
925 if (error
== AFM_ok
&& pcount
!= fi
->numOfPairs
)
926 error
= AFM_parseError
;
930 } /* parseAFM_PairKernData */
933 /************************* parseAFM_CompCharData **************************/
935 /* This function is called by "parseFile". It will parse the AFM File
936 * up to the "EndComposites" keyword. It will save the composite
937 * character data if requested by the caller of parseFile.
939 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
940 * a boolean representing if the data should be saved.
942 * This function will create the appropriate amount of storage for
943 * the composite character data and store a pointer to the storage
944 * in the FontInfo record.
946 * This function returns an error code specifying whether there was
947 * a premature EOF or a parsing error. This return value is used by
948 * parseFile to determine if there is more file to parse.
951 static int parseAFM_CompCharData (FILE *fp
, register AFM_Font_info
*fi
)
953 BOOL cont
= TRUE
, firstTime
= TRUE
, save
= (fi
->ccd
!= NULL
);
954 int pos
= 0, j
= 0, error
= AFM_ok
, ccount
= 0, pcount
= 0;
955 register char *keyword
;
959 keyword
= token (fp
);
961 /* Have reached an early and unexpected EOF. */
962 /* Set flag and stop parsing */
964 error
= AFM_earlyEOF
;
965 break; /* get out of loop */
967 if (ccount
> fi
->numOfComps
)
969 error
= AFM_parseError
;
970 break; /* get out of loop */
973 /* get tokens until the end of the Composite Character info */
974 /* section without saving any of the data */
975 switch (recognize (keyword
))
988 /* otherwise parse entire Composite Character info section, */
989 /* saving the data */
990 switch (recognize (keyword
))
993 keyword
= linetoken (fp
);
996 if (ccount
< fi
->numOfComps
)
998 keyword
= token (fp
);
999 if (pcount
!= fi
->ccd
[pos
].numOfPieces
)
1000 error
= AFM_parseError
;
1002 if (firstTime
) firstTime
= FALSE
;
1004 fi
->ccd
[pos
].ccName
= (char *)
1005 malloc (strlen (keyword
) + 1);
1006 strcpy (fi
->ccd
[pos
].ccName
, keyword
);
1007 keyword
= token (fp
);
1008 fi
->ccd
[pos
].numOfPieces
= atoi (keyword
);
1009 fi
->ccd
[pos
].pieces
= (AFM_Pcc
*)
1010 calloc (fi
->ccd
[pos
].numOfPieces
, sizeof (AFM_Pcc
));
1016 error
= AFM_parseError
;
1021 if (pcount
< fi
->ccd
[pos
].numOfPieces
)
1023 keyword
= token (fp
);
1024 fi
->ccd
[pos
].pieces
[j
].AFM_PccName
= (char *)
1025 malloc (strlen (keyword
) + 1);
1026 strcpy (fi
->ccd
[pos
].pieces
[j
].AFM_PccName
, keyword
);
1027 keyword
= token (fp
);
1028 fi
->ccd
[pos
].pieces
[j
].deltax
= atoi (keyword
);
1029 keyword
= token (fp
);
1030 fi
->ccd
[pos
].pieces
[j
++].deltay
= atoi (keyword
);
1034 error
= AFM_parseError
;
1039 case ENDFONTMETRICS
:
1045 error
= AFM_parseError
;
1050 if (error
== AFM_ok
&& ccount
!= fi
->numOfComps
)
1051 error
= AFM_parseError
;
1055 } /* parseAFM_CompCharData */
1060 /*************************** 'PUBLIC' FUNCTION ********************/
1063 /*************************** parseFile *****************************/
1065 /* parseFile is the only 'public' procedure available. It is called
1066 * from an application wishing to get information from an AFM file.
1067 * The caller of this function is responsible for locating and opening
1068 * an AFM file and handling all errors associated with that task.
1070 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1071 * to a (FontInfo *) variable (for which storage will be allocated and
1072 * the data requested filled in), and a mask specifying which
1073 * data from the AFM File should be saved in the FontInfo structure.
1075 * The file will be parsed and the requested data will be stored in
1076 * a record of type FontInfo (refer to ParseAFM.h).
1078 * parseFile returns an error code as defined in parseAFM.h.
1080 * The position of the read/write pointer associated with the file
1081 * pointer upon return of this function is undefined.
1084 extern int AFM_parseFile (FILE *fp
, AFM_Font_info
**fi
, int flags
)
1087 int code
= AFM_ok
; /* return code from each of the parsing routines */
1088 int error
= AFM_ok
; /* used as the return code from this function */
1090 register char *keyword
; /* used to store a token */
1093 /* storage data for the global variable ident */
1095 ident
= (char *) calloc (MAX_NAME
, sizeof (char));
1096 if (ident
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1098 (*fi
) = (AFM_Font_info
*) calloc (1, sizeof (AFM_Font_info
));
1099 if ((*fi
) == NULL
) {error
= AFM_storageProblem
; return (error
);}
1103 (*fi
)->gfi
= (AFM_GlobalFontInfo
*) calloc (1, sizeof (AFM_GlobalFontInfo
));
1104 if ((*fi
)->gfi
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1107 /* The AFM File begins with Global Font Information. This section */
1108 /* will be parsed whether or not information should be saved. */
1109 code
= parseGlobals (fp
, (*fi
)->gfi
);
1111 if (code
< 0) error
= code
;
1113 /* The Global Font Information is followed by the Character Metrics */
1114 /* section. Which procedure is used to parse this section depends on */
1115 /* how much information should be saved. If all of the metrics info */
1116 /* is wanted, parseCharMetrics is called. If only the character widths */
1117 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1118 /* be called in the case that no character data is to be saved, just */
1119 /* to parse through the section. */
1121 if ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1123 (*fi
)->numOfChars
= atoi (token (fp
));
1124 if (flags
& (P_M
^ P_W
))
1126 (*fi
)->cmi
= (AFM_CharMetricInfo
*)
1127 calloc ((*fi
)->numOfChars
, sizeof (AFM_CharMetricInfo
));
1128 if ((*fi
)->cmi
== NULL
) {error
= AFM_storageProblem
; return (error
);}
1129 code
= parseCharMetrics (fp
, *fi
);
1135 (*fi
)->cwi
= (int *) calloc (256, sizeof (int));
1136 if ((*fi
)->cwi
== NULL
)
1138 error
= AFM_storageProblem
;
1142 /* parse section regardless */
1143 code
= parseCharWidths (fp
, (*fi
)->cwi
);
1147 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1149 /* The remaining sections of the AFM are optional. This code will */
1150 /* look at the next keyword in the file to determine what section */
1151 /* is next, and then allocate the appropriate amount of storage */
1152 /* for the data (if the data is to be saved) and call the */
1153 /* appropriate parsing routine to parse the section. */
1155 while ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1157 keyword
= token (fp
);
1158 if (keyword
== NULL
)
1159 /* Have reached an early and unexpected EOF. */
1160 /* Set flag and stop parsing */
1162 code
= AFM_earlyEOF
;
1163 break; /* get out of loop */
1165 switch (recognize (keyword
))
1171 case STARTTRACKKERN
:
1172 keyword
= token (fp
);
1175 (*fi
)->numOfTracks
= atoi (keyword
);
1176 (*fi
)->tkd
= (AFM_TrackKernData
*)
1177 calloc ((*fi
)->numOfTracks
, sizeof (AFM_TrackKernData
));
1178 if ((*fi
)->tkd
== NULL
)
1180 error
= AFM_storageProblem
;
1184 code
= parseAFM_TrackKernData (fp
, *fi
);
1186 case STARTKERNPAIRS
:
1187 keyword
= token (fp
);
1190 (*fi
)->numOfPairs
= atoi (keyword
);
1191 (*fi
)->pkd
= (AFM_PairKernData
*)
1192 calloc ((*fi
)->numOfPairs
, sizeof (AFM_PairKernData
));
1193 if ((*fi
)->pkd
== NULL
)
1195 error
= AFM_storageProblem
;
1199 code
= parseAFM_PairKernData (fp
, *fi
);
1201 case STARTCOMPOSITES
:
1202 keyword
= token (fp
);
1205 (*fi
)->numOfComps
= atoi (keyword
);
1206 (*fi
)->ccd
= (AFM_CompCharData
*)
1207 calloc ((*fi
)->numOfComps
, sizeof (AFM_CompCharData
));
1208 if ((*fi
)->ccd
== NULL
)
1210 error
= AFM_storageProblem
;
1214 code
= parseAFM_CompCharData (fp
, *fi
);
1216 case ENDFONTMETRICS
:
1221 code
= AFM_parseError
;
1225 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1229 if ((error
!= AFM_earlyEOF
) && (code
< 0)) error
= code
;
1231 if (ident
!= NULL
) { free (ident
); ident
= NULL
; }
1239 AFM_free (AFM_Font_info
*fi
)
1242 free (fi
->gfi
->afmVersion
);
1243 free (fi
->gfi
->fontName
);
1244 free (fi
->gfi
->fullName
);
1245 free (fi
->gfi
->familyName
);
1246 free (fi
->gfi
->weight
);
1247 free (fi
->gfi
->version
);
1248 free (fi
->gfi
->notice
);
1249 free (fi
->gfi
->encodingScheme
);
1253 /* This contains just scalars. */
1258 for (i
= 0; i
< fi
->numOfChars
; i
++) {
1259 free (fi
->cmi
[i
].name
);
1260 while (fi
->cmi
[i
].ligs
) {
1262 tmp
= fi
->cmi
[i
].ligs
;
1266 fi
->cmi
[i
].ligs
= fi
->cmi
[i
].ligs
->next
;
1272 /* This contains just scalars. */
1277 for (i
= 0; i
< fi
->numOfPairs
; i
++) {
1278 free (fi
->pkd
[i
].name1
);
1279 free (fi
->pkd
[i
].name2
);
1286 for (i
= 0; i
< fi
->numOfComps
; i
++) {
1287 free (fi
->ccd
[i
].ccName
);
1288 for (j
= 0; j
< fi
->ccd
[i
].numOfPieces
; j
++) {
1289 free (fi
->ccd
[i
].pieces
[j
].AFM_PccName
);
1291 free (fi
->ccd
[i
].pieces
);