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
71 #include "parse-afm.hh"
82 /* your basic constants */
85 #define EOL '\n' /* end-of-line indicator */
86 #define MAX_NAME 4096 /* max length for identifiers */
90 /* Flags that can be AND'ed together to specify exactly what
91 * information from the AFM file should be saved.
93 #define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
94 #define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
95 #define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
96 #define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
97 #define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
98 #define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
101 /* Commonly used flags
110 (P_G | P_M | P_P | P_T)
112 (P_G | P_M | P_P | P_T | P_C)
114 #define METATYPE1_BUG /* Parse Metatype1's (version unknown)
115 'Generated' global tag as comment. */
117 #define lineterm EOL /* line terminating character */
118 #define lineterm_alt '\r' /* alternative line terminating character */
119 #define normalEOF 1 /* return code from parsing routines used only */
121 #define Space "space" /* used in string comparison to look for the width */
122 /* of the space character to init the widths array */
123 #define False "false" /* used in string comparison to check the value of */
124 /* boolean keys (e.g. IsFixedPitch) */
126 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
130 /*************************** GLOBALS ***********************/
132 static char *ident = NULL; /* storage buffer for keywords */
135 /* "shorts" for fast case statement
136 * The values of each of these enumerated items correspond to an entry in the
137 * table of strings defined below. Therefore, if you add a new string as
138 * new keyword into the keyStrings table, you must also add a corresponding
139 * parseKey AND it MUST be in the same position!
141 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
142 * keywords must be placed in lexicographical order, below. [Therefore, the
143 * enumerated items are not necessarily in lexicographical order, depending
144 * on the name chosen. BUT, they must be placed in the same position as the
145 * corresponding key string.] The NOPE shall remain in the last position,
146 * since it does not correspond to any key string, and it is used in the
147 * "recognize" procedure to calculate how many possible keys there are.
151 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
152 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
153 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
154 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME,
159 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
160 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
161 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
162 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
163 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
166 /* keywords for the system:
167 * This a table of all of the current strings that are vaild AFM keys.
168 * Each entry can be referenced by the appropriate parseKey value (an
169 * enumerated data type defined above). If you add a new keyword here,
170 * a corresponding parseKey MUST be added to the enumerated data type
171 * defined above, AND it MUST be added in the same position as the
172 * string is in this table.
174 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
175 * must be placed in lexicographical order. And, NULL should remain at the
179 static char *keyStrings[] = {
180 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
181 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
182 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
183 "FamilyName", "FontBBox", "FontName", "FullName",
188 "ItalicAngle", "KP", "KPX", "L", "N",
189 "Notice", "PCC", "StartCharMetrics", "StartComposites",
190 "StartFontMetrics", "StartKernData", "StartKernPairs",
191 "StartTrackKern", "TrackKern", "UnderlinePosition",
192 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
195 /*************************** PARSING ROUTINES **************/
197 /*************************** token *************************/
199 /* A "AFM File Conventions" tokenizer. That means that it will
200 * return the next token delimited by white space. See also
201 * the `linetoken' routine, which does a similar thing but
202 * reads all tokens until the next end-of-line.
210 /* skip over white space */
211 while ((ch = fgetc (stream)) == ' ' || ch == lineterm ||
212 ch == lineterm_alt ||
213 ch == ',' || ch == '\t' || ch == ';');
216 while (idx < MAX_NAME - 1 &&
217 ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
218 && ch != '\t' && ch != ':' && ch != ';')
224 if (ch == EOF && idx < 1) return ((char *)NULL);
225 if (idx >= 1 && ch != ':' ) ungetc (ch, stream);
226 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
229 return (ident); /* returns pointer to the token */
234 /*************************** linetoken *************************/
236 /* "linetoken" will get read all tokens until the EOL character from
237 * the given stream. This is used to get any arguments that can be
238 * more than one word (like Comment lines and FullName).
242 linetoken (FILE *stream)
246 while ((ch = fgetc (stream)) == ' ' || ch == '\t' );
249 while (idx < MAX_NAME - 1 &&
250 ch != EOF && ch != lineterm && ch != lineterm_alt)
259 return (ident); /* returns pointer to the token */
264 /*************************** recognize *************************/
266 /* This function tries to match a string to a known list of
267 * valid AFM entries (check the keyStrings array above).
268 * "ident" contains everything from white space through the
269 * next space, tab, or ":" character.
271 * The algorithm is a standard Knuth binary search.
275 recognize (register char *ident)
283 while ((upper >= lower) && !found)
285 midpoint = (lower + upper)/2;
286 if (keyStrings[midpoint] == NULL)
288 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
293 upper = midpoint - 1;
295 lower = midpoint + 1;
299 return (enum parseKey) midpoint;
305 /************************* parseGlobals *****************************/
307 /* This function is called by "parseFile". It will parse the AFM File
308 * up to the "StartCharMetrics" keyword, which essentially marks the
309 * end of the Global Font Information and the beginning of the character
310 * metrics information.
312 * If the caller of "parseFile" specified that it wanted the Global
313 * Font Information (as defined by the "AFM File Specification"
314 * document), then that information will be stored in the returned
317 * Any Global Font Information entries that are not found in a
318 * given file, will have the usual default initialization value
319 * for its type (i.e. entries of type int will be 0, etc).
321 * This function returns an error code specifying whether there was
322 * a premature EOF or a parsing error. This return value is used by
323 * parseFile to determine if there is more file to parse.
327 parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
329 BOOL cont = TRUE, save = (gfi != NULL);
331 register char *keyword;
335 keyword = token (fp);
338 /* Have reached an early and unexpected EOF. */
339 /* Set flag and stop parsing */
341 error = AFM_earlyEOF;
342 break; /* get out of loop */
345 /* get tokens until the end of the Global Font info section */
346 /* without saving any of the data */
347 switch (recognize (keyword))
349 case STARTCHARMETRICS:
360 /* otherwise parse entire global font info section, */
361 /* saving the data */
362 switch (recognize (keyword))
364 case STARTFONTMETRICS:
365 keyword = token (fp);
366 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
367 strcpy (gfi->afmVersion, keyword);
373 keyword = linetoken (fp);
376 keyword = token (fp);
377 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
378 strcpy (gfi->fontName, keyword);
381 keyword = token (fp);
382 gfi->encodingScheme = (char *)
383 malloc (strlen (keyword) + 1);
384 strcpy (gfi->encodingScheme, keyword);
387 keyword = linetoken (fp);
388 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
389 strcpy (gfi->fullName, keyword);
392 keyword = linetoken (fp);
393 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
394 strcpy (gfi->familyName, keyword);
397 keyword = token (fp);
398 gfi->weight = (char *) malloc (strlen (keyword) + 1);
399 strcpy (gfi->weight, keyword);
402 keyword = token (fp);
403 gfi->italicAngle = atof (keyword);
404 if (errno == ERANGE) error = AFM_parseError;
407 keyword = token (fp);
408 if (MATCH (keyword, False))
409 gfi->isFixedPitch = 0;
411 gfi->isFixedPitch = 1;
413 case UNDERLINEPOSITION:
414 keyword = token (fp);
415 gfi->underlinePosition = atoi (keyword);
417 case UNDERLINETHICKNESS:
418 keyword = token (fp);
419 gfi->underlineThickness = atoi (keyword);
422 keyword = linetoken (fp);
423 gfi->version = (char *) malloc (strlen (keyword) + 1);
424 strcpy (gfi->version, keyword);
427 keyword = linetoken (fp);
428 gfi->notice = (char *) malloc (strlen (keyword) + 1);
429 strcpy (gfi->notice, keyword);
432 keyword = token (fp);
433 gfi->fontBBox.llx = atoi (keyword);
434 keyword = token (fp);
435 gfi->fontBBox.lly = atoi (keyword);
436 keyword = token (fp);
437 gfi->fontBBox.urx = atoi (keyword);
438 keyword = token (fp);
439 gfi->fontBBox.ury = atoi (keyword);
442 keyword = token (fp);
443 gfi->capHeight = atoi (keyword);
446 keyword = token (fp);
447 gfi->xHeight = atoi (keyword);
450 keyword = token (fp);
451 gfi->descender = atoi (keyword);
454 keyword = token (fp);
455 gfi->ascender = atoi (keyword);
457 case STARTCHARMETRICS:
466 error = AFM_parseError;
477 /************************* initializeArray ************************/
479 /* Unmapped character codes are (at Adobe Systems) assigned the
480 * width of the space character (if one exists) else they get the
481 * value of 250 ems. This function initializes all entries in the
482 * char widths array to have this value. Then any mapped character
483 * codes will be replaced with the width of the appropriate character
484 * when parsing the character metric section.
486 * This function parses the Character Metrics Section looking
487 * for a space character (by comparing character names). If found,
488 * the width of the space character will be used to initialize the
489 * values in the array of character widths.
491 * Before returning, the position of the read/write pointer of the
492 * file is reset to be where it was upon entering this function.
496 initializeArray (FILE *fp, register int *cwi)
498 BOOL cont = TRUE, found = FALSE;
499 long opos = ftell (fp);
500 int code = 0, width = 0, i = 0, error = 0;
501 register char *keyword;
505 keyword = token (fp);
508 error = AFM_earlyEOF;
509 break; /* get out of loop */
511 switch (recognize (keyword))
514 keyword = linetoken (fp);
517 code = atoi (token (fp));
520 width = atoi (token (fp));
523 keyword = token (fp);
524 if (MATCH (keyword, Space))
539 error = AFM_parseError;
547 for (i = 0; i < 256; ++i)
554 } /* initializeArray */
557 /************************* parseCharWidths **************************/
559 /* This function is called by "parseFile". It will parse the AFM File
560 * up to the "EndCharMetrics" keyword. It will save the character
561 * width info (as opposed to all of the character metric information)
562 * if requested by the caller of parseFile. Otherwise, it will just
563 * parse through the section without saving any information.
565 * If data is to be saved, parseCharWidths is passed in a pointer
566 * to an array of widths that has already been initialized by the
567 * standard value for unmapped character codes. This function parses
568 * the Character Metrics section only storing the width information
569 * for the encoded characters into the array using the character code
570 * as the index into that array.
572 * This function returns an error code specifying whether there was
573 * a premature EOF or a parsing error. This return value is used by
574 * parseFile to determine if there is more file to parse.
578 parseCharWidths (FILE *fp, register int *cwi)
580 BOOL cont = TRUE, save = (cwi != NULL);
581 int pos = 0, error = AFM_ok;
582 register char *keyword;
586 keyword = token (fp);
587 /* Have reached an early and unexpected EOF. */
588 /* Set flag and stop parsing */
591 error = AFM_earlyEOF;
592 break; /* get out of loop */
595 /* get tokens until the end of the Char Metrics section without */
596 /* saving any of the data*/
597 switch (recognize (keyword))
610 /* otherwise parse entire char metrics section, saving */
611 /* only the char x-width info */
612 switch (recognize (keyword))
615 keyword = linetoken (fp);
618 keyword = token (fp);
619 pos = atoi (keyword);
622 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
623 keyword = token (fp); keyword = token (fp); /* eat values */
624 error = AFM_parseError;
627 keyword = token (fp);
628 if (pos >= 0) /* ignore unmapped chars */
629 cwi[pos] = atoi (keyword);
638 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
639 keyword = token (fp);
642 keyword = token (fp); keyword = token (fp);
643 keyword = token (fp); keyword = token (fp);
646 keyword = token (fp); keyword = token (fp);
650 error = AFM_parseError;
657 } /* parseCharWidths */
660 /************************* parseCharMetrics ************************/
662 /* This function is called by parseFile if the caller of parseFile
663 * requested that all character metric information be saved
664 * (as opposed to only the character width information).
666 * parseCharMetrics is passed in a pointer to an array of records
667 * to hold information on a per character basis. This function
668 * parses the Character Metrics section storing all character
669 * metric information for the ALL characters (mapped and unmapped)
672 * This function returns an error code specifying whether there was
673 * a premature EOF or a parsing error. This return value is used by
674 * parseFile to determine if there is more file to parse.
678 parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
680 BOOL cont = TRUE, firstTime = TRUE;
681 int error = AFM_ok, count = 0;
682 register AFM_CharMetricInfo *temp = fi->cmi;
683 register char *keyword;
687 keyword = token (fp);
690 error = AFM_earlyEOF;
691 break; /* get out of loop */
693 switch (recognize (keyword))
696 keyword = linetoken (fp);
699 if (count < fi->numOfChars)
705 temp->code = atoi (token (fp));
710 warning ("Too many metrics.");
711 error = AFM_parseError;
716 temp->wx = atoi (token (fp));
717 temp->wy = atoi (token (fp));
720 temp->wx = atoi (token (fp));
724 keyword = token (fp);
725 temp->name = (char *) malloc (strlen (keyword) + 1);
726 strcpy (temp->name, keyword);
730 temp->charBBox.llx = atoi (token (fp));
731 temp->charBBox.lly = atoi (token (fp));
732 temp->charBBox.urx = atoi (token (fp));
733 temp->charBBox.ury = atoi (token (fp));
737 AFM_Ligature **tail = & (temp->ligs);
738 AFM_Ligature *node = *tail;
742 while (node->next != NULL)
744 tail = & (node->next);
747 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
748 keyword = token (fp);
749 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
750 strcpy ((*tail)->succ, keyword);
751 keyword = token (fp);
752 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
753 strcpy ((*tail)->lig, keyword);
764 warning ("Unknown token");
766 error = AFM_parseError;
771 if ((error == AFM_ok) && (count != fi->numOfChars))
773 warning ("Incorrect char count");
774 error = AFM_parseError;
778 } /* parseCharMetrics */
782 /************************* parseAFM_TrackKernData ***********************/
784 /* This function is called by "parseFile". It will parse the AFM File
785 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
786 * track kerning data if requested by the caller of parseFile.
788 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
789 * If data is to be saved, the FontInfo record will already contain
790 * a valid pointer to storage for the track kerning data.
792 * This function returns an error code specifying whether there was
793 * a premature EOF or a parsing error. This return value is used by
794 * parseFile to determine if there is more file to parse.
798 parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
800 BOOL cont = TRUE, save = (fi->tkd != NULL);
801 int pos = 0, error = AFM_ok, tcount = 0;
802 register char *keyword;
806 keyword = token (fp);
810 error = AFM_earlyEOF;
811 break; /* get out of loop */
814 /* get tokens until the end of the Track Kerning Data */
815 /* section without saving any of the data */
816 switch (recognize (keyword))
830 /* otherwise parse entire Track Kerning Data section, */
831 /* saving the data */
832 switch (recognize (keyword))
838 keyword = linetoken (fp);
841 if (tcount < fi->numOfTracks)
843 keyword = token (fp);
844 fi->tkd[pos].degree = atoi (keyword);
845 keyword = token (fp);
846 fi->tkd[pos].minPtSize = atof (keyword);
847 if (errno == ERANGE) error = AFM_parseError;
848 keyword = token (fp);
849 fi->tkd[pos].minKernAmt = atof (keyword);
850 if (errno == ERANGE) error = AFM_parseError;
851 keyword = token (fp);
852 fi->tkd[pos].maxPtSize = atof (keyword);
853 if (errno == ERANGE) error = AFM_parseError;
854 keyword = token (fp);
855 fi->tkd[pos++].maxKernAmt = atof (keyword);
856 if (errno == ERANGE) error = AFM_parseError;
861 error = AFM_parseError;
875 error = AFM_parseError;
880 if (error == AFM_ok && tcount != fi->numOfTracks)
881 error = AFM_parseError;
885 } /* parseAFM_TrackKernData */
888 /************************* parseAFM_PairKernData ************************/
890 /* This function is called by "parseFile". It will parse the AFM File
891 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
892 * the pair kerning data if requested by the caller of parseFile.
894 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
895 * If data is to be saved, the FontInfo record will already contain
896 * a valid pointer to storage for the pair kerning data.
898 * This function returns an error code specifying whether there was
899 * a premature EOF or a parsing error. This return value is used by
900 * parseFile to determine if there is more file to parse.
904 parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
906 BOOL cont = TRUE, save = (fi->pkd != NULL);
907 int pos = 0, error = AFM_ok, pcount = 0;
908 register char *keyword;
912 keyword = token (fp);
916 error = AFM_earlyEOF;
917 break; /* get out of loop */
920 /* get tokens until the end of the Pair Kerning Data */
921 /* section without saving any of the data */
922 switch (recognize (keyword))
936 /* otherwise parse entire Pair Kerning Data section, */
937 /* saving the data */
938 switch (recognize (keyword))
941 keyword = linetoken (fp);
944 if (pcount < fi->numOfPairs)
946 keyword = token (fp);
947 fi->pkd[pos].name1 = (char *)
948 malloc (strlen (keyword) + 1);
949 strcpy (fi->pkd[pos].name1, keyword);
950 keyword = token (fp);
951 fi->pkd[pos].name2 = (char *)
952 malloc (strlen (keyword) + 1);
953 strcpy (fi->pkd[pos].name2, keyword);
954 keyword = token (fp);
955 fi->pkd[pos].xamt = atoi (keyword);
956 keyword = token (fp);
957 fi->pkd[pos++].yamt = atoi (keyword);
962 error = AFM_parseError;
967 if (pcount < fi->numOfPairs)
969 keyword = token (fp);
970 fi->pkd[pos].name1 = (char *)
971 malloc (strlen (keyword) + 1);
972 strcpy (fi->pkd[pos].name1, keyword);
973 keyword = token (fp);
974 fi->pkd[pos].name2 = (char *)
975 malloc (strlen (keyword) + 1);
976 strcpy (fi->pkd[pos].name2, keyword);
977 keyword = token (fp);
978 fi->pkd[pos++].xamt = atoi (keyword);
983 error = AFM_parseError;
997 error = AFM_parseError;
1002 if (error == AFM_ok && pcount != fi->numOfPairs)
1003 error = AFM_parseError;
1007 } /* parseAFM_PairKernData */
1010 /************************* parseAFM_CompCharData **************************/
1012 /* This function is called by "parseFile". It will parse the AFM File
1013 * up to the "EndComposites" keyword. It will save the composite
1014 * character data if requested by the caller of parseFile.
1016 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
1017 * a boolean representing if the data should be saved.
1019 * This function will create the appropriate amount of storage for
1020 * the composite character data and store a pointer to the storage
1021 * in the FontInfo record.
1023 * This function returns an error code specifying whether there was
1024 * a premature EOF or a parsing error. This return value is used by
1025 * parseFile to determine if there is more file to parse.
1029 parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
1031 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
1032 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
1033 register char *keyword;
1037 keyword = token (fp);
1038 if (keyword == NULL)
1039 /* Have reached an early and unexpected EOF. */
1040 /* Set flag and stop parsing */
1042 error = AFM_earlyEOF;
1043 break; /* get out of loop */
1045 if (ccount > fi->numOfComps)
1047 error = AFM_parseError;
1048 break; /* get out of loop */
1051 /* get tokens until the end of the Composite Character info */
1052 /* section without saving any of the data */
1053 switch (recognize (keyword))
1058 case ENDFONTMETRICS:
1066 /* otherwise parse entire Composite Character info section, */
1067 /* saving the data */
1068 switch (recognize (keyword))
1071 keyword = linetoken (fp);
1074 if (ccount < fi->numOfComps)
1076 keyword = token (fp);
1077 if (pcount != fi->ccd[pos].numOfPieces)
1078 error = AFM_parseError;
1080 if (firstTime) firstTime = FALSE;
1082 fi->ccd[pos].ccName = (char *)
1083 malloc (strlen (keyword) + 1);
1084 strcpy (fi->ccd[pos].ccName, keyword);
1085 keyword = token (fp);
1086 fi->ccd[pos].numOfPieces = atoi (keyword);
1087 fi->ccd[pos].pieces = (AFM_Pcc *)
1088 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1094 error = AFM_parseError;
1099 if (pcount < fi->ccd[pos].numOfPieces)
1101 keyword = token (fp);
1102 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1103 malloc (strlen (keyword) + 1);
1104 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1105 keyword = token (fp);
1106 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1107 keyword = token (fp);
1108 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1112 error = AFM_parseError;
1117 case ENDFONTMETRICS:
1123 error = AFM_parseError;
1128 if (error == AFM_ok && ccount != fi->numOfComps)
1129 error = AFM_parseError;
1133 } /* parseAFM_CompCharData */
1138 /*************************** 'PUBLIC' FUNCTION ********************/
1141 AFM_free (AFM_Font_info *fi)
1144 free (fi->gfi->afmVersion);
1145 free (fi->gfi->fontName);
1146 free (fi->gfi->fullName);
1147 free (fi->gfi->familyName);
1148 free (fi->gfi->weight);
1149 free (fi->gfi->version);
1150 free (fi->gfi->notice);
1151 free (fi->gfi->encodingScheme);
1155 /* This contains just scalars. */
1160 for (i = 0; i < fi->numOfChars; i++) {
1161 free (fi->cmi[i].name);
1162 while (fi->cmi[i].ligs) {
1164 tmp = fi->cmi[i].ligs;
1168 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1174 /* This contains just scalars. */
1179 for (i = 0; i < fi->numOfPairs; i++) {
1180 free (fi->pkd[i].name1);
1181 free (fi->pkd[i].name2);
1188 for (i = 0; i < fi->numOfComps; i++) {
1189 free (fi->ccd[i].ccName);
1190 for (j = 0; j < fi->ccd[i].numOfPieces; j++) {
1191 free (fi->ccd[i].pieces[j].AFM_PccName);
1193 free (fi->ccd[i].pieces);
1202 /*************************** parseFile *****************************/
1204 /* parseFile is the only 'public' procedure available. It is called
1205 * from an application wishing to get information from an AFM file.
1206 * The caller of this function is responsible for locating and opening
1207 * an AFM file and handling all errors associated with that task.
1209 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1210 * to a (FontInfo *) variable (for which storage will be allocated and
1211 * the data requested filled in), and a mask specifying which
1212 * data from the AFM File should be saved in the FontInfo structure.
1214 * The file will be parsed and the requested data will be stored in
1215 * a record of type FontInfo (refer to ParseAFM.h).
1217 * parseFile returns an error code as defined in parseAFM.h.
1219 * The position of the read/write pointer associated with the file
1220 * pointer upon return of this function is undefined.
1224 AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1227 int code = AFM_ok; /* return code from each of the parsing routines */
1228 int error = AFM_ok; /* used as the return code from this function */
1230 register char *keyword; /* used to store a token */
1233 /* storage data for the global variable ident */
1235 ident = (char *) calloc (MAX_NAME, sizeof (char));
1238 error = AFM_storageProblem;
1242 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1245 error = AFM_storageProblem;
1251 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1,
1252 sizeof (AFM_GlobalFontInfo));
1253 if ((*fi)->gfi == NULL)
1255 error = AFM_storageProblem;
1260 /* The AFM File begins with Global Font Information. This section */
1261 /* will be parsed whether or not information should be saved. */
1262 code = parseGlobals (fp, (*fi)->gfi);
1267 /* The Global Font Information is followed by the Character Metrics */
1268 /* section. Which procedure is used to parse this section depends on */
1269 /* how much information should be saved. If all of the metrics info */
1270 /* is wanted, parseCharMetrics is called. If only the character widths */
1271 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1272 /* be called in the case that no character data is to be saved, just */
1273 /* to parse through the section. */
1275 if ((code != normalEOF) && (code != AFM_earlyEOF))
1277 (*fi)->numOfChars = atoi (token (fp));
1278 if (flags & (P_M ^ P_W))
1280 (*fi)->cmi = (AFM_CharMetricInfo *)
1281 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1282 if ((*fi)->cmi == NULL)
1284 error = AFM_storageProblem;
1287 code = parseCharMetrics (fp, *fi);
1293 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1294 if ((*fi)->cwi == NULL)
1296 error = AFM_storageProblem;
1300 /* parse section regardless */
1301 code = parseCharWidths (fp, (*fi)->cwi);
1305 if ((error != AFM_earlyEOF) && (code < 0))
1308 /* The remaining sections of the AFM are optional. This code will */
1309 /* look at the next keyword in the file to determine what section */
1310 /* is next, and then allocate the appropriate amount of storage */
1311 /* for the data (if the data is to be saved) and call the */
1312 /* appropriate parsing routine to parse the section. */
1314 while ((code != normalEOF) && (code != AFM_earlyEOF))
1316 keyword = token (fp);
1317 if (keyword == NULL)
1318 /* Have reached an early and unexpected EOF. */
1319 /* Set flag and stop parsing */
1321 code = AFM_earlyEOF;
1322 break; /* get out of loop */
1324 switch (recognize (keyword))
1330 case STARTTRACKKERN:
1331 keyword = token (fp);
1334 (*fi)->numOfTracks = atoi (keyword);
1335 (*fi)->tkd = (AFM_TrackKernData *)
1336 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1337 if ((*fi)->tkd == NULL)
1339 error = AFM_storageProblem;
1343 code = parseAFM_TrackKernData (fp, *fi);
1345 case STARTKERNPAIRS:
1346 keyword = token (fp);
1349 (*fi)->numOfPairs = atoi (keyword);
1350 (*fi)->pkd = (AFM_PairKernData *)
1351 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1352 if ((*fi)->pkd == NULL)
1354 error = AFM_storageProblem;
1358 code = parseAFM_PairKernData (fp, *fi);
1360 case STARTCOMPOSITES:
1361 keyword = token (fp);
1364 (*fi)->numOfComps = atoi (keyword);
1365 (*fi)->ccd = (AFM_CompCharData *)
1366 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1367 if ((*fi)->ccd == NULL)
1369 error = AFM_storageProblem;
1373 code = parseAFM_CompCharData (fp, *fi);
1375 case ENDFONTMETRICS:
1380 code = AFM_parseError;
1384 if ((error != AFM_earlyEOF) && (code < 0))
1389 if ((error != AFM_earlyEOF) && (code < 0))
1392 if (ident != NULL) { free (ident); ident = NULL; }