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"
82 /* your basic constants */
85 #define EOL '\n' /* end-of-line indicator */
86 #define MAX_NAME 4096 /* max length for identifiers */
88 /* Flags that can be AND'ed together to specify exactly what
89 * information from the AFM file should be saved.
91 #define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
92 #define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
93 #define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
94 #define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
95 #define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
96 #define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
98 /* Commonly used flags
107 (P_G | P_M | P_P | P_T)
109 (P_G | P_M | P_P | P_T | P_C)
111 #define METATYPE1_BUG /* Parse Metatype1's (version unknown)
112 'Generated' global tag as comment. */
114 #define lineterm EOL /* line terminating character */
115 #define lineterm_alt '\r' /* alternative line terminating character */
116 #define normalEOF 1 /* return code from parsing routines used only */
118 #define Space "space" /* used in string comparison to look for the width */
119 /* of the space character to init the widths array */
120 #define False "false" /* used in string comparison to check the value of */
121 /* boolean keys (e.g. IsFixedPitch) */
123 #define MATCH(A, B) (strncmp ((A), (B), MAX_NAME) == 0)
125 /*************************** GLOBALS ***********************/
127 static char *ident = NULL; /* storage buffer for keywords */
129 /* "shorts" for fast case statement
130 * The values of each of these enumerated items correspond to an entry in the
131 * table of strings defined below. Therefore, if you add a new string as
132 * new keyword into the keyStrings table, you must also add a corresponding
133 * parseKey AND it MUST be in the same position!
135 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
136 * keywords must be placed in lexicographical order, below. [Therefore, the
137 * enumerated items are not necessarily in lexicographical order, depending
138 * on the name chosen. BUT, they must be placed in the same position as the
139 * corresponding key string.] The NOPE shall remain in the last position,
140 * since it does not correspond to any key string, and it is used in the
141 * "recognize" procedure to calculate how many possible keys there are.
146 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
147 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
148 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
149 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME,
154 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
155 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
156 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
157 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
158 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
161 /* keywords for the system:
162 * This a table of all of the current strings that are vaild AFM keys.
163 * Each entry can be referenced by the appropriate parseKey value (an
164 * enumerated data type defined above). If you add a new keyword here,
165 * a corresponding parseKey MUST be added to the enumerated data type
166 * defined above, AND it MUST be added in the same position as the
167 * string is in this table.
169 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
170 * must be placed in lexicographical order. And, NULL should remain at the
174 static char *keyStrings[]
176 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
177 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
178 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
179 "FamilyName", "FontBBox", "FontName", "FullName",
184 "ItalicAngle", "KP", "KPX", "L", "N",
185 "Notice", "PCC", "StartCharMetrics", "StartComposites",
186 "StartFontMetrics", "StartKernData", "StartKernPairs",
187 "StartTrackKern", "TrackKern", "UnderlinePosition",
188 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
191 /*************************** PARSING ROUTINES **************/
193 /*************************** token *************************/
195 /* A "AFM File Conventions" tokenizer. That means that it will
196 * return the next token delimited by white space. See also
197 * the `linetoken' routine, which does a similar thing but
198 * reads all tokens until the next end-of-line.
206 /* skip over white space */
207 while ((ch = fgetc (stream)) == ' ' || ch == lineterm
208 || ch == lineterm_alt
209 || ch == ',' || ch == '\t' || ch == ';');
212 while (idx < MAX_NAME - 1
213 && ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
214 && ch != '\t' && ch != ':' && ch != ';')
220 if (ch == EOF && idx < 1) return ((char *)NULL);
221 if (idx >= 1 && ch != ':') ungetc (ch, stream);
222 if (idx < 1) ident[idx++] = ch; /* single-character token */
225 return (ident); /* returns pointer to the token */
228 /*************************** linetoken *************************/
230 /* "linetoken" will get read all tokens until the EOL character from
231 * the given stream. This is used to get any arguments that can be
232 * more than one word (like Comment lines and FullName).
236 linetoken (FILE *stream)
240 while ((ch = fgetc (stream)) == ' ' || ch == '\t');
243 while (idx < MAX_NAME - 1
244 && ch != EOF && ch != lineterm && ch != lineterm_alt)
253 return (ident); /* returns pointer to the token */
256 /*************************** recognize *************************/
258 /* This function tries to match a string to a known list of
259 * valid AFM entries (check the keyStrings array above).
260 * "ident" contains everything from white space through the
261 * next space, tab, or ":" character.
263 * The algorithm is a standard Knuth binary search.
267 recognize (register char *ident)
275 while ((upper >= lower) && !found)
277 midpoint = (lower + upper) / 2;
278 if (keyStrings[midpoint] == NULL)
280 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
285 upper = midpoint - 1;
287 lower = midpoint + 1;
291 return (enum parseKey) midpoint;
296 /************************* parseGlobals *****************************/
298 /* This function is called by "parseFile". It will parse the AFM File
299 * up to the "StartCharMetrics" keyword, which essentially marks the
300 * end of the Global Font Information and the beginning of the character
301 * metrics information.
303 * If the caller of "parseFile" specified that it wanted the Global
304 * Font Information (as defined by the "AFM File Specification"
305 * document), then that information will be stored in the returned
308 * Any Global Font Information entries that are not found in a
309 * given file, will have the usual default initialization value
310 * for its type (i.e. entries of type int will be 0, etc).
312 * This function returns an error code specifying whether there was
313 * a premature EOF or a parsing error. This return value is used by
314 * parseFile to determine if there is more file to parse.
318 parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
320 BOOL cont = TRUE, save = (gfi != NULL);
322 register char *keyword;
326 keyword = token (fp);
329 /* Have reached an early and unexpected EOF. */
330 /* Set flag and stop parsing */
332 error = AFM_earlyEOF;
333 break; /* get out of loop */
336 /* get tokens until the end of the Global Font info section */
337 /* without saving any of the data */
338 switch (recognize (keyword))
340 case STARTCHARMETRICS:
351 /* otherwise parse entire global font info section, */
352 /* saving the data */
353 switch (recognize (keyword))
355 case STARTFONTMETRICS:
356 keyword = token (fp);
357 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
358 strcpy (gfi->afmVersion, keyword);
364 keyword = linetoken (fp);
367 keyword = token (fp);
368 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
369 strcpy (gfi->fontName, keyword);
372 keyword = token (fp);
373 gfi->encodingScheme = (char *)
374 malloc (strlen (keyword) + 1);
375 strcpy (gfi->encodingScheme, keyword);
378 keyword = linetoken (fp);
379 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
380 strcpy (gfi->fullName, keyword);
383 keyword = linetoken (fp);
384 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
385 strcpy (gfi->familyName, keyword);
388 keyword = token (fp);
389 gfi->weight = (char *) malloc (strlen (keyword) + 1);
390 strcpy (gfi->weight, keyword);
393 keyword = token (fp);
394 gfi->italicAngle = atof (keyword);
395 if (errno == ERANGE) error = AFM_parseError;
398 keyword = token (fp);
399 if (MATCH (keyword, False))
400 gfi->isFixedPitch = 0;
402 gfi->isFixedPitch = 1;
404 case UNDERLINEPOSITION:
405 keyword = token (fp);
406 gfi->underlinePosition = atoi (keyword);
408 case UNDERLINETHICKNESS:
409 keyword = token (fp);
410 gfi->underlineThickness = atoi (keyword);
413 keyword = linetoken (fp);
414 gfi->version = (char *) malloc (strlen (keyword) + 1);
415 strcpy (gfi->version, keyword);
418 keyword = linetoken (fp);
419 gfi->notice = (char *) malloc (strlen (keyword) + 1);
420 strcpy (gfi->notice, keyword);
423 keyword = token (fp);
424 gfi->fontBBox.llx = atoi (keyword);
425 keyword = token (fp);
426 gfi->fontBBox.lly = atoi (keyword);
427 keyword = token (fp);
428 gfi->fontBBox.urx = atoi (keyword);
429 keyword = token (fp);
430 gfi->fontBBox.ury = atoi (keyword);
433 keyword = token (fp);
434 gfi->capHeight = atoi (keyword);
437 keyword = token (fp);
438 gfi->xHeight = atoi (keyword);
441 keyword = token (fp);
442 gfi->descender = atoi (keyword);
445 keyword = token (fp);
446 gfi->ascender = atoi (keyword);
448 case STARTCHARMETRICS:
457 error = AFM_parseError;
466 /************************* initializeArray ************************/
468 /* Unmapped character codes are (at Adobe Systems) assigned the
469 * width of the space character (if one exists) else they get the
470 * value of 250 ems. This function initializes all entries in the
471 * char widths array to have this value. Then any mapped character
472 * codes will be replaced with the width of the appropriate character
473 * when parsing the character metric section.
475 * This function parses the Character Metrics Section looking
476 * for a space character (by comparing character names). If found,
477 * the width of the space character will be used to initialize the
478 * values in the array of character widths.
480 * Before returning, the position of the read/write pointer of the
481 * file is reset to be where it was upon entering this function.
485 initializeArray (FILE *fp, register int *cwi)
487 BOOL cont = TRUE, found = FALSE;
488 long opos = ftell (fp);
489 int code = 0, width = 0, i = 0, error = 0;
490 register char *keyword;
494 keyword = token (fp);
497 error = AFM_earlyEOF;
498 break; /* get out of loop */
500 switch (recognize (keyword))
503 keyword = linetoken (fp);
506 code = atoi (token (fp));
509 width = atoi (token (fp));
512 keyword = token (fp);
513 if (MATCH (keyword, Space))
528 error = AFM_parseError;
536 for (i = 0; i < 256; ++i)
542 } /* initializeArray */
545 /************************* parseCharWidths **************************/
547 /* This function is called by "parseFile". It will parse the AFM File
548 * up to the "EndCharMetrics" keyword. It will save the character
549 * width info (as opposed to all of the character metric information)
550 * if requested by the caller of parseFile. Otherwise, it will just
551 * parse through the section without saving any information.
553 * If data is to be saved, parseCharWidths is passed in a pointer
554 * to an array of widths that has already been initialized by the
555 * standard value for unmapped character codes. This function parses
556 * the Character Metrics section only storing the width information
557 * for the encoded characters into the array using the character code
558 * as the index into that array.
560 * This function returns an error code specifying whether there was
561 * a premature EOF or a parsing error. This return value is used by
562 * parseFile to determine if there is more file to parse.
566 parseCharWidths (FILE *fp, register int *cwi)
568 BOOL cont = TRUE, save = (cwi != NULL);
569 int pos = 0, error = AFM_ok;
570 register char *keyword;
574 keyword = token (fp);
575 /* Have reached an early and unexpected EOF. */
576 /* Set flag and stop parsing */
579 error = AFM_earlyEOF;
580 break; /* get out of loop */
583 /* get tokens until the end of the Char Metrics section without */
584 /* saving any of the data*/
585 switch (recognize (keyword))
598 /* otherwise parse entire char metrics section, saving */
599 /* only the char x-width info */
600 switch (recognize (keyword))
603 keyword = linetoken (fp);
606 keyword = token (fp);
607 pos = atoi (keyword);
610 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
611 keyword = token (fp); keyword = token (fp); /* eat values */
612 error = AFM_parseError;
615 keyword = token (fp);
616 if (pos >= 0) /* ignore unmapped chars */
617 cwi[pos] = atoi (keyword);
626 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
627 keyword = token (fp);
630 keyword = token (fp); keyword = token (fp);
631 keyword = token (fp); keyword = token (fp);
634 keyword = token (fp); keyword = token (fp);
638 error = AFM_parseError;
644 } /* parseCharWidths */
646 /************************* parseCharMetrics ************************/
648 /* This function is called by parseFile if the caller of parseFile
649 * requested that all character metric information be saved
650 * (as opposed to only the character width information).
652 * parseCharMetrics is passed in a pointer to an array of records
653 * to hold information on a per character basis. This function
654 * parses the Character Metrics section storing all character
655 * metric information for the ALL characters (mapped and unmapped)
658 * This function returns an error code specifying whether there was
659 * a premature EOF or a parsing error. This return value is used by
660 * parseFile to determine if there is more file to parse.
664 parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
666 BOOL cont = TRUE, firstTime = TRUE;
667 int error = AFM_ok, count = 0;
668 register AFM_CharMetricInfo *temp = fi->cmi;
669 register char *keyword;
673 keyword = token (fp);
676 error = AFM_earlyEOF;
677 break; /* get out of loop */
679 switch (recognize (keyword))
682 keyword = linetoken (fp);
685 if (count < fi->numOfChars)
691 temp->code = atoi (token (fp));
696 warning ("Too many metrics.");
697 error = AFM_parseError;
702 temp->wx = atoi (token (fp));
703 temp->wy = atoi (token (fp));
706 temp->wx = atoi (token (fp));
710 keyword = token (fp);
711 temp->name = (char *) malloc (strlen (keyword) + 1);
712 strcpy (temp->name, keyword);
716 temp->charBBox.llx = atoi (token (fp));
717 temp->charBBox.lly = atoi (token (fp));
718 temp->charBBox.urx = atoi (token (fp));
719 temp->charBBox.ury = atoi (token (fp));
724 AFM_Ligature **tail = &(temp->ligs);
725 AFM_Ligature *node = *tail;
729 while (node->next != NULL)
731 tail = &(node->next);
734 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
735 keyword = token (fp);
736 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
737 strcpy ((*tail)->succ, keyword);
738 keyword = token (fp);
739 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
740 strcpy ((*tail)->lig, keyword);
751 warning ("Unknown token");
753 error = AFM_parseError;
758 if ((error == AFM_ok) && (count != fi->numOfChars))
760 warning ("Incorrect char count");
761 error = AFM_parseError;
764 } /* parseCharMetrics */
766 /************************* parseAFM_TrackKernData ***********************/
768 /* This function is called by "parseFile". It will parse the AFM File
769 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
770 * track kerning data if requested by the caller of parseFile.
772 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
773 * If data is to be saved, the FontInfo record will already contain
774 * a valid pointer to storage for the track kerning data.
776 * This function returns an error code specifying whether there was
777 * a premature EOF or a parsing error. This return value is used by
778 * parseFile to determine if there is more file to parse.
782 parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
784 BOOL cont = TRUE, save = (fi->tkd != NULL);
785 int pos = 0, error = AFM_ok, tcount = 0;
786 register char *keyword;
790 keyword = token (fp);
794 error = AFM_earlyEOF;
795 break; /* get out of loop */
798 /* get tokens until the end of the Track Kerning Data */
799 /* section without saving any of the data */
800 switch (recognize (keyword))
814 /* otherwise parse entire Track Kerning Data section, */
815 /* saving the data */
816 switch (recognize (keyword))
822 keyword = linetoken (fp);
825 if (tcount < fi->numOfTracks)
827 keyword = token (fp);
828 fi->tkd[pos].degree = atoi (keyword);
829 keyword = token (fp);
830 fi->tkd[pos].minPtSize = atof (keyword);
831 if (errno == ERANGE) error = AFM_parseError;
832 keyword = token (fp);
833 fi->tkd[pos].minKernAmt = atof (keyword);
834 if (errno == ERANGE) error = AFM_parseError;
835 keyword = token (fp);
836 fi->tkd[pos].maxPtSize = atof (keyword);
837 if (errno == ERANGE) error = AFM_parseError;
838 keyword = token (fp);
839 fi->tkd[pos++].maxKernAmt = atof (keyword);
840 if (errno == ERANGE) error = AFM_parseError;
845 error = AFM_parseError;
859 error = AFM_parseError;
864 if (error == AFM_ok && tcount != fi->numOfTracks)
865 error = AFM_parseError;
868 } /* parseAFM_TrackKernData */
870 /************************* parseAFM_PairKernData ************************/
872 /* This function is called by "parseFile". It will parse the AFM File
873 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
874 * the pair kerning data if requested by the caller of parseFile.
876 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
877 * If data is to be saved, the FontInfo record will already contain
878 * a valid pointer to storage for the pair kerning data.
880 * This function returns an error code specifying whether there was
881 * a premature EOF or a parsing error. This return value is used by
882 * parseFile to determine if there is more file to parse.
886 parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
888 BOOL cont = TRUE, save = (fi->pkd != NULL);
889 int pos = 0, error = AFM_ok, pcount = 0;
890 register char *keyword;
894 keyword = token (fp);
898 error = AFM_earlyEOF;
899 break; /* get out of loop */
902 /* get tokens until the end of the Pair Kerning Data */
903 /* section without saving any of the data */
904 switch (recognize (keyword))
918 /* otherwise parse entire Pair Kerning Data section, */
919 /* saving the data */
920 switch (recognize (keyword))
923 keyword = linetoken (fp);
926 if (pcount < fi->numOfPairs)
928 keyword = token (fp);
929 fi->pkd[pos].name1 = (char *)
930 malloc (strlen (keyword) + 1);
931 strcpy (fi->pkd[pos].name1, keyword);
932 keyword = token (fp);
933 fi->pkd[pos].name2 = (char *)
934 malloc (strlen (keyword) + 1);
935 strcpy (fi->pkd[pos].name2, keyword);
936 keyword = token (fp);
937 fi->pkd[pos].xamt = atoi (keyword);
938 keyword = token (fp);
939 fi->pkd[pos++].yamt = atoi (keyword);
944 error = AFM_parseError;
949 if (pcount < fi->numOfPairs)
951 keyword = token (fp);
952 fi->pkd[pos].name1 = (char *)
953 malloc (strlen (keyword) + 1);
954 strcpy (fi->pkd[pos].name1, keyword);
955 keyword = token (fp);
956 fi->pkd[pos].name2 = (char *)
957 malloc (strlen (keyword) + 1);
958 strcpy (fi->pkd[pos].name2, keyword);
959 keyword = token (fp);
960 fi->pkd[pos++].xamt = atoi (keyword);
965 error = AFM_parseError;
979 error = AFM_parseError;
984 if (error == AFM_ok && pcount != fi->numOfPairs)
985 error = AFM_parseError;
988 } /* parseAFM_PairKernData */
990 /************************* parseAFM_CompCharData **************************/
992 /* This function is called by "parseFile". It will parse the AFM File
993 * up to the "EndComposites" keyword. It will save the composite
994 * character data if requested by the caller of parseFile.
996 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
997 * a boolean representing if the data should be saved.
999 * This function will create the appropriate amount of storage for
1000 * the composite character data and store a pointer to the storage
1001 * in the FontInfo record.
1003 * This function returns an error code specifying whether there was
1004 * a premature EOF or a parsing error. This return value is used by
1005 * parseFile to determine if there is more file to parse.
1009 parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
1011 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
1012 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
1013 register char *keyword;
1017 keyword = token (fp);
1018 if (keyword == NULL)
1019 /* Have reached an early and unexpected EOF. */
1020 /* Set flag and stop parsing */
1022 error = AFM_earlyEOF;
1023 break; /* get out of loop */
1025 if (ccount > fi->numOfComps)
1027 error = AFM_parseError;
1028 break; /* get out of loop */
1031 /* get tokens until the end of the Composite Character info */
1032 /* section without saving any of the data */
1033 switch (recognize (keyword))
1038 case ENDFONTMETRICS:
1046 /* otherwise parse entire Composite Character info section, */
1047 /* saving the data */
1048 switch (recognize (keyword))
1051 keyword = linetoken (fp);
1054 if (ccount < fi->numOfComps)
1056 keyword = token (fp);
1057 if (pcount != fi->ccd[pos].numOfPieces)
1058 error = AFM_parseError;
1060 if (firstTime) firstTime = FALSE;
1062 fi->ccd[pos].ccName = (char *)
1063 malloc (strlen (keyword) + 1);
1064 strcpy (fi->ccd[pos].ccName, keyword);
1065 keyword = token (fp);
1066 fi->ccd[pos].numOfPieces = atoi (keyword);
1067 fi->ccd[pos].pieces = (AFM_Pcc *)
1068 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1074 error = AFM_parseError;
1079 if (pcount < fi->ccd[pos].numOfPieces)
1081 keyword = token (fp);
1082 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1083 malloc (strlen (keyword) + 1);
1084 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1085 keyword = token (fp);
1086 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1087 keyword = token (fp);
1088 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1092 error = AFM_parseError;
1097 case ENDFONTMETRICS:
1103 error = AFM_parseError;
1108 if (error == AFM_ok && ccount != fi->numOfComps)
1109 error = AFM_parseError;
1112 } /* parseAFM_CompCharData */
1114 /*************************** 'PUBLIC' FUNCTION ********************/
1117 AFM_free (AFM_Font_info *fi)
1121 free (fi->gfi->afmVersion);
1122 free (fi->gfi->fontName);
1123 free (fi->gfi->fullName);
1124 free (fi->gfi->familyName);
1125 free (fi->gfi->weight);
1126 free (fi->gfi->version);
1127 free (fi->gfi->notice);
1128 free (fi->gfi->encodingScheme);
1132 /* This contains just scalars. */
1138 for (i = 0; i < fi->numOfChars; i++)
1140 free (fi->cmi[i].name);
1141 while (fi->cmi[i].ligs)
1144 tmp = fi->cmi[i].ligs;
1148 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1154 /* This contains just scalars. */
1160 for (i = 0; i < fi->numOfPairs; i++)
1162 free (fi->pkd[i].name1);
1163 free (fi->pkd[i].name2);
1171 for (i = 0; i < fi->numOfComps; i++)
1173 free (fi->ccd[i].ccName);
1174 for (j = 0; j < fi->ccd[i].numOfPieces; j++)
1175 free (fi->ccd[i].pieces[j].AFM_PccName);
1176 free (fi->ccd[i].pieces);
1184 /*************************** parseFile *****************************/
1186 /* parseFile is the only 'public' procedure available. It is called
1187 * from an application wishing to get information from an AFM file.
1188 * The caller of this function is responsible for locating and opening
1189 * an AFM file and handling all errors associated with that task.
1191 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1192 * to a (FontInfo *) variable (for which storage will be allocated and
1193 * the data requested filled in), and a mask specifying which
1194 * data from the AFM File should be saved in the FontInfo structure.
1196 * The file will be parsed and the requested data will be stored in
1197 * a record of type FontInfo (refer to ParseAFM.h).
1199 * parseFile returns an error code as defined in parseAFM.h.
1201 * The position of the read/write pointer associated with the file
1202 * pointer upon return of this function is undefined.
1206 AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1209 int code = AFM_ok; /* return code from each of the parsing routines */
1210 int error = AFM_ok; /* used as the return code from this function */
1212 register char *keyword; /* used to store a token */
1214 /* storage data for the global variable ident */
1216 ident = (char *) calloc (MAX_NAME, sizeof (char));
1219 error = AFM_storageProblem;
1223 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1226 error = AFM_storageProblem;
1232 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1,
1233 sizeof (AFM_GlobalFontInfo));
1234 if ((*fi)->gfi == NULL)
1236 error = AFM_storageProblem;
1241 /* The AFM File begins with Global Font Information. This section */
1242 /* will be parsed whether or not information should be saved. */
1243 code = parseGlobals (fp, (*fi)->gfi);
1248 /* The Global Font Information is followed by the Character Metrics */
1249 /* section. Which procedure is used to parse this section depends on */
1250 /* how much information should be saved. If all of the metrics info */
1251 /* is wanted, parseCharMetrics is called. If only the character widths */
1252 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1253 /* be called in the case that no character data is to be saved, just */
1254 /* to parse through the section. */
1256 if ((code != normalEOF) && (code != AFM_earlyEOF))
1258 (*fi)->numOfChars = atoi (token (fp));
1259 if (flags & (P_M ^ P_W))
1261 (*fi)->cmi = (AFM_CharMetricInfo *)
1262 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1263 if ((*fi)->cmi == NULL)
1265 error = AFM_storageProblem;
1268 code = parseCharMetrics (fp, *fi);
1274 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1275 if ((*fi)->cwi == NULL)
1277 error = AFM_storageProblem;
1281 /* parse section regardless */
1282 code = parseCharWidths (fp, (*fi)->cwi);
1286 if ((error != AFM_earlyEOF) && (code < 0))
1289 /* The remaining sections of the AFM are optional. This code will */
1290 /* look at the next keyword in the file to determine what section */
1291 /* is next, and then allocate the appropriate amount of storage */
1292 /* for the data (if the data is to be saved) and call the */
1293 /* appropriate parsing routine to parse the section. */
1295 while ((code != normalEOF) && (code != AFM_earlyEOF))
1297 keyword = token (fp);
1298 if (keyword == NULL)
1299 /* Have reached an early and unexpected EOF. */
1300 /* Set flag and stop parsing */
1302 code = AFM_earlyEOF;
1303 break; /* get out of loop */
1305 switch (recognize (keyword))
1311 case STARTTRACKKERN:
1312 keyword = token (fp);
1315 (*fi)->numOfTracks = atoi (keyword);
1316 (*fi)->tkd = (AFM_TrackKernData *)
1317 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1318 if ((*fi)->tkd == NULL)
1320 error = AFM_storageProblem;
1324 code = parseAFM_TrackKernData (fp, *fi);
1326 case STARTKERNPAIRS:
1327 keyword = token (fp);
1330 (*fi)->numOfPairs = atoi (keyword);
1331 (*fi)->pkd = (AFM_PairKernData *)
1332 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1333 if ((*fi)->pkd == NULL)
1335 error = AFM_storageProblem;
1339 code = parseAFM_PairKernData (fp, *fi);
1341 case STARTCOMPOSITES:
1342 keyword = token (fp);
1345 (*fi)->numOfComps = atoi (keyword);
1346 (*fi)->ccd = (AFM_CompCharData *)
1347 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1348 if ((*fi)->ccd == NULL)
1350 error = AFM_storageProblem;
1354 code = parseAFM_CompCharData (fp, *fi);
1356 case ENDFONTMETRICS:
1361 code = AFM_parseError;
1365 if ((error != AFM_earlyEOF) && (code < 0))
1369 if ((error != AFM_earlyEOF) && (code < 0))
1372 if (ident != NULL) { free (ident); ident = NULL; }