2 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
4 * This file may be freely copied and redistributed as long as:
5 * 1) This entire notice continues to be included in the file,
6 * 2) If the file has been modified in any way, a notice of such
7 * modification is conspicuously indicated.
9 * PostScript, Display PostScript, and Adobe are registered trademarks of
10 * Adobe Systems Incorporated.
12 * ************************************************************************
13 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
14 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
15 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
16 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
17 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
18 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
20 * ************************************************************************
25 * - some names changed to avoid conflicts with T1lib
26 * - changed to ANSI C prototypes, as used by MDVI
32 * This file is used in conjuction with the parseAFM.h header file.
33 * This file contains several procedures that are used to parse AFM
34 * files. It is intended to work with an application program that needs
35 * font metric information. The program can be used as is by making a
36 * procedure call to "parseFile" (passing in the expected parameters)
37 * and having it fill in a data structure with the data from the
38 * AFM file, or an application developer may wish to customize this
41 * There is also a file, parseAFMclient.c, that is a sample application
42 * showing how to call the "parseFile" procedure and how to use the data
43 * after "parseFile" has returned.
45 * Please read the comments in parseAFM.h and parseAFMclient.c.
48 * original: DSM Thu Oct 20 17:39:59 PDT 1988
49 * modified: DSM Mon Jul 3 14:17:50 PDT 1989
50 * - added 'storageProblem' return code
51 * - fixed bug of not allocating extra byte for string duplication
53 * modified: DSM Tue Apr 3 11:18:34 PDT 1990
54 * - added free(ident) at end of parseFile routine
55 * modified: DSM Tue Jun 19 10:16:29 PDT 1990
56 * - changed (width == 250) to (width = 250) in initializeArray
64 #include <stdlib.h> /* added for MDVI */
65 #include <string.h> /* added for MDVI */
74 #define lineterm EOL /* line terminating character */
75 #define normalEOF 1 /* return code from parsing routines used only */
77 #define Space "space" /* used in string comparison to look for the width */
78 /* of the space character to init the widths array */
79 #define False "false" /* used in string comparison to check the value of */
80 /* boolean keys (e.g. IsFixedPitch) */
82 #define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
86 /*************************** GLOBALS ***********************/
88 static char *ident = NULL; /* storage buffer for keywords */
91 /* "shorts" for fast case statement
92 * The values of each of these enumerated items correspond to an entry in the
93 * table of strings defined below. Therefore, if you add a new string as
94 * new keyword into the keyStrings table, you must also add a corresponding
95 * parseKey AND it MUST be in the same position!
97 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
98 * keywords must be placed in lexicographical order, below. [Therefore, the
99 * enumerated items are not necessarily in lexicographical order, depending
100 * on the name chosen. BUT, they must be placed in the same position as the
101 * corresponding key string.] The NOPE shall remain in the last position,
102 * since it does not correspond to any key string, and it is used in the
103 * "recognize" procedure to calculate how many possible keys there are.
107 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
108 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
109 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
110 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH,
111 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
112 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
113 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
114 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
115 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
118 /* keywords for the system:
119 * This a table of all of the current strings that are vaild AFM keys.
120 * Each entry can be referenced by the appropriate parseKey value (an
121 * enumerated data type defined above). If you add a new keyword here,
122 * a corresponding parseKey MUST be added to the enumerated data type
123 * defined above, AND it MUST be added in the same position as the
124 * string is in this table.
126 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
127 * must be placed in lexicographical order. And, NULL should remain at the
131 static char *keyStrings[] = {
132 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
133 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
134 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
135 "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
136 "ItalicAngle", "KP", "KPX", "L", "N",
137 "Notice", "PCC", "StartCharMetrics", "StartComposites",
138 "StartFontMetrics", "StartKernData", "StartKernPairs",
139 "StartTrackKern", "TrackKern", "UnderlinePosition",
140 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
143 /*************************** PARSING ROUTINES **************/
145 /*************************** token *************************/
147 /* A "AFM File Conventions" tokenizer. That means that it will
148 * return the next token delimited by white space. See also
149 * the `linetoken' routine, which does a similar thing but
150 * reads all tokens until the next end-of-line.
153 static char *token(FILE *stream)
157 /* skip over white space */
158 while ((ch = fgetc(stream)) == ' ' || ch == lineterm ||
159 ch == ',' || ch == '\t' || ch == ';');
162 while (ch != EOF && ch != ' ' && ch != lineterm
163 && ch != '\t' && ch != ':' && ch != ';' && idx < (MAX_NAME - 1))
169 if (ch == EOF && idx < 1) return ((char *)NULL);
170 if (idx >= 1 && ch != ':' ) ungetc(ch, stream);
171 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
174 return(ident); /* returns pointer to the token */
179 /*************************** linetoken *************************/
181 /* "linetoken" will get read all tokens until the EOL character from
182 * the given stream. This is used to get any arguments that can be
183 * more than one word (like Comment lines and FullName).
186 static char *linetoken(FILE *stream)
190 while ((ch = fgetc(stream)) == ' ' || ch == '\t' );
193 while (ch != EOF && ch != lineterm && idx < (MAX_NAME - 1))
202 return(ident); /* returns pointer to the token */
207 /*************************** recognize *************************/
209 /* This function tries to match a string to a known list of
210 * valid AFM entries (check the keyStrings array above).
211 * "ident" contains everything from white space through the
212 * next space, tab, or ":" character.
214 * The algorithm is a standard Knuth binary search.
217 static enum parseKey recognize(char *ident)
219 int lower = 0, upper = (int) NOPE, midpoint, cmpvalue;
222 while ((upper >= lower) && !found)
224 midpoint = (lower + upper)/2;
225 if (keyStrings[midpoint] == NULL) break;
226 cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
227 if (cmpvalue == 0) found = TRUE;
228 else if (cmpvalue < 0) upper = midpoint - 1;
229 else lower = midpoint + 1;
232 if (found) return (enum parseKey) midpoint;
238 /************************* parseGlobals *****************************/
240 /* This function is called by "parseFile". It will parse the AFM File
241 * up to the "StartCharMetrics" keyword, which essentially marks the
242 * end of the Global Font Information and the beginning of the character
243 * metrics information.
245 * If the caller of "parseFile" specified that it wanted the Global
246 * Font Information (as defined by the "AFM File Specification"
247 * document), then that information will be stored in the returned
250 * Any Global Font Information entries that are not found in a
251 * given file, will have the usual default initialization value
252 * for its type (i.e. entries of type int will be 0, etc).
254 * This function returns an error code specifying whether there was
255 * a premature EOF or a parsing error. This return value is used by
256 * parseFile to determine if there is more file to parse.
259 static BOOL parseGlobals(FILE *fp, GlobalFontInfo *gfi)
261 BOOL cont = TRUE, save = (gfi != NULL);
263 register char *keyword;
270 /* Have reached an early and unexpected EOF. */
271 /* Set flag and stop parsing */
274 break; /* get out of loop */
277 /* get tokens until the end of the Global Font info section */
278 /* without saving any of the data */
279 switch (recognize(keyword))
281 case STARTCHARMETRICS:
292 /* otherwise parse entire global font info section, */
293 /* saving the data */
294 switch(recognize(keyword))
296 case STARTFONTMETRICS:
298 gfi->afmVersion = (char *) malloc(strlen(keyword) + 1);
299 strcpy(gfi->afmVersion, keyword);
302 keyword = linetoken(fp);
306 gfi->fontName = (char *) malloc(strlen(keyword) + 1);
307 strcpy(gfi->fontName, keyword);
311 gfi->encodingScheme = (char *)
312 malloc(strlen(keyword) + 1);
313 strcpy(gfi->encodingScheme, keyword);
316 keyword = linetoken(fp);
317 gfi->fullName = (char *) malloc(strlen(keyword) + 1);
318 strcpy(gfi->fullName, keyword);
321 keyword = linetoken(fp);
322 gfi->familyName = (char *) malloc(strlen(keyword) + 1);
323 strcpy(gfi->familyName, keyword);
327 gfi->weight = (char *) malloc(strlen(keyword) + 1);
328 strcpy(gfi->weight, keyword);
332 gfi->italicAngle = atof(keyword);
333 if (errno == ERANGE) error = parseError;
337 if (MATCH(keyword, False))
338 gfi->isFixedPitch = 0;
340 gfi->isFixedPitch = 1;
342 case UNDERLINEPOSITION:
344 gfi->underlinePosition = atoi(keyword);
346 case UNDERLINETHICKNESS:
348 gfi->underlineThickness = atoi(keyword);
352 gfi->version = (char *) malloc(strlen(keyword) + 1);
353 strcpy(gfi->version, keyword);
356 keyword = linetoken(fp);
357 gfi->notice = (char *) malloc(strlen(keyword) + 1);
358 strcpy(gfi->notice, keyword);
362 gfi->fontBBox.llx = atoi(keyword);
364 gfi->fontBBox.lly = atoi(keyword);
366 gfi->fontBBox.urx = atoi(keyword);
368 gfi->fontBBox.ury = atoi(keyword);
372 gfi->capHeight = atoi(keyword);
376 gfi->xHeight = atoi(keyword);
380 gfi->descender = atoi(keyword);
384 gfi->ascender = atoi(keyword);
386 case STARTCHARMETRICS:
406 #if 0 /* this function does not seem to be used anywhere */
407 /************************* initializeArray ************************/
409 /* Unmapped character codes are (at Adobe Systems) assigned the
410 * width of the space character (if one exists) else they get the
411 * value of 250 ems. This function initializes all entries in the
412 * char widths array to have this value. Then any mapped character
413 * codes will be replaced with the width of the appropriate character
414 * when parsing the character metric section.
416 * This function parses the Character Metrics Section looking
417 * for a space character (by comparing character names). If found,
418 * the width of the space character will be used to initialize the
419 * values in the array of character widths.
421 * Before returning, the position of the read/write pointer of the
422 * file is reset to be where it was upon entering this function.
425 static int initializeArray(FILE *fp, int *cwi)
427 BOOL cont = TRUE, found = FALSE;
428 long opos = ftell(fp);
429 int code = 0, width = 0, i = 0, error = 0;
430 register char *keyword;
438 break; /* get out of loop */
440 switch(recognize(keyword))
443 keyword = linetoken(fp);
446 code = atoi(token(fp));
449 width = atoi(token(fp));
453 if (MATCH(keyword, Space))
476 for (i = 0; i < 256; ++i)
483 } /* initializeArray */
486 /************************* parseCharWidths **************************/
488 /* This function is called by "parseFile". It will parse the AFM File
489 * up to the "EndCharMetrics" keyword. It will save the character
490 * width info (as opposed to all of the character metric information)
491 * if requested by the caller of parseFile. Otherwise, it will just
492 * parse through the section without saving any information.
494 * If data is to be saved, parseCharWidths is passed in a pointer
495 * to an array of widths that has already been initialized by the
496 * standard value for unmapped character codes. This function parses
497 * the Character Metrics section only storing the width information
498 * for the encoded characters into the array using the character code
499 * as the index into that array.
501 * This function returns an error code specifying whether there was
502 * a premature EOF or a parsing error. This return value is used by
503 * parseFile to determine if there is more file to parse.
506 static int parseCharWidths(FILE *fp, int *cwi)
508 BOOL cont = TRUE, save = (cwi != NULL);
509 int pos = 0, error = ok;
510 register char *keyword;
515 /* Have reached an early and unexpected EOF. */
516 /* Set flag and stop parsing */
520 break; /* get out of loop */
523 /* get tokens until the end of the Char Metrics section without */
524 /* saving any of the data*/
525 switch (recognize(keyword))
538 /* otherwise parse entire char metrics section, saving */
539 /* only the char x-width info */
540 switch(recognize(keyword))
543 keyword = linetoken(fp);
550 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
551 keyword = token(fp); keyword = token(fp); /* eat values */
556 if (pos >= 0) /* ignore unmapped chars */
557 cwi[pos] = atoi(keyword);
566 case CHARNAME: /* eat values (so doesn't cause parseError) */
570 keyword = token(fp); keyword = token(fp);
571 keyword = token(fp); keyword = token(fp);
574 keyword = token(fp); keyword = token(fp);
585 } /* parseCharWidths */
588 /************************* parseCharMetrics ************************/
590 /* This function is called by parseFile if the caller of parseFile
591 * requested that all character metric information be saved
592 * (as opposed to only the character width information).
594 * parseCharMetrics is passed in a pointer to an array of records
595 * to hold information on a per character basis. This function
596 * parses the Character Metrics section storing all character
597 * metric information for the ALL characters (mapped and unmapped)
600 * This function returns an error code specifying whether there was
601 * a premature EOF or a parsing error. This return value is used by
602 * parseFile to determine if there is more file to parse.
605 static int parseCharMetrics(FILE *fp, FontInfo *fi)
607 BOOL cont = TRUE, firstTime = TRUE;
608 int error = ok, count = 0;
609 register CharMetricInfo *temp = fi->cmi;
610 register char *keyword;
618 break; /* get out of loop */
620 switch(recognize(keyword))
623 keyword = linetoken(fp);
626 if (count < fi->numOfChars)
628 if (firstTime) firstTime = FALSE;
630 temp->code = atoi(token(fp));
640 temp->wx = atoi(token(fp));
641 temp->wy = atoi(token(fp));
644 temp->wx = atoi(token(fp));
648 temp->name = (char *) malloc(strlen(keyword) + 1);
649 strcpy(temp->name, keyword);
652 temp->charBBox.llx = atoi(token(fp));
653 temp->charBBox.lly = atoi(token(fp));
654 temp->charBBox.urx = atoi(token(fp));
655 temp->charBBox.ury = atoi(token(fp));
658 Ligature **tail = &(temp->ligs);
659 Ligature *node = *tail;
663 while (node->next != NULL)
665 tail = &(node->next);
668 *tail = (Ligature *) calloc(1, sizeof(Ligature));
670 (*tail)->succ = (char *) malloc(strlen(keyword) + 1);
671 strcpy((*tail)->succ, keyword);
673 (*tail)->lig = (char *) malloc(strlen(keyword) + 1);
674 strcpy((*tail)->lig, keyword);
690 if ((error == ok) && (count != fi->numOfChars))
695 } /* parseCharMetrics */
699 /************************* parseTrackKernData ***********************/
701 /* This function is called by "parseFile". It will parse the AFM File
702 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
703 * track kerning data if requested by the caller of parseFile.
705 * parseTrackKernData is passed in a pointer to the FontInfo record.
706 * If data is to be saved, the FontInfo record will already contain
707 * a valid pointer to storage for the track kerning data.
709 * This function returns an error code specifying whether there was
710 * a premature EOF or a parsing error. This return value is used by
711 * parseFile to determine if there is more file to parse.
714 static int parseTrackKernData(FILE *fp, FontInfo *fi)
716 BOOL cont = TRUE, save = (fi->tkd != NULL);
717 int pos = 0, error = ok, tcount = 0;
718 register char *keyword;
727 break; /* get out of loop */
730 /* get tokens until the end of the Track Kerning Data */
731 /* section without saving any of the data */
732 switch(recognize(keyword))
746 /* otherwise parse entire Track Kerning Data section, */
747 /* saving the data */
748 switch(recognize(keyword))
751 keyword = linetoken(fp);
754 if (tcount < fi->numOfTracks)
757 fi->tkd[pos].degree = atoi(keyword);
759 fi->tkd[pos].minPtSize = atof(keyword);
760 if (errno == ERANGE) error = parseError;
762 fi->tkd[pos].minKernAmt = atof(keyword);
763 if (errno == ERANGE) error = parseError;
765 fi->tkd[pos].maxPtSize = atof(keyword);
766 if (errno == ERANGE) error = parseError;
768 fi->tkd[pos++].maxKernAmt = atof(keyword);
769 if (errno == ERANGE) error = parseError;
793 if (error == ok && tcount != fi->numOfTracks)
798 } /* parseTrackKernData */
801 /************************* parsePairKernData ************************/
803 /* This function is called by "parseFile". It will parse the AFM File
804 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
805 * the pair kerning data if requested by the caller of parseFile.
807 * parsePairKernData is passed in a pointer to the FontInfo record.
808 * If data is to be saved, the FontInfo record will already contain
809 * a valid pointer to storage for the pair kerning data.
811 * This function returns an error code specifying whether there was
812 * a premature EOF or a parsing error. This return value is used by
813 * parseFile to determine if there is more file to parse.
816 static int parsePairKernData(FILE *fp, FontInfo *fi)
818 BOOL cont = TRUE, save = (fi->pkd != NULL);
819 int pos = 0, error = ok, pcount = 0;
820 register char *keyword;
829 break; /* get out of loop */
832 /* get tokens until the end of the Pair Kerning Data */
833 /* section without saving any of the data */
834 switch(recognize(keyword))
848 /* otherwise parse entire Pair Kerning Data section, */
849 /* saving the data */
850 switch(recognize(keyword))
853 keyword = linetoken(fp);
856 if (pcount < fi->numOfPairs)
859 fi->pkd[pos].name1 = (char *)
860 malloc(strlen(keyword) + 1);
861 strcpy(fi->pkd[pos].name1, keyword);
863 fi->pkd[pos].name2 = (char *)
864 malloc(strlen(keyword) + 1);
865 strcpy(fi->pkd[pos].name2, keyword);
867 fi->pkd[pos].xamt = atoi(keyword);
869 fi->pkd[pos++].yamt = atoi(keyword);
879 if (pcount < fi->numOfPairs)
882 fi->pkd[pos].name1 = (char *)
883 malloc(strlen(keyword) + 1);
884 strcpy(fi->pkd[pos].name1, keyword);
886 fi->pkd[pos].name2 = (char *)
887 malloc(strlen(keyword) + 1);
888 strcpy(fi->pkd[pos].name2, keyword);
890 fi->pkd[pos++].xamt = atoi(keyword);
914 if (error == ok && pcount != fi->numOfPairs)
919 } /* parsePairKernData */
922 /************************* parseCompCharData **************************/
924 /* This function is called by "parseFile". It will parse the AFM File
925 * up to the "EndComposites" keyword. It will save the composite
926 * character data if requested by the caller of parseFile.
928 * parseCompCharData is passed in a pointer to the FontInfo record, and
929 * a boolean representing if the data should be saved.
931 * This function will create the appropriate amount of storage for
932 * the composite character data and store a pointer to the storage
933 * in the FontInfo record.
935 * This function returns an error code specifying whether there was
936 * a premature EOF or a parsing error. This return value is used by
937 * parseFile to determine if there is more file to parse.
940 static int parseCompCharData(FILE *fp, FontInfo *fi)
942 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
943 int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0;
944 register char *keyword;
950 /* Have reached an early and unexpected EOF. */
951 /* Set flag and stop parsing */
954 break; /* get out of loop */
956 if (ccount > fi->numOfComps)
959 break; /* get out of loop */
962 /* get tokens until the end of the Composite Character info */
963 /* section without saving any of the data */
964 switch(recognize(keyword))
977 /* otherwise parse entire Composite Character info section, */
978 /* saving the data */
979 switch(recognize(keyword))
982 keyword = linetoken(fp);
985 if (ccount < fi->numOfComps)
988 if (pcount != fi->ccd[pos].numOfPieces)
991 if (firstTime) firstTime = FALSE;
993 fi->ccd[pos].ccName = (char *)
994 malloc(strlen(keyword) + 1);
995 strcpy(fi->ccd[pos].ccName, keyword);
997 fi->ccd[pos].numOfPieces = atoi(keyword);
998 fi->ccd[pos].pieces = (Pcc *)
999 calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
1010 if (pcount < fi->ccd[pos].numOfPieces)
1012 keyword = token(fp);
1013 fi->ccd[pos].pieces[j].pccName = (char *)
1014 malloc(strlen(keyword) + 1);
1015 strcpy(fi->ccd[pos].pieces[j].pccName, keyword);
1016 keyword = token(fp);
1017 fi->ccd[pos].pieces[j].deltax = atoi(keyword);
1018 keyword = token(fp);
1019 fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
1028 case ENDFONTMETRICS:
1039 if (error == ok && ccount != fi->numOfComps)
1044 } /* parseCompCharData */
1049 /*************************** 'PUBLIC' FUNCTION ********************/
1052 /*************************** parseFile *****************************/
1054 /* parseFile is the only 'public' procedure available. It is called
1055 * from an application wishing to get information from an AFM file.
1056 * The caller of this function is responsible for locating and opening
1057 * an AFM file and handling all errors associated with that task.
1059 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1060 * to a (FontInfo *) variable (for which storage will be allocated and
1061 * the data requested filled in), and a mask specifying which
1062 * data from the AFM File should be saved in the FontInfo structure.
1064 * The file will be parsed and the requested data will be stored in
1065 * a record of type FontInfo (refer to ParseAFM.h).
1067 * parseFile returns an error code as defined in parseAFM.h.
1069 * The position of the read/write pointer associated with the file
1070 * pointer upon return of this function is undefined.
1073 extern int afm_parse_file(FILE *fp, FontInfo **fi, FLAGS flags)
1076 int code = ok; /* return code from each of the parsing routines */
1077 int error = ok; /* used as the return code from this function */
1079 register char *keyword; /* used to store a token */
1082 /* storage data for the global variable ident */
1083 ident = (char *) calloc(MAX_NAME, sizeof(char));
1084 if (ident == NULL) {error = storageProblem; return(error);}
1086 (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
1087 if ((*fi) == NULL) {error = storageProblem; return(error);}
1091 (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
1092 if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
1095 /* The AFM File begins with Global Font Information. This section */
1096 /* will be parsed whether or not information should be saved. */
1097 code = parseGlobals(fp, (*fi)->gfi);
1099 if (code < 0) error = code;
1101 /* The Global Font Information is followed by the Character Metrics */
1102 /* section. Which procedure is used to parse this section depends on */
1103 /* how much information should be saved. If all of the metrics info */
1104 /* is wanted, parseCharMetrics is called. If only the character widths */
1105 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1106 /* be called in the case that no character data is to be saved, just */
1107 /* to parse through the section. */
1109 if ((code != normalEOF) && (code != earlyEOF))
1111 (*fi)->numOfChars = atoi(token(fp));
1112 if (flags & (P_M ^ P_W))
1114 (*fi)->cmi = (CharMetricInfo *)
1115 calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
1116 if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
1117 code = parseCharMetrics(fp, *fi);
1123 (*fi)->cwi = (int *) calloc(256, sizeof(int));
1124 if ((*fi)->cwi == NULL)
1126 error = storageProblem;
1130 /* parse section regardless */
1131 code = parseCharWidths(fp, (*fi)->cwi);
1135 if ((error != earlyEOF) && (code < 0)) error = code;
1137 /* The remaining sections of the AFM are optional. This code will */
1138 /* look at the next keyword in the file to determine what section */
1139 /* is next, and then allocate the appropriate amount of storage */
1140 /* for the data (if the data is to be saved) and call the */
1141 /* appropriate parsing routine to parse the section. */
1143 while ((code != normalEOF) && (code != earlyEOF))
1145 keyword = token(fp);
1146 if (keyword == NULL)
1147 /* Have reached an early and unexpected EOF. */
1148 /* Set flag and stop parsing */
1151 break; /* get out of loop */
1153 switch(recognize(keyword))
1159 case STARTTRACKKERN:
1160 keyword = token(fp);
1163 (*fi)->numOfTracks = atoi(keyword);
1164 (*fi)->tkd = (TrackKernData *)
1165 calloc((*fi)->numOfTracks, sizeof(TrackKernData));
1166 if ((*fi)->tkd == NULL)
1168 error = storageProblem;
1172 code = parseTrackKernData(fp, *fi);
1174 case STARTKERNPAIRS:
1175 keyword = token(fp);
1178 (*fi)->numOfPairs = atoi(keyword);
1179 (*fi)->pkd = (PairKernData *)
1180 calloc((*fi)->numOfPairs, sizeof(PairKernData));
1181 if ((*fi)->pkd == NULL)
1183 error = storageProblem;
1187 code = parsePairKernData(fp, *fi);
1189 case STARTCOMPOSITES:
1190 keyword = token(fp);
1193 (*fi)->numOfComps = atoi(keyword);
1194 (*fi)->ccd = (CompCharData *)
1195 calloc((*fi)->numOfComps, sizeof(CompCharData));
1196 if ((*fi)->ccd == NULL)
1198 error = storageProblem;
1202 code = parseCompCharData(fp, *fi);
1204 case ENDFONTMETRICS:
1213 if ((error != earlyEOF) && (code < 0)) error = code;
1217 if ((error != earlyEOF) && (code < 0)) error = code;
1219 if (ident != NULL) { free(ident); ident = NULL; }
1225 /* added for MDVI: this function was copied from `parseAFMclient.c' */
1227 void afm_free_fontinfo(FontInfo *fi)
1231 if (fi->gfi != NULL)
1233 free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL;
1234 free(fi->gfi->fontName); fi->gfi->fontName = NULL;
1235 free(fi->gfi->fullName); fi->gfi->fullName = NULL;
1236 free(fi->gfi->familyName); fi->gfi->familyName = NULL;
1237 free(fi->gfi->weight); fi->gfi->weight = NULL;
1238 free(fi->gfi->version); fi->gfi->version = NULL;
1239 free(fi->gfi->notice); fi->gfi->notice = NULL;
1240 free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL;
1241 free(fi->gfi); fi->gfi = NULL;
1244 if (fi->cwi != NULL)
1245 { free(fi->cwi); fi->cwi = NULL; }
1247 if (fi->cmi != NULL)
1250 CharMetricInfo *temp = fi->cmi;
1251 Ligature *node = temp->ligs;
1253 for (i = 0; i < fi->numOfChars; ++i)
1255 for (node = temp->ligs; node != NULL; node = node->next)
1257 free(node->succ); node->succ = NULL;
1258 free(node->lig); node->lig = NULL;
1261 free(temp->name); temp->name = NULL;
1265 free(fi->cmi); fi->cmi = NULL;
1268 if (fi->tkd != NULL)
1269 { free(fi->tkd); fi->tkd = NULL; }
1271 if (fi->pkd != NULL)
1273 free(fi->pkd->name1); fi->pkd->name1 = NULL;
1274 free(fi->pkd->name2); fi->pkd->name2 = NULL;
1275 free(fi->pkd); fi->pkd = NULL;
1278 if (fi->ccd != NULL)
1281 CompCharData *ccd = fi->ccd;
1283 for (i = 0; i < fi->numOfComps; ++i)
1285 for (j = 0; j < ccd[i].numOfPieces; ++j)
1287 free(ccd[i].pieces[j].pccName);
1288 ccd[i].pieces[j].pccName = NULL;
1291 free(ccd[i].ccName); ccd[i].ccName = NULL;
1294 free(fi->ccd); fi->ccd = NULL;
1301 } /* afm_free_fontinfo */
1303 #endif /* WITH_AFM_FILES */