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 #define METATYPE1_BUG /* Parse Metatype1's (version unknown)
83 'Generated' global tag as comment. */
85 #define lineterm EOL /* line terminating character */
86 #define lineterm_alt '\r' /* alternative line terminating character */
87 #define normalEOF 1 /* return code from parsing routines used only */
89 #define Space "space" /* used in string comparison to look for the width */
90 /* of the space character to init the widths array */
91 #define False "false" /* used in string comparison to check the value of */
92 /* boolean keys (e.g. IsFixedPitch) */
94 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
98 /*************************** GLOBALS ***********************/
100 static char *ident = NULL; /* storage buffer for keywords */
103 /* "shorts" for fast case statement
104 * The values of each of these enumerated items correspond to an entry in the
105 * table of strings defined below. Therefore, if you add a new string as
106 * new keyword into the keyStrings table, you must also add a corresponding
107 * parseKey AND it MUST be in the same position!
109 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
110 * keywords must be placed in lexicographical order, below. [Therefore, the
111 * enumerated items are not necessarily in lexicographical order, depending
112 * on the name chosen. BUT, they must be placed in the same position as the
113 * corresponding key string.] The NOPE shall remain in the last position,
114 * since it does not correspond to any key string, and it is used in the
115 * "recognize" procedure to calculate how many possible keys there are.
119 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
120 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
121 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
122 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME,
127 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
128 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
129 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
130 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
131 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
134 /* keywords for the system:
135 * This a table of all of the current strings that are vaild AFM keys.
136 * Each entry can be referenced by the appropriate parseKey value (an
137 * enumerated data type defined above). If you add a new keyword here,
138 * a corresponding parseKey MUST be added to the enumerated data type
139 * defined above, AND it MUST be added in the same position as the
140 * string is in this table.
142 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
143 * must be placed in lexicographical order. And, NULL should remain at the
147 static char *keyStrings[] = {
148 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
149 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
150 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
151 "FamilyName", "FontBBox", "FontName", "FullName",
156 "ItalicAngle", "KP", "KPX", "L", "N",
157 "Notice", "PCC", "StartCharMetrics", "StartComposites",
158 "StartFontMetrics", "StartKernData", "StartKernPairs",
159 "StartTrackKern", "TrackKern", "UnderlinePosition",
160 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
163 /*************************** PARSING ROUTINES **************/
165 /*************************** token *************************/
167 /* A "AFM File Conventions" tokenizer. That means that it will
168 * return the next token delimited by white space. See also
169 * the `linetoken' routine, which does a similar thing but
170 * reads all tokens until the next end-of-line.
178 /* skip over white space */
179 while ((ch = fgetc (stream)) == ' ' || ch == lineterm ||
180 ch == lineterm_alt ||
181 ch == ',' || ch == '\t' || ch == ';');
184 while (idx < MAX_NAME - 1 &&
185 ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
186 && ch != '\t' && ch != ':' && ch != ';')
192 if (ch == EOF && idx < 1) return ((char *)NULL);
193 if (idx >= 1 && ch != ':' ) ungetc (ch, stream);
194 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
197 return (ident); /* returns pointer to the token */
202 /*************************** linetoken *************************/
204 /* "linetoken" will get read all tokens until the EOL character from
205 * the given stream. This is used to get any arguments that can be
206 * more than one word (like Comment lines and FullName).
210 linetoken (FILE *stream)
214 while ((ch = fgetc (stream)) == ' ' || ch == '\t' );
217 while (idx < MAX_NAME - 1 &&
218 ch != EOF && ch != lineterm && ch != lineterm_alt)
227 return (ident); /* returns pointer to the token */
232 /*************************** recognize *************************/
234 /* This function tries to match a string to a known list of
235 * valid AFM entries (check the keyStrings array above).
236 * "ident" contains everything from white space through the
237 * next space, tab, or ":" character.
239 * The algorithm is a standard Knuth binary search.
243 recognize (register char *ident)
251 while ((upper >= lower) && !found)
253 midpoint = (lower + upper)/2;
254 if (keyStrings[midpoint] == NULL)
256 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
261 upper = midpoint - 1;
263 lower = midpoint + 1;
267 return (enum parseKey) midpoint;
273 /************************* parseGlobals *****************************/
275 /* This function is called by "parseFile". It will parse the AFM File
276 * up to the "StartCharMetrics" keyword, which essentially marks the
277 * end of the Global Font Information and the beginning of the character
278 * metrics information.
280 * If the caller of "parseFile" specified that it wanted the Global
281 * Font Information (as defined by the "AFM File Specification"
282 * document), then that information will be stored in the returned
285 * Any Global Font Information entries that are not found in a
286 * given file, will have the usual default initialization value
287 * for its type (i.e. entries of type int will be 0, etc).
289 * This function returns an error code specifying whether there was
290 * a premature EOF or a parsing error. This return value is used by
291 * parseFile to determine if there is more file to parse.
295 parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
297 BOOL cont = TRUE, save = (gfi != NULL);
299 register char *keyword;
303 keyword = token (fp);
306 /* Have reached an early and unexpected EOF. */
307 /* Set flag and stop parsing */
309 error = AFM_earlyEOF;
310 break; /* get out of loop */
313 /* get tokens until the end of the Global Font info section */
314 /* without saving any of the data */
315 switch (recognize (keyword))
317 case STARTCHARMETRICS:
328 /* otherwise parse entire global font info section, */
329 /* saving the data */
330 switch (recognize (keyword))
332 case STARTFONTMETRICS:
333 keyword = token (fp);
334 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
335 strcpy (gfi->afmVersion, keyword);
341 keyword = linetoken (fp);
344 keyword = token (fp);
345 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
346 strcpy (gfi->fontName, keyword);
349 keyword = token (fp);
350 gfi->encodingScheme = (char *)
351 malloc (strlen (keyword) + 1);
352 strcpy (gfi->encodingScheme, keyword);
355 keyword = linetoken (fp);
356 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
357 strcpy (gfi->fullName, keyword);
360 keyword = linetoken (fp);
361 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
362 strcpy (gfi->familyName, keyword);
365 keyword = token (fp);
366 gfi->weight = (char *) malloc (strlen (keyword) + 1);
367 strcpy (gfi->weight, keyword);
370 keyword = token (fp);
371 gfi->italicAngle = atof (keyword);
372 if (errno == ERANGE) error = AFM_parseError;
375 keyword = token (fp);
376 if (MATCH (keyword, False))
377 gfi->isFixedPitch = 0;
379 gfi->isFixedPitch = 1;
381 case UNDERLINEPOSITION:
382 keyword = token (fp);
383 gfi->underlinePosition = atoi (keyword);
385 case UNDERLINETHICKNESS:
386 keyword = token (fp);
387 gfi->underlineThickness = atoi (keyword);
390 keyword = linetoken (fp);
391 gfi->version = (char *) malloc (strlen (keyword) + 1);
392 strcpy (gfi->version, keyword);
395 keyword = linetoken (fp);
396 gfi->notice = (char *) malloc (strlen (keyword) + 1);
397 strcpy (gfi->notice, keyword);
400 keyword = token (fp);
401 gfi->fontBBox.llx = atoi (keyword);
402 keyword = token (fp);
403 gfi->fontBBox.lly = atoi (keyword);
404 keyword = token (fp);
405 gfi->fontBBox.urx = atoi (keyword);
406 keyword = token (fp);
407 gfi->fontBBox.ury = atoi (keyword);
410 keyword = token (fp);
411 gfi->capHeight = atoi (keyword);
414 keyword = token (fp);
415 gfi->xHeight = atoi (keyword);
418 keyword = token (fp);
419 gfi->descender = atoi (keyword);
422 keyword = token (fp);
423 gfi->ascender = atoi (keyword);
425 case STARTCHARMETRICS:
434 error = AFM_parseError;
445 /************************* initializeArray ************************/
447 /* Unmapped character codes are (at Adobe Systems) assigned the
448 * width of the space character (if one exists) else they get the
449 * value of 250 ems. This function initializes all entries in the
450 * char widths array to have this value. Then any mapped character
451 * codes will be replaced with the width of the appropriate character
452 * when parsing the character metric section.
454 * This function parses the Character Metrics Section looking
455 * for a space character (by comparing character names). If found,
456 * the width of the space character will be used to initialize the
457 * values in the array of character widths.
459 * Before returning, the position of the read/write pointer of the
460 * file is reset to be where it was upon entering this function.
464 initializeArray (FILE *fp, register int *cwi)
466 BOOL cont = TRUE, found = FALSE;
467 long opos = ftell (fp);
468 int code = 0, width = 0, i = 0, error = 0;
469 register char *keyword;
473 keyword = token (fp);
476 error = AFM_earlyEOF;
477 break; /* get out of loop */
479 switch (recognize (keyword))
482 keyword = linetoken (fp);
485 code = atoi (token (fp));
488 width = atoi (token (fp));
491 keyword = token (fp);
492 if (MATCH (keyword, Space))
507 error = AFM_parseError;
515 for (i = 0; i < 256; ++i)
522 } /* initializeArray */
525 /************************* parseCharWidths **************************/
527 /* This function is called by "parseFile". It will parse the AFM File
528 * up to the "EndCharMetrics" keyword. It will save the character
529 * width info (as opposed to all of the character metric information)
530 * if requested by the caller of parseFile. Otherwise, it will just
531 * parse through the section without saving any information.
533 * If data is to be saved, parseCharWidths is passed in a pointer
534 * to an array of widths that has already been initialized by the
535 * standard value for unmapped character codes. This function parses
536 * the Character Metrics section only storing the width information
537 * for the encoded characters into the array using the character code
538 * as the index into that array.
540 * This function returns an error code specifying whether there was
541 * a premature EOF or a parsing error. This return value is used by
542 * parseFile to determine if there is more file to parse.
546 parseCharWidths (FILE *fp, register int *cwi)
548 BOOL cont = TRUE, save = (cwi != NULL);
549 int pos = 0, error = AFM_ok;
550 register char *keyword;
554 keyword = token (fp);
555 /* Have reached an early and unexpected EOF. */
556 /* Set flag and stop parsing */
559 error = AFM_earlyEOF;
560 break; /* get out of loop */
563 /* get tokens until the end of the Char Metrics section without */
564 /* saving any of the data*/
565 switch (recognize (keyword))
578 /* otherwise parse entire char metrics section, saving */
579 /* only the char x-width info */
580 switch (recognize (keyword))
583 keyword = linetoken (fp);
586 keyword = token (fp);
587 pos = atoi (keyword);
590 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
591 keyword = token (fp); keyword = token (fp); /* eat values */
592 error = AFM_parseError;
595 keyword = token (fp);
596 if (pos >= 0) /* ignore unmapped chars */
597 cwi[pos] = atoi (keyword);
606 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
607 keyword = token (fp);
610 keyword = token (fp); keyword = token (fp);
611 keyword = token (fp); keyword = token (fp);
614 keyword = token (fp); keyword = token (fp);
618 error = AFM_parseError;
625 } /* parseCharWidths */
628 /************************* parseCharMetrics ************************/
630 /* This function is called by parseFile if the caller of parseFile
631 * requested that all character metric information be saved
632 * (as opposed to only the character width information).
634 * parseCharMetrics is passed in a pointer to an array of records
635 * to hold information on a per character basis. This function
636 * parses the Character Metrics section storing all character
637 * metric information for the ALL characters (mapped and unmapped)
640 * This function returns an error code specifying whether there was
641 * a premature EOF or a parsing error. This return value is used by
642 * parseFile to determine if there is more file to parse.
646 parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
648 BOOL cont = TRUE, firstTime = TRUE;
649 int error = AFM_ok, count = 0;
650 register AFM_CharMetricInfo *temp = fi->cmi;
651 register char *keyword;
655 keyword = token (fp);
658 error = AFM_earlyEOF;
659 break; /* get out of loop */
661 switch (recognize (keyword))
664 keyword = linetoken (fp);
667 if (count < fi->numOfChars)
673 temp->code = atoi (token (fp));
678 warning ("Too many metrics.");
679 error = AFM_parseError;
684 temp->wx = atoi (token (fp));
685 temp->wy = atoi (token (fp));
688 temp->wx = atoi (token (fp));
692 keyword = token (fp);
693 temp->name = (char *) malloc (strlen (keyword) + 1);
694 strcpy (temp->name, keyword);
698 temp->charBBox.llx = atoi (token (fp));
699 temp->charBBox.lly = atoi (token (fp));
700 temp->charBBox.urx = atoi (token (fp));
701 temp->charBBox.ury = atoi (token (fp));
705 AFM_Ligature **tail = & (temp->ligs);
706 AFM_Ligature *node = *tail;
710 while (node->next != NULL)
712 tail = & (node->next);
715 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
716 keyword = token (fp);
717 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
718 strcpy ((*tail)->succ, keyword);
719 keyword = token (fp);
720 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
721 strcpy ((*tail)->lig, keyword);
732 warning ("Unknown token");
734 error = AFM_parseError;
739 if ((error == AFM_ok) && (count != fi->numOfChars))
741 warning ("Incorrect char count");
742 error = AFM_parseError;
746 } /* parseCharMetrics */
750 /************************* parseAFM_TrackKernData ***********************/
752 /* This function is called by "parseFile". It will parse the AFM File
753 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
754 * track kerning data if requested by the caller of parseFile.
756 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
757 * If data is to be saved, the FontInfo record will already contain
758 * a valid pointer to storage for the track kerning data.
760 * This function returns an error code specifying whether there was
761 * a premature EOF or a parsing error. This return value is used by
762 * parseFile to determine if there is more file to parse.
766 parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
768 BOOL cont = TRUE, save = (fi->tkd != NULL);
769 int pos = 0, error = AFM_ok, tcount = 0;
770 register char *keyword;
774 keyword = token (fp);
778 error = AFM_earlyEOF;
779 break; /* get out of loop */
782 /* get tokens until the end of the Track Kerning Data */
783 /* section without saving any of the data */
784 switch (recognize (keyword))
798 /* otherwise parse entire Track Kerning Data section, */
799 /* saving the data */
800 switch (recognize (keyword))
806 keyword = linetoken (fp);
809 if (tcount < fi->numOfTracks)
811 keyword = token (fp);
812 fi->tkd[pos].degree = atoi (keyword);
813 keyword = token (fp);
814 fi->tkd[pos].minPtSize = atof (keyword);
815 if (errno == ERANGE) error = AFM_parseError;
816 keyword = token (fp);
817 fi->tkd[pos].minKernAmt = atof (keyword);
818 if (errno == ERANGE) error = AFM_parseError;
819 keyword = token (fp);
820 fi->tkd[pos].maxPtSize = atof (keyword);
821 if (errno == ERANGE) error = AFM_parseError;
822 keyword = token (fp);
823 fi->tkd[pos++].maxKernAmt = atof (keyword);
824 if (errno == ERANGE) error = AFM_parseError;
829 error = AFM_parseError;
843 error = AFM_parseError;
848 if (error == AFM_ok && tcount != fi->numOfTracks)
849 error = AFM_parseError;
853 } /* parseAFM_TrackKernData */
856 /************************* parseAFM_PairKernData ************************/
858 /* This function is called by "parseFile". It will parse the AFM File
859 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
860 * the pair kerning data if requested by the caller of parseFile.
862 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
863 * If data is to be saved, the FontInfo record will already contain
864 * a valid pointer to storage for the pair kerning data.
866 * This function returns an error code specifying whether there was
867 * a premature EOF or a parsing error. This return value is used by
868 * parseFile to determine if there is more file to parse.
872 parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
874 BOOL cont = TRUE, save = (fi->pkd != NULL);
875 int pos = 0, error = AFM_ok, pcount = 0;
876 register char *keyword;
880 keyword = token (fp);
884 error = AFM_earlyEOF;
885 break; /* get out of loop */
888 /* get tokens until the end of the Pair Kerning Data */
889 /* section without saving any of the data */
890 switch (recognize (keyword))
904 /* otherwise parse entire Pair Kerning Data section, */
905 /* saving the data */
906 switch (recognize (keyword))
909 keyword = linetoken (fp);
912 if (pcount < fi->numOfPairs)
914 keyword = token (fp);
915 fi->pkd[pos].name1 = (char *)
916 malloc (strlen (keyword) + 1);
917 strcpy (fi->pkd[pos].name1, keyword);
918 keyword = token (fp);
919 fi->pkd[pos].name2 = (char *)
920 malloc (strlen (keyword) + 1);
921 strcpy (fi->pkd[pos].name2, keyword);
922 keyword = token (fp);
923 fi->pkd[pos].xamt = atoi (keyword);
924 keyword = token (fp);
925 fi->pkd[pos++].yamt = atoi (keyword);
930 error = AFM_parseError;
935 if (pcount < fi->numOfPairs)
937 keyword = token (fp);
938 fi->pkd[pos].name1 = (char *)
939 malloc (strlen (keyword) + 1);
940 strcpy (fi->pkd[pos].name1, keyword);
941 keyword = token (fp);
942 fi->pkd[pos].name2 = (char *)
943 malloc (strlen (keyword) + 1);
944 strcpy (fi->pkd[pos].name2, keyword);
945 keyword = token (fp);
946 fi->pkd[pos++].xamt = atoi (keyword);
951 error = AFM_parseError;
965 error = AFM_parseError;
970 if (error == AFM_ok && pcount != fi->numOfPairs)
971 error = AFM_parseError;
975 } /* parseAFM_PairKernData */
978 /************************* parseAFM_CompCharData **************************/
980 /* This function is called by "parseFile". It will parse the AFM File
981 * up to the "EndComposites" keyword. It will save the composite
982 * character data if requested by the caller of parseFile.
984 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
985 * a boolean representing if the data should be saved.
987 * This function will create the appropriate amount of storage for
988 * the composite character data and store a pointer to the storage
989 * in the FontInfo record.
991 * This function returns an error code specifying whether there was
992 * a premature EOF or a parsing error. This return value is used by
993 * parseFile to determine if there is more file to parse.
997 parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
999 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
1000 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
1001 register char *keyword;
1005 keyword = token (fp);
1006 if (keyword == NULL)
1007 /* Have reached an early and unexpected EOF. */
1008 /* Set flag and stop parsing */
1010 error = AFM_earlyEOF;
1011 break; /* get out of loop */
1013 if (ccount > fi->numOfComps)
1015 error = AFM_parseError;
1016 break; /* get out of loop */
1019 /* get tokens until the end of the Composite Character info */
1020 /* section without saving any of the data */
1021 switch (recognize (keyword))
1026 case ENDFONTMETRICS:
1034 /* otherwise parse entire Composite Character info section, */
1035 /* saving the data */
1036 switch (recognize (keyword))
1039 keyword = linetoken (fp);
1042 if (ccount < fi->numOfComps)
1044 keyword = token (fp);
1045 if (pcount != fi->ccd[pos].numOfPieces)
1046 error = AFM_parseError;
1048 if (firstTime) firstTime = FALSE;
1050 fi->ccd[pos].ccName = (char *)
1051 malloc (strlen (keyword) + 1);
1052 strcpy (fi->ccd[pos].ccName, keyword);
1053 keyword = token (fp);
1054 fi->ccd[pos].numOfPieces = atoi (keyword);
1055 fi->ccd[pos].pieces = (AFM_Pcc *)
1056 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1062 error = AFM_parseError;
1067 if (pcount < fi->ccd[pos].numOfPieces)
1069 keyword = token (fp);
1070 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1071 malloc (strlen (keyword) + 1);
1072 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1073 keyword = token (fp);
1074 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1075 keyword = token (fp);
1076 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1080 error = AFM_parseError;
1085 case ENDFONTMETRICS:
1091 error = AFM_parseError;
1096 if (error == AFM_ok && ccount != fi->numOfComps)
1097 error = AFM_parseError;
1101 } /* parseAFM_CompCharData */
1106 /*************************** 'PUBLIC' FUNCTION ********************/
1109 AFM_free (AFM_Font_info *fi)
1112 free (fi->gfi->afmVersion);
1113 free (fi->gfi->fontName);
1114 free (fi->gfi->fullName);
1115 free (fi->gfi->familyName);
1116 free (fi->gfi->weight);
1117 free (fi->gfi->version);
1118 free (fi->gfi->notice);
1119 free (fi->gfi->encodingScheme);
1123 /* This contains just scalars. */
1128 for (i = 0; i < fi->numOfChars; i++) {
1129 free (fi->cmi[i].name);
1130 while (fi->cmi[i].ligs) {
1132 tmp = fi->cmi[i].ligs;
1136 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1142 /* This contains just scalars. */
1147 for (i = 0; i < fi->numOfPairs; i++) {
1148 free (fi->pkd[i].name1);
1149 free (fi->pkd[i].name2);
1156 for (i = 0; i < fi->numOfComps; i++) {
1157 free (fi->ccd[i].ccName);
1158 for (j = 0; j < fi->ccd[i].numOfPieces; j++) {
1159 free (fi->ccd[i].pieces[j].AFM_PccName);
1161 free (fi->ccd[i].pieces);
1170 /*************************** parseFile *****************************/
1172 /* parseFile is the only 'public' procedure available. It is called
1173 * from an application wishing to get information from an AFM file.
1174 * The caller of this function is responsible for locating and opening
1175 * an AFM file and handling all errors associated with that task.
1177 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1178 * to a (FontInfo *) variable (for which storage will be allocated and
1179 * the data requested filled in), and a mask specifying which
1180 * data from the AFM File should be saved in the FontInfo structure.
1182 * The file will be parsed and the requested data will be stored in
1183 * a record of type FontInfo (refer to ParseAFM.h).
1185 * parseFile returns an error code as defined in parseAFM.h.
1187 * The position of the read/write pointer associated with the file
1188 * pointer upon return of this function is undefined.
1192 AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1195 int code = AFM_ok; /* return code from each of the parsing routines */
1196 int error = AFM_ok; /* used as the return code from this function */
1198 register char *keyword; /* used to store a token */
1201 /* storage data for the global variable ident */
1203 ident = (char *) calloc (MAX_NAME, sizeof (char));
1206 error = AFM_storageProblem;
1210 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1213 error = AFM_storageProblem;
1219 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1,
1220 sizeof (AFM_GlobalFontInfo));
1221 if ((*fi)->gfi == NULL)
1223 error = AFM_storageProblem;
1228 /* The AFM File begins with Global Font Information. This section */
1229 /* will be parsed whether or not information should be saved. */
1230 code = parseGlobals (fp, (*fi)->gfi);
1235 /* The Global Font Information is followed by the Character Metrics */
1236 /* section. Which procedure is used to parse this section depends on */
1237 /* how much information should be saved. If all of the metrics info */
1238 /* is wanted, parseCharMetrics is called. If only the character widths */
1239 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1240 /* be called in the case that no character data is to be saved, just */
1241 /* to parse through the section. */
1243 if ((code != normalEOF) && (code != AFM_earlyEOF))
1245 (*fi)->numOfChars = atoi (token (fp));
1246 if (flags & (P_M ^ P_W))
1248 (*fi)->cmi = (AFM_CharMetricInfo *)
1249 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1250 if ((*fi)->cmi == NULL)
1252 error = AFM_storageProblem;
1255 code = parseCharMetrics (fp, *fi);
1261 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1262 if ((*fi)->cwi == NULL)
1264 error = AFM_storageProblem;
1268 /* parse section regardless */
1269 code = parseCharWidths (fp, (*fi)->cwi);
1273 if ((error != AFM_earlyEOF) && (code < 0))
1276 /* The remaining sections of the AFM are optional. This code will */
1277 /* look at the next keyword in the file to determine what section */
1278 /* is next, and then allocate the appropriate amount of storage */
1279 /* for the data (if the data is to be saved) and call the */
1280 /* appropriate parsing routine to parse the section. */
1282 while ((code != normalEOF) && (code != AFM_earlyEOF))
1284 keyword = token (fp);
1285 if (keyword == NULL)
1286 /* Have reached an early and unexpected EOF. */
1287 /* Set flag and stop parsing */
1289 code = AFM_earlyEOF;
1290 break; /* get out of loop */
1292 switch (recognize (keyword))
1298 case STARTTRACKKERN:
1299 keyword = token (fp);
1302 (*fi)->numOfTracks = atoi (keyword);
1303 (*fi)->tkd = (AFM_TrackKernData *)
1304 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1305 if ((*fi)->tkd == NULL)
1307 error = AFM_storageProblem;
1311 code = parseAFM_TrackKernData (fp, *fi);
1313 case STARTKERNPAIRS:
1314 keyword = token (fp);
1317 (*fi)->numOfPairs = atoi (keyword);
1318 (*fi)->pkd = (AFM_PairKernData *)
1319 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1320 if ((*fi)->pkd == NULL)
1322 error = AFM_storageProblem;
1326 code = parseAFM_PairKernData (fp, *fi);
1328 case STARTCOMPOSITES:
1329 keyword = token (fp);
1332 (*fi)->numOfComps = atoi (keyword);
1333 (*fi)->ccd = (AFM_CompCharData *)
1334 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1335 if ((*fi)->ccd == NULL)
1337 error = AFM_storageProblem;
1341 code = parseAFM_CompCharData (fp, *fi);
1343 case ENDFONTMETRICS:
1348 code = AFM_parseError;
1352 if ((error != AFM_earlyEOF) && (code < 0))
1357 if ((error != AFM_earlyEOF) && (code < 0))
1360 if (ident != NULL) { free (ident); ident = NULL; }