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.
20 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
22 * This file may be freely copied and redistributed as long as:
23 * 1) This entire notice continues to be included in the file,
24 * 2) If the file has been modified in any way, a notice of such
25 * modification is conspicuously indicated.
27 * PostScript, Display PostScript, and Adobe are registered trademarks of
28 * Adobe Systems Incorporated.
30 * ************************************************************************
31 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
32 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
33 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
34 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
35 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
36 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
38 * ************************************************************************
43 * This file is used in conjuction with the parseAFM.h header file.
44 * This file contains several procedures that are used to parse AFM
45 * files. It is intended to work with an application program that needs
46 * font metric information. The program can be used as is by making a
47 * procedure call to "parseFile" (passing in the expected parameters)
48 * and having it fill in a data structure with the data from the
49 * AFM file, or an application developer may wish to customize this
52 * There is also a file, parseAFMclient.c, that is a sample application
53 * showing how to call the "parseFile" procedure and how to use the data
54 * after "parseFile" has returned.
56 * Please read the comments in parseAFM.h and parseAFMclient.c.
59 * original: DSM Thu Oct 20 17:39:59 PDT 1988
60 * modified: DSM Mon Jul 3 14:17:50 PDT 1989
61 * - added 'storageProblem' return code
62 * - fixed bug of not allocating extra byte for string duplication
64 * modified: DSM Tue Apr 3 11:18:34 PDT 1990
65 * - added free (ident) at end of parseFile routine
66 * modified: DSM Tue Jun 19 10:16:29 PDT 1990
67 * - changed (width == 250) to (width = 250) in initializeArray
70 #include "parse-afm.hh"
81 /* your basic constants */
84 #define EOL '\n' /* end-of-line indicator */
85 #define MAX_NAME 4096 /* max length for identifiers */
87 /* Flags that can be AND'ed together to specify exactly what
88 * information from the AFM file should be saved.
90 #define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
91 #define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
92 #define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
93 #define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
94 #define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
95 #define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
97 /* Commonly used flags
106 (P_G | P_M | P_P | P_T)
108 (P_G | P_M | P_P | P_T | P_C)
110 #define METATYPE1_BUG /* Parse Metatype1's (version unknown)
111 'Generated' global tag as comment. */
113 #define lineterm EOL /* line terminating character */
114 #define lineterm_alt '\r' /* alternative line terminating character */
115 #define normalEOF 1 /* return code from parsing routines used only */
117 #define Space "space" /* used in string comparison to look for the width */
118 /* of the space character to init the widths array */
119 #define False "false" /* used in string comparison to check the value of */
120 /* boolean keys (e.g. IsFixedPitch) */
122 #define MATCH(A, B) (strncmp ((A), (B), MAX_NAME) == 0)
124 /*************************** GLOBALS ***********************/
126 static char *ident = NULL; /* storage buffer for keywords */
128 /* "shorts" for fast case statement
129 * The values of each of these enumerated items correspond to an entry in the
130 * table of strings defined below. Therefore, if you add a new string as
131 * new keyword into the keyStrings table, you must also add a corresponding
132 * parseKey AND it MUST be in the same position!
134 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
135 * keywords must be placed in lexicographical order, below. [Therefore, the
136 * enumerated items are not necessarily in lexicographical order, depending
137 * on the name chosen. BUT, they must be placed in the same position as the
138 * corresponding key string.] The NOPE shall remain in the last position,
139 * since it does not correspond to any key string, and it is used in the
140 * "recognize" procedure to calculate how many possible keys there are.
145 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
146 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
147 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
148 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME,
153 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
154 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
155 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
156 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
157 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
160 /* keywords for the system:
161 * This a table of all of the current strings that are vaild AFM keys.
162 * Each entry can be referenced by the appropriate parseKey value (an
163 * enumerated data type defined above). If you add a new keyword here,
164 * a corresponding parseKey MUST be added to the enumerated data type
165 * defined above, AND it MUST be added in the same position as the
166 * string is in this table.
168 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
169 * must be placed in lexicographical order. And, NULL should remain at the
173 static char *keyStrings[]
175 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
176 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
177 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
178 "FamilyName", "FontBBox", "FontName", "FullName",
183 "ItalicAngle", "KP", "KPX", "L", "N",
184 "Notice", "PCC", "StartCharMetrics", "StartComposites",
185 "StartFontMetrics", "StartKernData", "StartKernPairs",
186 "StartTrackKern", "TrackKern", "UnderlinePosition",
187 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
190 /*************************** PARSING ROUTINES **************/
192 /*************************** token *************************/
194 /* A "AFM File Conventions" tokenizer. That means that it will
195 * return the next token delimited by white space. See also
196 * the `linetoken' routine, which does a similar thing but
197 * reads all tokens until the next end-of-line.
205 /* skip over white space */
206 while ((ch = fgetc (stream)) == ' ' || ch == lineterm
207 || ch == lineterm_alt
208 || ch == ',' || ch == '\t' || ch == ';');
211 while (idx < MAX_NAME - 1
212 && ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
213 && ch != '\t' && ch != ':' && ch != ';')
219 if (ch == EOF && idx < 1) return ((char *)NULL);
220 if (idx >= 1 && ch != ':') ungetc (ch, stream);
221 if (idx < 1) ident[idx++] = ch; /* single-character token */
224 return (ident); /* returns pointer to the token */
227 /*************************** linetoken *************************/
229 /* "linetoken" will get read all tokens until the EOL character from
230 * the given stream. This is used to get any arguments that can be
231 * more than one word (like Comment lines and FullName).
235 linetoken (FILE *stream)
239 while ((ch = fgetc (stream)) == ' ' || ch == '\t');
242 while (idx < MAX_NAME - 1
243 && ch != EOF && ch != lineterm && ch != lineterm_alt)
252 return (ident); /* returns pointer to the token */
255 /*************************** recognize *************************/
257 /* This function tries to match a string to a known list of
258 * valid AFM entries (check the keyStrings array above).
259 * "ident" contains everything from white space through the
260 * next space, tab, or ":" character.
262 * The algorithm is a standard Knuth binary search.
266 recognize (register char *ident)
274 while ((upper >= lower) && !found)
276 midpoint = (lower + upper) / 2;
277 if (keyStrings[midpoint] == NULL)
279 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
284 upper = midpoint - 1;
286 lower = midpoint + 1;
290 return (enum parseKey) midpoint;
295 /************************* parseGlobals *****************************/
297 /* This function is called by "parseFile". It will parse the AFM File
298 * up to the "StartCharMetrics" keyword, which essentially marks the
299 * end of the Global Font Information and the beginning of the character
300 * metrics information.
302 * If the caller of "parseFile" specified that it wanted the Global
303 * Font Information (as defined by the "AFM File Specification"
304 * document), then that information will be stored in the returned
307 * Any Global Font Information entries that are not found in a
308 * given file, will have the usual default initialization value
309 * for its type (i.e. entries of type int will be 0, etc).
311 * This function returns an error code specifying whether there was
312 * a premature EOF or a parsing error. This return value is used by
313 * parseFile to determine if there is more file to parse.
317 parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
319 BOOL cont = TRUE, save = (gfi != NULL);
321 register char *keyword;
325 keyword = token (fp);
328 /* Have reached an early and unexpected EOF. */
329 /* Set flag and stop parsing */
331 error = AFM_earlyEOF;
332 break; /* get out of loop */
335 /* get tokens until the end of the Global Font info section */
336 /* without saving any of the data */
337 switch (recognize (keyword))
339 case STARTCHARMETRICS:
350 /* otherwise parse entire global font info section, */
351 /* saving the data */
352 switch (recognize (keyword))
354 case STARTFONTMETRICS:
355 keyword = token (fp);
356 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
357 strcpy (gfi->afmVersion, keyword);
363 keyword = linetoken (fp);
366 keyword = token (fp);
367 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
368 strcpy (gfi->fontName, keyword);
371 keyword = token (fp);
372 gfi->encodingScheme = (char *)
373 malloc (strlen (keyword) + 1);
374 strcpy (gfi->encodingScheme, keyword);
377 keyword = linetoken (fp);
378 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
379 strcpy (gfi->fullName, keyword);
382 keyword = linetoken (fp);
383 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
384 strcpy (gfi->familyName, keyword);
387 keyword = token (fp);
388 gfi->weight = (char *) malloc (strlen (keyword) + 1);
389 strcpy (gfi->weight, keyword);
392 keyword = token (fp);
393 gfi->italicAngle = atof (keyword);
394 if (errno == ERANGE) error = AFM_parseError;
397 keyword = token (fp);
398 if (MATCH (keyword, False))
399 gfi->isFixedPitch = 0;
401 gfi->isFixedPitch = 1;
403 case UNDERLINEPOSITION:
404 keyword = token (fp);
405 gfi->underlinePosition = atoi (keyword);
407 case UNDERLINETHICKNESS:
408 keyword = token (fp);
409 gfi->underlineThickness = atoi (keyword);
412 keyword = linetoken (fp);
413 gfi->version = (char *) malloc (strlen (keyword) + 1);
414 strcpy (gfi->version, keyword);
417 keyword = linetoken (fp);
418 gfi->notice = (char *) malloc (strlen (keyword) + 1);
419 strcpy (gfi->notice, keyword);
422 keyword = token (fp);
423 gfi->fontBBox.llx = atoi (keyword);
424 keyword = token (fp);
425 gfi->fontBBox.lly = atoi (keyword);
426 keyword = token (fp);
427 gfi->fontBBox.urx = atoi (keyword);
428 keyword = token (fp);
429 gfi->fontBBox.ury = atoi (keyword);
432 keyword = token (fp);
433 gfi->capHeight = atoi (keyword);
436 keyword = token (fp);
437 gfi->xHeight = atoi (keyword);
440 keyword = token (fp);
441 gfi->descender = atoi (keyword);
444 keyword = token (fp);
445 gfi->ascender = atoi (keyword);
447 case STARTCHARMETRICS:
456 error = AFM_parseError;
465 /************************* initializeArray ************************/
467 /* Unmapped character codes are (at Adobe Systems) assigned the
468 * width of the space character (if one exists) else they get the
469 * value of 250 ems. This function initializes all entries in the
470 * char widths array to have this value. Then any mapped character
471 * codes will be replaced with the width of the appropriate character
472 * when parsing the character metric section.
474 * This function parses the Character Metrics Section looking
475 * for a space character (by comparing character names). If found,
476 * the width of the space character will be used to initialize the
477 * values in the array of character widths.
479 * Before returning, the position of the read/write pointer of the
480 * file is reset to be where it was upon entering this function.
484 initializeArray (FILE *fp, register int *cwi)
486 BOOL cont = TRUE, found = FALSE;
487 long opos = ftell (fp);
488 int code = 0, width = 0, i = 0, error = 0;
489 register char *keyword;
493 keyword = token (fp);
496 error = AFM_earlyEOF;
497 break; /* get out of loop */
499 switch (recognize (keyword))
502 keyword = linetoken (fp);
505 code = atoi (token (fp));
508 width = atoi (token (fp));
511 keyword = token (fp);
512 if (MATCH (keyword, Space))
527 error = AFM_parseError;
535 for (i = 0; i < 256; ++i)
541 } /* initializeArray */
544 /************************* parseCharWidths **************************/
546 /* This function is called by "parseFile". It will parse the AFM File
547 * up to the "EndCharMetrics" keyword. It will save the character
548 * width info (as opposed to all of the character metric information)
549 * if requested by the caller of parseFile. Otherwise, it will just
550 * parse through the section without saving any information.
552 * If data is to be saved, parseCharWidths is passed in a pointer
553 * to an array of widths that has already been initialized by the
554 * standard value for unmapped character codes. This function parses
555 * the Character Metrics section only storing the width information
556 * for the encoded characters into the array using the character code
557 * as the index into that array.
559 * This function returns an error code specifying whether there was
560 * a premature EOF or a parsing error. This return value is used by
561 * parseFile to determine if there is more file to parse.
565 parseCharWidths (FILE *fp, register int *cwi)
567 BOOL cont = TRUE, save = (cwi != NULL);
568 int pos = 0, error = AFM_ok;
569 register char *keyword;
573 keyword = token (fp);
574 /* Have reached an early and unexpected EOF. */
575 /* Set flag and stop parsing */
578 error = AFM_earlyEOF;
579 break; /* get out of loop */
582 /* get tokens until the end of the Char Metrics section without */
583 /* saving any of the data*/
584 switch (recognize (keyword))
597 /* otherwise parse entire char metrics section, saving */
598 /* only the char x-width info */
599 switch (recognize (keyword))
602 keyword = linetoken (fp);
605 keyword = token (fp);
606 pos = atoi (keyword);
609 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
610 keyword = token (fp); keyword = token (fp); /* eat values */
611 error = AFM_parseError;
614 keyword = token (fp);
615 if (pos >= 0) /* ignore unmapped chars */
616 cwi[pos] = atoi (keyword);
625 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
626 keyword = token (fp);
629 keyword = token (fp); keyword = token (fp);
630 keyword = token (fp); keyword = token (fp);
633 keyword = token (fp); keyword = token (fp);
637 error = AFM_parseError;
643 } /* parseCharWidths */
645 /************************* parseCharMetrics ************************/
647 /* This function is called by parseFile if the caller of parseFile
648 * requested that all character metric information be saved
649 * (as opposed to only the character width information).
651 * parseCharMetrics is passed in a pointer to an array of records
652 * to hold information on a per character basis. This function
653 * parses the Character Metrics section storing all character
654 * metric information for the ALL characters (mapped and unmapped)
657 * This function returns an error code specifying whether there was
658 * a premature EOF or a parsing error. This return value is used by
659 * parseFile to determine if there is more file to parse.
663 parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
665 BOOL cont = TRUE, firstTime = TRUE;
666 int error = AFM_ok, count = 0;
667 register AFM_CharMetricInfo *temp = fi->cmi;
668 register char *keyword;
672 keyword = token (fp);
675 error = AFM_earlyEOF;
676 break; /* get out of loop */
678 switch (recognize (keyword))
681 keyword = linetoken (fp);
684 if (count < fi->numOfChars)
690 temp->code = atoi (token (fp));
695 warning ("Too many metrics.");
696 error = AFM_parseError;
701 temp->wx = atoi (token (fp));
702 temp->wy = atoi (token (fp));
705 temp->wx = atoi (token (fp));
709 keyword = token (fp);
710 temp->name = (char *) malloc (strlen (keyword) + 1);
711 strcpy (temp->name, keyword);
715 temp->charBBox.llx = atoi (token (fp));
716 temp->charBBox.lly = atoi (token (fp));
717 temp->charBBox.urx = atoi (token (fp));
718 temp->charBBox.ury = atoi (token (fp));
723 AFM_Ligature **tail = &(temp->ligs);
724 AFM_Ligature *node = *tail;
728 while (node->next != NULL)
730 tail = &(node->next);
733 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
734 keyword = token (fp);
735 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
736 strcpy ((*tail)->succ, keyword);
737 keyword = token (fp);
738 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
739 strcpy ((*tail)->lig, keyword);
750 warning ("Unknown token");
752 error = AFM_parseError;
757 if ((error == AFM_ok) && (count != fi->numOfChars))
759 warning ("Incorrect char count");
760 error = AFM_parseError;
763 } /* parseCharMetrics */
765 /************************* parseAFM_TrackKernData ***********************/
767 /* This function is called by "parseFile". It will parse the AFM File
768 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
769 * track kerning data if requested by the caller of parseFile.
771 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
772 * If data is to be saved, the FontInfo record will already contain
773 * a valid pointer to storage for the track kerning data.
775 * This function returns an error code specifying whether there was
776 * a premature EOF or a parsing error. This return value is used by
777 * parseFile to determine if there is more file to parse.
781 parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
783 BOOL cont = TRUE, save = (fi->tkd != NULL);
784 int pos = 0, error = AFM_ok, tcount = 0;
785 register char *keyword;
789 keyword = token (fp);
793 error = AFM_earlyEOF;
794 break; /* get out of loop */
797 /* get tokens until the end of the Track Kerning Data */
798 /* section without saving any of the data */
799 switch (recognize (keyword))
813 /* otherwise parse entire Track Kerning Data section, */
814 /* saving the data */
815 switch (recognize (keyword))
821 keyword = linetoken (fp);
824 if (tcount < fi->numOfTracks)
826 keyword = token (fp);
827 fi->tkd[pos].degree = atoi (keyword);
828 keyword = token (fp);
829 fi->tkd[pos].minPtSize = atof (keyword);
830 if (errno == ERANGE) error = AFM_parseError;
831 keyword = token (fp);
832 fi->tkd[pos].minKernAmt = atof (keyword);
833 if (errno == ERANGE) error = AFM_parseError;
834 keyword = token (fp);
835 fi->tkd[pos].maxPtSize = atof (keyword);
836 if (errno == ERANGE) error = AFM_parseError;
837 keyword = token (fp);
838 fi->tkd[pos++].maxKernAmt = atof (keyword);
839 if (errno == ERANGE) error = AFM_parseError;
844 error = AFM_parseError;
858 error = AFM_parseError;
863 if (error == AFM_ok && tcount != fi->numOfTracks)
864 error = AFM_parseError;
867 } /* parseAFM_TrackKernData */
869 /************************* parseAFM_PairKernData ************************/
871 /* This function is called by "parseFile". It will parse the AFM File
872 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
873 * the pair kerning data if requested by the caller of parseFile.
875 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
876 * If data is to be saved, the FontInfo record will already contain
877 * a valid pointer to storage for the pair kerning data.
879 * This function returns an error code specifying whether there was
880 * a premature EOF or a parsing error. This return value is used by
881 * parseFile to determine if there is more file to parse.
885 parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
887 BOOL cont = TRUE, save = (fi->pkd != NULL);
888 int pos = 0, error = AFM_ok, pcount = 0;
889 register char *keyword;
893 keyword = token (fp);
897 error = AFM_earlyEOF;
898 break; /* get out of loop */
901 /* get tokens until the end of the Pair Kerning Data */
902 /* section without saving any of the data */
903 switch (recognize (keyword))
917 /* otherwise parse entire Pair Kerning Data section, */
918 /* saving the data */
919 switch (recognize (keyword))
922 keyword = linetoken (fp);
925 if (pcount < fi->numOfPairs)
927 keyword = token (fp);
928 fi->pkd[pos].name1 = (char *)
929 malloc (strlen (keyword) + 1);
930 strcpy (fi->pkd[pos].name1, keyword);
931 keyword = token (fp);
932 fi->pkd[pos].name2 = (char *)
933 malloc (strlen (keyword) + 1);
934 strcpy (fi->pkd[pos].name2, keyword);
935 keyword = token (fp);
936 fi->pkd[pos].xamt = atoi (keyword);
937 keyword = token (fp);
938 fi->pkd[pos++].yamt = atoi (keyword);
943 error = AFM_parseError;
948 if (pcount < fi->numOfPairs)
950 keyword = token (fp);
951 fi->pkd[pos].name1 = (char *)
952 malloc (strlen (keyword) + 1);
953 strcpy (fi->pkd[pos].name1, keyword);
954 keyword = token (fp);
955 fi->pkd[pos].name2 = (char *)
956 malloc (strlen (keyword) + 1);
957 strcpy (fi->pkd[pos].name2, keyword);
958 keyword = token (fp);
959 fi->pkd[pos++].xamt = atoi (keyword);
964 error = AFM_parseError;
978 error = AFM_parseError;
983 if (error == AFM_ok && pcount != fi->numOfPairs)
984 error = AFM_parseError;
987 } /* parseAFM_PairKernData */
989 /************************* parseAFM_CompCharData **************************/
991 /* This function is called by "parseFile". It will parse the AFM File
992 * up to the "EndComposites" keyword. It will save the composite
993 * character data if requested by the caller of parseFile.
995 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
996 * a boolean representing if the data should be saved.
998 * This function will create the appropriate amount of storage for
999 * the composite character data and store a pointer to the storage
1000 * in the FontInfo record.
1002 * This function returns an error code specifying whether there was
1003 * a premature EOF or a parsing error. This return value is used by
1004 * parseFile to determine if there is more file to parse.
1008 parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
1010 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
1011 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
1012 register char *keyword;
1016 keyword = token (fp);
1017 if (keyword == NULL)
1018 /* Have reached an early and unexpected EOF. */
1019 /* Set flag and stop parsing */
1021 error = AFM_earlyEOF;
1022 break; /* get out of loop */
1024 if (ccount > fi->numOfComps)
1026 error = AFM_parseError;
1027 break; /* get out of loop */
1030 /* get tokens until the end of the Composite Character info */
1031 /* section without saving any of the data */
1032 switch (recognize (keyword))
1037 case ENDFONTMETRICS:
1045 /* otherwise parse entire Composite Character info section, */
1046 /* saving the data */
1047 switch (recognize (keyword))
1050 keyword = linetoken (fp);
1053 if (ccount < fi->numOfComps)
1055 keyword = token (fp);
1056 if (pcount != fi->ccd[pos].numOfPieces)
1057 error = AFM_parseError;
1059 if (firstTime) firstTime = FALSE;
1061 fi->ccd[pos].ccName = (char *)
1062 malloc (strlen (keyword) + 1);
1063 strcpy (fi->ccd[pos].ccName, keyword);
1064 keyword = token (fp);
1065 fi->ccd[pos].numOfPieces = atoi (keyword);
1066 fi->ccd[pos].pieces = (AFM_Pcc *)
1067 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1073 error = AFM_parseError;
1078 if (pcount < fi->ccd[pos].numOfPieces)
1080 keyword = token (fp);
1081 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1082 malloc (strlen (keyword) + 1);
1083 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1084 keyword = token (fp);
1085 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1086 keyword = token (fp);
1087 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1091 error = AFM_parseError;
1096 case ENDFONTMETRICS:
1102 error = AFM_parseError;
1107 if (error == AFM_ok && ccount != fi->numOfComps)
1108 error = AFM_parseError;
1111 } /* parseAFM_CompCharData */
1113 /*************************** 'PUBLIC' FUNCTION ********************/
1116 AFM_free (AFM_Font_info *fi)
1120 free (fi->gfi->afmVersion);
1121 free (fi->gfi->fontName);
1122 free (fi->gfi->fullName);
1123 free (fi->gfi->familyName);
1124 free (fi->gfi->weight);
1125 free (fi->gfi->version);
1126 free (fi->gfi->notice);
1127 free (fi->gfi->encodingScheme);
1131 /* This contains just scalars. */
1137 for (i = 0; i < fi->numOfChars; i++)
1139 free (fi->cmi[i].name);
1140 while (fi->cmi[i].ligs)
1143 tmp = fi->cmi[i].ligs;
1147 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1153 /* This contains just scalars. */
1159 for (i = 0; i < fi->numOfPairs; i++)
1161 free (fi->pkd[i].name1);
1162 free (fi->pkd[i].name2);
1170 for (i = 0; i < fi->numOfComps; i++)
1172 free (fi->ccd[i].ccName);
1173 for (j = 0; j < fi->ccd[i].numOfPieces; j++)
1174 free (fi->ccd[i].pieces[j].AFM_PccName);
1175 free (fi->ccd[i].pieces);
1183 /*************************** parseFile *****************************/
1185 /* parseFile is the only 'public' procedure available. It is called
1186 * from an application wishing to get information from an AFM file.
1187 * The caller of this function is responsible for locating and opening
1188 * an AFM file and handling all errors associated with that task.
1190 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1191 * to a (FontInfo *) variable (for which storage will be allocated and
1192 * the data requested filled in), and a mask specifying which
1193 * data from the AFM File should be saved in the FontInfo structure.
1195 * The file will be parsed and the requested data will be stored in
1196 * a record of type FontInfo (refer to ParseAFM.h).
1198 * parseFile returns an error code as defined in parseAFM.h.
1200 * The position of the read/write pointer associated with the file
1201 * pointer upon return of this function is undefined.
1205 AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1208 int code = AFM_ok; /* return code from each of the parsing routines */
1209 int error = AFM_ok; /* used as the return code from this function */
1211 register char *keyword; /* used to store a token */
1213 /* storage data for the global variable ident */
1215 ident = (char *) calloc (MAX_NAME, sizeof (char));
1218 error = AFM_storageProblem;
1222 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1225 error = AFM_storageProblem;
1231 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1,
1232 sizeof (AFM_GlobalFontInfo));
1233 if ((*fi)->gfi == NULL)
1235 error = AFM_storageProblem;
1240 /* The AFM File begins with Global Font Information. This section */
1241 /* will be parsed whether or not information should be saved. */
1242 code = parseGlobals (fp, (*fi)->gfi);
1247 /* The Global Font Information is followed by the Character Metrics */
1248 /* section. Which procedure is used to parse this section depends on */
1249 /* how much information should be saved. If all of the metrics info */
1250 /* is wanted, parseCharMetrics is called. If only the character widths */
1251 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1252 /* be called in the case that no character data is to be saved, just */
1253 /* to parse through the section. */
1255 if ((code != normalEOF) && (code != AFM_earlyEOF))
1257 (*fi)->numOfChars = atoi (token (fp));
1258 if (flags & (P_M ^ P_W))
1260 (*fi)->cmi = (AFM_CharMetricInfo *)
1261 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1262 if ((*fi)->cmi == NULL)
1264 error = AFM_storageProblem;
1267 code = parseCharMetrics (fp, *fi);
1273 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1274 if ((*fi)->cwi == NULL)
1276 error = AFM_storageProblem;
1280 /* parse section regardless */
1281 code = parseCharWidths (fp, (*fi)->cwi);
1285 if ((error != AFM_earlyEOF) && (code < 0))
1288 /* The remaining sections of the AFM are optional. This code will */
1289 /* look at the next keyword in the file to determine what section */
1290 /* is next, and then allocate the appropriate amount of storage */
1291 /* for the data (if the data is to be saved) and call the */
1292 /* appropriate parsing routine to parse the section. */
1294 while ((code != normalEOF) && (code != AFM_earlyEOF))
1296 keyword = token (fp);
1297 if (keyword == NULL)
1298 /* Have reached an early and unexpected EOF. */
1299 /* Set flag and stop parsing */
1301 code = AFM_earlyEOF;
1302 break; /* get out of loop */
1304 switch (recognize (keyword))
1310 case STARTTRACKKERN:
1311 keyword = token (fp);
1314 (*fi)->numOfTracks = atoi (keyword);
1315 (*fi)->tkd = (AFM_TrackKernData *)
1316 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1317 if ((*fi)->tkd == NULL)
1319 error = AFM_storageProblem;
1323 code = parseAFM_TrackKernData (fp, *fi);
1325 case STARTKERNPAIRS:
1326 keyword = token (fp);
1329 (*fi)->numOfPairs = atoi (keyword);
1330 (*fi)->pkd = (AFM_PairKernData *)
1331 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1332 if ((*fi)->pkd == NULL)
1334 error = AFM_storageProblem;
1338 code = parseAFM_PairKernData (fp, *fi);
1340 case STARTCOMPOSITES:
1341 keyword = token (fp);
1344 (*fi)->numOfComps = atoi (keyword);
1345 (*fi)->ccd = (AFM_CompCharData *)
1346 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1347 if ((*fi)->ccd == NULL)
1349 error = AFM_storageProblem;
1353 code = parseAFM_CompCharData (fp, *fi);
1355 case ENDFONTMETRICS:
1360 code = AFM_parseError;
1364 if ((error != AFM_earlyEOF) && (code < 0))
1368 if ((error != AFM_earlyEOF) && (code < 0))
1371 if (ident != NULL) { free (ident); ident = NULL; }