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"
80 #define lineterm EOL /* line terminating character */
81 #define lineterm_alt '\r' /* alternative line terminating character */
82 #define normalEOF 1 /* return code from parsing routines used only */
84 #define Space "space" /* used in string comparison to look for the width */
85 /* of the space character to init the widths array */
86 #define False "false" /* used in string comparison to check the value of */
87 /* boolean keys (e.g. IsFixedPitch) */
89 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
93 /*************************** GLOBALS ***********************/
95 static char *ident = NULL; /* storage buffer for keywords */
98 /* "shorts" for fast case statement
99 * The values of each of these enumerated items correspond to an entry in the
100 * table of strings defined below. Therefore, if you add a new string as
101 * new keyword into the keyStrings table, you must also add a corresponding
102 * parseKey AND it MUST be in the same position!
104 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
105 * keywords must be placed in lexicographical order, below. [Therefore, the
106 * enumerated items are not necessarily in lexicographical order, depending
107 * on the name chosen. BUT, they must be placed in the same position as the
108 * corresponding key string.] The NOPE shall remain in the last position,
109 * since it does not correspond to any key string, and it is used in the
110 * "recognize" procedure to calculate how many possible keys there are.
114 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
115 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
116 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
117 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH,
118 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
119 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
120 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
121 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
122 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
125 /* keywords for the system:
126 * This a table of all of the current strings that are vaild AFM keys.
127 * Each entry can be referenced by the appropriate parseKey value (an
128 * enumerated data type defined above). If you add a new keyword here,
129 * a corresponding parseKey MUST be added to the enumerated data type
130 * defined above, AND it MUST be added in the same position as the
131 * string is in this table.
133 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
134 * must be placed in lexicographical order. And, NULL should remain at the
138 static char *keyStrings[] = {
139 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
140 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
141 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
142 "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
143 "ItalicAngle", "KP", "KPX", "L", "N",
144 "Notice", "PCC", "StartCharMetrics", "StartComposites",
145 "StartFontMetrics", "StartKernData", "StartKernPairs",
146 "StartTrackKern", "TrackKern", "UnderlinePosition",
147 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
150 /*************************** PARSING ROUTINES **************/
152 /*************************** token *************************/
154 /* A "AFM File Conventions" tokenizer. That means that it will
155 * return the next token delimited by white space. See also
156 * the `linetoken' routine, which does a similar thing but
157 * reads all tokens until the next end-of-line.
160 static char *token (FILE *stream)
164 /* skip over white space */
165 while ((ch = fgetc (stream)) == ' ' || ch == lineterm ||
166 ch == lineterm_alt ||
167 ch == ',' || ch == '\t' || ch == ';');
170 while (idx < MAX_NAME - 1 &&
171 ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
172 && ch != '\t' && ch != ':' && ch != ';')
178 if (ch == EOF && idx < 1) return ((char *)NULL);
179 if (idx >= 1 && ch != ':' ) ungetc (ch, stream);
180 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
183 return (ident); /* returns pointer to the token */
188 /*************************** linetoken *************************/
190 /* "linetoken" will get read all tokens until the EOL character from
191 * the given stream. This is used to get any arguments that can be
192 * more than one word (like Comment lines and FullName).
195 static char *linetoken (FILE *stream)
199 while ((ch = fgetc (stream)) == ' ' || ch == '\t' );
202 while (idx < MAX_NAME - 1 &&
203 ch != EOF && ch != lineterm && ch != lineterm_alt)
212 return (ident); /* returns pointer to the token */
217 /*************************** recognize *************************/
219 /* This function tries to match a string to a known list of
220 * valid AFM entries (check the keyStrings array above).
221 * "ident" contains everything from white space through the
222 * next space, tab, or ":" character.
224 * The algorithm is a standard Knuth binary search.
227 static enum parseKey recognize ( register char *ident)
235 while ((upper >= lower) && !found)
237 midpoint = (lower + upper)/2;
238 if (keyStrings[midpoint] == NULL) break;
239 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
240 if (cmpvalue == 0) found = TRUE;
241 else if (cmpvalue < 0) upper = midpoint - 1;
242 else lower = midpoint + 1;
245 if (found) return (enum parseKey) midpoint;
251 /************************* parseGlobals *****************************/
253 /* This function is called by "parseFile". It will parse the AFM File
254 * up to the "StartCharMetrics" keyword, which essentially marks the
255 * end of the Global Font Information and the beginning of the character
256 * metrics information.
258 * If the caller of "parseFile" specified that it wanted the Global
259 * Font Information (as defined by the "AFM File Specification"
260 * document), then that information will be stored in the returned
263 * Any Global Font Information entries that are not found in a
264 * given file, will have the usual default initialization value
265 * for its type (i.e. entries of type int will be 0, etc).
267 * This function returns an error code specifying whether there was
268 * a premature EOF or a parsing error. This return value is used by
269 * parseFile to determine if there is more file to parse.
272 static BOOL parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
274 BOOL cont = TRUE, save = (gfi != NULL);
276 register char *keyword;
280 keyword = token (fp);
283 /* Have reached an early and unexpected EOF. */
284 /* Set flag and stop parsing */
286 error = AFM_earlyEOF;
287 break; /* get out of loop */
290 /* get tokens until the end of the Global Font info section */
291 /* without saving any of the data */
292 switch (recognize (keyword))
294 case STARTCHARMETRICS:
305 /* otherwise parse entire global font info section, */
306 /* saving the data */
307 switch (recognize (keyword))
309 case STARTFONTMETRICS:
310 keyword = token (fp);
311 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
312 strcpy (gfi->afmVersion, keyword);
315 keyword = linetoken (fp);
318 keyword = token (fp);
319 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
320 strcpy (gfi->fontName, keyword);
323 keyword = token (fp);
324 gfi->encodingScheme = (char *)
325 malloc (strlen (keyword) + 1);
326 strcpy (gfi->encodingScheme, keyword);
329 keyword = linetoken (fp);
330 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
331 strcpy (gfi->fullName, keyword);
334 keyword = linetoken (fp);
335 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
336 strcpy (gfi->familyName, keyword);
339 keyword = token (fp);
340 gfi->weight = (char *) malloc (strlen (keyword) + 1);
341 strcpy (gfi->weight, keyword);
344 keyword = token (fp);
345 gfi->italicAngle = atof (keyword);
346 if (errno == ERANGE) error = AFM_parseError;
349 keyword = token (fp);
350 if (MATCH (keyword, False))
351 gfi->isFixedPitch = 0;
353 gfi->isFixedPitch = 1;
355 case UNDERLINEPOSITION:
356 keyword = token (fp);
357 gfi->underlinePosition = atoi (keyword);
359 case UNDERLINETHICKNESS:
360 keyword = token (fp);
361 gfi->underlineThickness = atoi (keyword);
364 keyword = linetoken (fp);
365 gfi->version = (char *) malloc (strlen (keyword) + 1);
366 strcpy (gfi->version, keyword);
369 keyword = linetoken (fp);
370 gfi->notice = (char *) malloc (strlen (keyword) + 1);
371 strcpy (gfi->notice, keyword);
374 keyword = token (fp);
375 gfi->fontBBox.llx = atoi (keyword);
376 keyword = token (fp);
377 gfi->fontBBox.lly = atoi (keyword);
378 keyword = token (fp);
379 gfi->fontBBox.urx = atoi (keyword);
380 keyword = token (fp);
381 gfi->fontBBox.ury = atoi (keyword);
384 keyword = token (fp);
385 gfi->capHeight = atoi (keyword);
388 keyword = token (fp);
389 gfi->xHeight = atoi (keyword);
392 keyword = token (fp);
393 gfi->descender = atoi (keyword);
396 keyword = token (fp);
397 gfi->ascender = atoi (keyword);
399 case STARTCHARMETRICS:
408 error = AFM_parseError;
419 /************************* initializeArray ************************/
421 /* Unmapped character codes are (at Adobe Systems) assigned the
422 * width of the space character (if one exists) else they get the
423 * value of 250 ems. This function initializes all entries in the
424 * char widths array to have this value. Then any mapped character
425 * codes will be replaced with the width of the appropriate character
426 * when parsing the character metric section.
428 * This function parses the Character Metrics Section looking
429 * for a space character (by comparing character names). If found,
430 * the width of the space character will be used to initialize the
431 * values in the array of character widths.
433 * Before returning, the position of the read/write pointer of the
434 * file is reset to be where it was upon entering this function.
437 static int initializeArray (FILE *fp, register int *cwi)
439 BOOL cont = TRUE, found = FALSE;
440 long opos = ftell (fp);
441 int code = 0, width = 0, i = 0, error = 0;
442 register char *keyword;
446 keyword = token (fp);
449 error = AFM_earlyEOF;
450 break; /* get out of loop */
452 switch (recognize (keyword))
455 keyword = linetoken (fp);
458 code = atoi (token (fp));
461 width = atoi (token (fp));
464 keyword = token (fp);
465 if (MATCH (keyword, Space))
480 error = AFM_parseError;
488 for (i = 0; i < 256; ++i)
495 } /* initializeArray */
498 /************************* parseCharWidths **************************/
500 /* This function is called by "parseFile". It will parse the AFM File
501 * up to the "EndCharMetrics" keyword. It will save the character
502 * width info (as opposed to all of the character metric information)
503 * if requested by the caller of parseFile. Otherwise, it will just
504 * parse through the section without saving any information.
506 * If data is to be saved, parseCharWidths is passed in a pointer
507 * to an array of widths that has already been initialized by the
508 * standard value for unmapped character codes. This function parses
509 * the Character Metrics section only storing the width information
510 * for the encoded characters into the array using the character code
511 * as the index into that array.
513 * This function returns an error code specifying whether there was
514 * a premature EOF or a parsing error. This return value is used by
515 * parseFile to determine if there is more file to parse.
518 static int parseCharWidths (FILE *fp, register int *cwi)
520 BOOL cont = TRUE, save = (cwi != NULL);
521 int pos = 0, error = AFM_ok;
522 register char *keyword;
526 keyword = token (fp);
527 /* Have reached an early and unexpected EOF. */
528 /* Set flag and stop parsing */
531 error = AFM_earlyEOF;
532 break; /* get out of loop */
535 /* get tokens until the end of the Char Metrics section without */
536 /* saving any of the data*/
537 switch (recognize (keyword))
550 /* otherwise parse entire char metrics section, saving */
551 /* only the char x-width info */
552 switch (recognize (keyword))
555 keyword = linetoken (fp);
558 keyword = token (fp);
559 pos = atoi (keyword);
562 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
563 keyword = token (fp); keyword = token (fp); /* eat values */
564 error = AFM_parseError;
567 keyword = token (fp);
568 if (pos >= 0) /* ignore unmapped chars */
569 cwi[pos] = atoi (keyword);
578 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
579 keyword = token (fp);
582 keyword = token (fp); keyword = token (fp);
583 keyword = token (fp); keyword = token (fp);
586 keyword = token (fp); keyword = token (fp);
590 error = AFM_parseError;
597 } /* parseCharWidths */
600 /************************* parseCharMetrics ************************/
602 /* This function is called by parseFile if the caller of parseFile
603 * requested that all character metric information be saved
604 * (as opposed to only the character width information).
606 * parseCharMetrics is passed in a pointer to an array of records
607 * to hold information on a per character basis. This function
608 * parses the Character Metrics section storing all character
609 * metric information for the ALL characters (mapped and unmapped)
612 * This function returns an error code specifying whether there was
613 * a premature EOF or a parsing error. This return value is used by
614 * parseFile to determine if there is more file to parse.
617 static int parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
619 BOOL cont = TRUE, firstTime = TRUE;
620 int error = AFM_ok, count = 0;
621 register AFM_CharMetricInfo *temp = fi->cmi;
622 register char *keyword;
626 keyword = token (fp);
629 error = AFM_earlyEOF;
630 break; /* get out of loop */
632 switch (recognize (keyword))
635 keyword = linetoken (fp);
638 if (count < fi->numOfChars)
644 temp->code = atoi (token (fp));
649 warning ("Too many metrics.");
650 error = AFM_parseError;
655 temp->wx = atoi (token (fp));
656 temp->wy = atoi (token (fp));
659 temp->wx = atoi (token (fp));
663 keyword = token (fp);
664 temp->name = (char *) malloc (strlen (keyword) + 1);
665 strcpy (temp->name, keyword);
669 temp->charBBox.llx = atoi (token (fp));
670 temp->charBBox.lly = atoi (token (fp));
671 temp->charBBox.urx = atoi (token (fp));
672 temp->charBBox.ury = atoi (token (fp));
676 AFM_Ligature **tail = & (temp->ligs);
677 AFM_Ligature *node = *tail;
681 while (node->next != NULL)
683 tail = & (node->next);
686 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
687 keyword = token (fp);
688 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
689 strcpy ((*tail)->succ, keyword);
690 keyword = token (fp);
691 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
692 strcpy ((*tail)->lig, keyword);
703 warning ("Unknown token");
705 error = AFM_parseError;
710 if ((error == AFM_ok) && (count != fi->numOfChars))
712 warning ("Incorrect char count");
713 error = AFM_parseError;
717 } /* parseCharMetrics */
721 /************************* parseAFM_TrackKernData ***********************/
723 /* This function is called by "parseFile". It will parse the AFM File
724 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
725 * track kerning data if requested by the caller of parseFile.
727 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
728 * If data is to be saved, the FontInfo record will already contain
729 * a valid pointer to storage for the track kerning data.
731 * This function returns an error code specifying whether there was
732 * a premature EOF or a parsing error. This return value is used by
733 * parseFile to determine if there is more file to parse.
736 static int parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
738 BOOL cont = TRUE, save = (fi->tkd != NULL);
739 int pos = 0, error = AFM_ok, tcount = 0;
740 register char *keyword;
744 keyword = token (fp);
748 error = AFM_earlyEOF;
749 break; /* get out of loop */
752 /* get tokens until the end of the Track Kerning Data */
753 /* section without saving any of the data */
754 switch (recognize (keyword))
768 /* otherwise parse entire Track Kerning Data section, */
769 /* saving the data */
770 switch (recognize (keyword))
773 keyword = linetoken (fp);
776 if (tcount < fi->numOfTracks)
778 keyword = token (fp);
779 fi->tkd[pos].degree = atoi (keyword);
780 keyword = token (fp);
781 fi->tkd[pos].minPtSize = atof (keyword);
782 if (errno == ERANGE) error = AFM_parseError;
783 keyword = token (fp);
784 fi->tkd[pos].minKernAmt = atof (keyword);
785 if (errno == ERANGE) error = AFM_parseError;
786 keyword = token (fp);
787 fi->tkd[pos].maxPtSize = atof (keyword);
788 if (errno == ERANGE) error = AFM_parseError;
789 keyword = token (fp);
790 fi->tkd[pos++].maxKernAmt = atof (keyword);
791 if (errno == ERANGE) error = AFM_parseError;
796 error = AFM_parseError;
810 error = AFM_parseError;
815 if (error == AFM_ok && tcount != fi->numOfTracks)
816 error = AFM_parseError;
820 } /* parseAFM_TrackKernData */
823 /************************* parseAFM_PairKernData ************************/
825 /* This function is called by "parseFile". It will parse the AFM File
826 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
827 * the pair kerning data if requested by the caller of parseFile.
829 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
830 * If data is to be saved, the FontInfo record will already contain
831 * a valid pointer to storage for the pair kerning data.
833 * This function returns an error code specifying whether there was
834 * a premature EOF or a parsing error. This return value is used by
835 * parseFile to determine if there is more file to parse.
838 static int parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
840 BOOL cont = TRUE, save = (fi->pkd != NULL);
841 int pos = 0, error = AFM_ok, pcount = 0;
842 register char *keyword;
846 keyword = token (fp);
850 error = AFM_earlyEOF;
851 break; /* get out of loop */
854 /* get tokens until the end of the Pair Kerning Data */
855 /* section without saving any of the data */
856 switch (recognize (keyword))
870 /* otherwise parse entire Pair Kerning Data section, */
871 /* saving the data */
872 switch (recognize (keyword))
875 keyword = linetoken (fp);
878 if (pcount < fi->numOfPairs)
880 keyword = token (fp);
881 fi->pkd[pos].name1 = (char *)
882 malloc (strlen (keyword) + 1);
883 strcpy (fi->pkd[pos].name1, keyword);
884 keyword = token (fp);
885 fi->pkd[pos].name2 = (char *)
886 malloc (strlen (keyword) + 1);
887 strcpy (fi->pkd[pos].name2, keyword);
888 keyword = token (fp);
889 fi->pkd[pos].xamt = atoi (keyword);
890 keyword = token (fp);
891 fi->pkd[pos++].yamt = atoi (keyword);
896 error = AFM_parseError;
901 if (pcount < fi->numOfPairs)
903 keyword = token (fp);
904 fi->pkd[pos].name1 = (char *)
905 malloc (strlen (keyword) + 1);
906 strcpy (fi->pkd[pos].name1, keyword);
907 keyword = token (fp);
908 fi->pkd[pos].name2 = (char *)
909 malloc (strlen (keyword) + 1);
910 strcpy (fi->pkd[pos].name2, keyword);
911 keyword = token (fp);
912 fi->pkd[pos++].xamt = atoi (keyword);
917 error = AFM_parseError;
931 error = AFM_parseError;
936 if (error == AFM_ok && pcount != fi->numOfPairs)
937 error = AFM_parseError;
941 } /* parseAFM_PairKernData */
944 /************************* parseAFM_CompCharData **************************/
946 /* This function is called by "parseFile". It will parse the AFM File
947 * up to the "EndComposites" keyword. It will save the composite
948 * character data if requested by the caller of parseFile.
950 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
951 * a boolean representing if the data should be saved.
953 * This function will create the appropriate amount of storage for
954 * the composite character data and store a pointer to the storage
955 * in the FontInfo record.
957 * This function returns an error code specifying whether there was
958 * a premature EOF or a parsing error. This return value is used by
959 * parseFile to determine if there is more file to parse.
962 static int parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
964 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
965 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
966 register char *keyword;
970 keyword = token (fp);
972 /* Have reached an early and unexpected EOF. */
973 /* Set flag and stop parsing */
975 error = AFM_earlyEOF;
976 break; /* get out of loop */
978 if (ccount > fi->numOfComps)
980 error = AFM_parseError;
981 break; /* get out of loop */
984 /* get tokens until the end of the Composite Character info */
985 /* section without saving any of the data */
986 switch (recognize (keyword))
999 /* otherwise parse entire Composite Character info section, */
1000 /* saving the data */
1001 switch (recognize (keyword))
1004 keyword = linetoken (fp);
1007 if (ccount < fi->numOfComps)
1009 keyword = token (fp);
1010 if (pcount != fi->ccd[pos].numOfPieces)
1011 error = AFM_parseError;
1013 if (firstTime) firstTime = FALSE;
1015 fi->ccd[pos].ccName = (char *)
1016 malloc (strlen (keyword) + 1);
1017 strcpy (fi->ccd[pos].ccName, keyword);
1018 keyword = token (fp);
1019 fi->ccd[pos].numOfPieces = atoi (keyword);
1020 fi->ccd[pos].pieces = (AFM_Pcc *)
1021 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1027 error = AFM_parseError;
1032 if (pcount < fi->ccd[pos].numOfPieces)
1034 keyword = token (fp);
1035 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1036 malloc (strlen (keyword) + 1);
1037 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1038 keyword = token (fp);
1039 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1040 keyword = token (fp);
1041 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1045 error = AFM_parseError;
1050 case ENDFONTMETRICS:
1056 error = AFM_parseError;
1061 if (error == AFM_ok && ccount != fi->numOfComps)
1062 error = AFM_parseError;
1066 } /* parseAFM_CompCharData */
1071 /*************************** 'PUBLIC' FUNCTION ********************/
1074 AFM_free (AFM_Font_info *fi)
1077 free (fi->gfi->afmVersion);
1078 free (fi->gfi->fontName);
1079 free (fi->gfi->fullName);
1080 free (fi->gfi->familyName);
1081 free (fi->gfi->weight);
1082 free (fi->gfi->version);
1083 free (fi->gfi->notice);
1084 free (fi->gfi->encodingScheme);
1088 /* This contains just scalars. */
1093 for (i = 0; i < fi->numOfChars; i++) {
1094 free (fi->cmi[i].name);
1095 while (fi->cmi[i].ligs) {
1097 tmp = fi->cmi[i].ligs;
1101 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1107 /* This contains just scalars. */
1112 for (i = 0; i < fi->numOfPairs; i++) {
1113 free (fi->pkd[i].name1);
1114 free (fi->pkd[i].name2);
1121 for (i = 0; i < fi->numOfComps; i++) {
1122 free (fi->ccd[i].ccName);
1123 for (j = 0; j < fi->ccd[i].numOfPieces; j++) {
1124 free (fi->ccd[i].pieces[j].AFM_PccName);
1126 free (fi->ccd[i].pieces);
1135 /*************************** parseFile *****************************/
1137 /* parseFile is the only 'public' procedure available. It is called
1138 * from an application wishing to get information from an AFM file.
1139 * The caller of this function is responsible for locating and opening
1140 * an AFM file and handling all errors associated with that task.
1142 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1143 * to a (FontInfo *) variable (for which storage will be allocated and
1144 * the data requested filled in), and a mask specifying which
1145 * data from the AFM File should be saved in the FontInfo structure.
1147 * The file will be parsed and the requested data will be stored in
1148 * a record of type FontInfo (refer to ParseAFM.h).
1150 * parseFile returns an error code as defined in parseAFM.h.
1152 * The position of the read/write pointer associated with the file
1153 * pointer upon return of this function is undefined.
1156 extern int AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1159 int code = AFM_ok; /* return code from each of the parsing routines */
1160 int error = AFM_ok; /* used as the return code from this function */
1162 register char *keyword; /* used to store a token */
1165 /* storage data for the global variable ident */
1167 ident = (char *) calloc (MAX_NAME, sizeof (char));
1168 if (ident == NULL) {error = AFM_storageProblem; return (error);}
1170 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1171 if ((*fi) == NULL) {error = AFM_storageProblem; return (error);}
1175 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1, sizeof (AFM_GlobalFontInfo));
1176 if ((*fi)->gfi == NULL) {error = AFM_storageProblem; return (error);}
1179 /* The AFM File begins with Global Font Information. This section */
1180 /* will be parsed whether or not information should be saved. */
1181 code = parseGlobals (fp, (*fi)->gfi);
1186 /* The Global Font Information is followed by the Character Metrics */
1187 /* section. Which procedure is used to parse this section depends on */
1188 /* how much information should be saved. If all of the metrics info */
1189 /* is wanted, parseCharMetrics is called. If only the character widths */
1190 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1191 /* be called in the case that no character data is to be saved, just */
1192 /* to parse through the section. */
1194 if ((code != normalEOF) && (code != AFM_earlyEOF))
1196 (*fi)->numOfChars = atoi (token (fp));
1197 if (flags & (P_M ^ P_W))
1199 (*fi)->cmi = (AFM_CharMetricInfo *)
1200 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1201 if ((*fi)->cmi == NULL) {
1202 error = AFM_storageProblem;
1206 code = parseCharMetrics (fp, *fi);
1212 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1213 if ((*fi)->cwi == NULL)
1215 error = AFM_storageProblem;
1219 /* parse section regardless */
1220 code = parseCharWidths (fp, (*fi)->cwi);
1224 if ((error != AFM_earlyEOF) && (code < 0))
1227 /* The remaining sections of the AFM are optional. This code will */
1228 /* look at the next keyword in the file to determine what section */
1229 /* is next, and then allocate the appropriate amount of storage */
1230 /* for the data (if the data is to be saved) and call the */
1231 /* appropriate parsing routine to parse the section. */
1233 while ((code != normalEOF) && (code != AFM_earlyEOF))
1235 keyword = token (fp);
1236 if (keyword == NULL)
1237 /* Have reached an early and unexpected EOF. */
1238 /* Set flag and stop parsing */
1240 code = AFM_earlyEOF;
1241 break; /* get out of loop */
1243 switch (recognize (keyword))
1249 case STARTTRACKKERN:
1250 keyword = token (fp);
1253 (*fi)->numOfTracks = atoi (keyword);
1254 (*fi)->tkd = (AFM_TrackKernData *)
1255 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1256 if ((*fi)->tkd == NULL)
1258 error = AFM_storageProblem;
1262 code = parseAFM_TrackKernData (fp, *fi);
1264 case STARTKERNPAIRS:
1265 keyword = token (fp);
1268 (*fi)->numOfPairs = atoi (keyword);
1269 (*fi)->pkd = (AFM_PairKernData *)
1270 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1271 if ((*fi)->pkd == NULL)
1273 error = AFM_storageProblem;
1277 code = parseAFM_PairKernData (fp, *fi);
1279 case STARTCOMPOSITES:
1280 keyword = token (fp);
1283 (*fi)->numOfComps = atoi (keyword);
1284 (*fi)->ccd = (AFM_CompCharData *)
1285 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1286 if ((*fi)->ccd == NULL)
1288 error = AFM_storageProblem;
1292 code = parseAFM_CompCharData (fp, *fi);
1294 case ENDFONTMETRICS:
1299 code = AFM_parseError;
1303 if ((error != AFM_earlyEOF) && (code < 0))
1308 if ((error != AFM_earlyEOF) && (code < 0))
1311 if (ident != NULL) { free (ident); ident = NULL; }