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
77 #include "parse-afm.hh"
80 #define METATYPE1_BUG /* Parse Metatype1's (version unknown)
81 'Generated' global tag as comment. */
83 #define lineterm EOL /* line terminating character */
84 #define lineterm_alt '\r' /* alternative line terminating character */
85 #define normalEOF 1 /* return code from parsing routines used only */
87 #define Space "space" /* used in string comparison to look for the width */
88 /* of the space character to init the widths array */
89 #define False "false" /* used in string comparison to check the value of */
90 /* boolean keys (e.g. IsFixedPitch) */
92 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
96 /*************************** GLOBALS ***********************/
98 static char *ident
= NULL
; /* storage buffer for keywords */
101 /* "shorts" for fast case statement
102 * The values of each of these enumerated items correspond to an entry in the
103 * table of strings defined below. Therefore, if you add a new string as
104 * new keyword into the keyStrings table, you must also add a corresponding
105 * parseKey AND it MUST be in the same position!
107 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
108 * keywords must be placed in lexicographical order, below. [Therefore, the
109 * enumerated items are not necessarily in lexicographical order, depending
110 * on the name chosen. BUT, they must be placed in the same position as the
111 * corresponding key string.] The NOPE shall remain in the last position,
112 * since it does not correspond to any key string, and it is used in the
113 * "recognize" procedure to calculate how many possible keys there are.
117 ASCENDER
, CHARBBOX
, CODE
, COMPCHAR
, CAPHEIGHT
, COMMENT
,
118 DESCENDER
, ENCODINGSCHEME
, ENDCHARMETRICS
, ENDCOMPOSITES
,
119 ENDFONTMETRICS
, ENDKERNDATA
, ENDKERNPAIRS
, ENDTRACKKERN
,
120 FAMILYNAME
, FONTBBOX
, FONTNAME
, FULLNAME
,
125 ITALICANGLE
, KERNPAIR
, KERNPAIRXAMT
, LIGATURE
, CHARNAME
,
126 NOTICE
, COMPCHARPIECE
, STARTCHARMETRICS
, STARTCOMPOSITES
,
127 STARTFONTMETRICS
, STARTKERNDATA
, STARTKERNPAIRS
,
128 STARTTRACKKERN
, TRACKKERN
, UNDERLINEPOSITION
,
129 UNDERLINETHICKNESS
, VERSION
, XYWIDTH
, XWIDTH
, WEIGHT
, XHEIGHT
,
132 /* keywords for the system:
133 * This a table of all of the current strings that are vaild AFM keys.
134 * Each entry can be referenced by the appropriate parseKey value (an
135 * enumerated data type defined above). If you add a new keyword here,
136 * a corresponding parseKey MUST be added to the enumerated data type
137 * defined above, AND it MUST be added in the same position as the
138 * string is in this table.
140 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
141 * must be placed in lexicographical order. And, NULL should remain at the
145 static char *keyStrings
[] = {
146 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
147 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
148 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
149 "FamilyName", "FontBBox", "FontName", "FullName",
154 "ItalicAngle", "KP", "KPX", "L", "N",
155 "Notice", "PCC", "StartCharMetrics", "StartComposites",
156 "StartFontMetrics", "StartKernData", "StartKernPairs",
157 "StartTrackKern", "TrackKern", "UnderlinePosition",
158 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
161 /*************************** PARSING ROUTINES **************/
163 /*************************** token *************************/
165 /* A "AFM File Conventions" tokenizer. That means that it will
166 * return the next token delimited by white space. See also
167 * the `linetoken' routine, which does a similar thing but
168 * reads all tokens until the next end-of-line.
176 /* skip over white space */
177 while ((ch
= fgetc (stream
)) == ' ' || ch
== lineterm
||
178 ch
== lineterm_alt
||
179 ch
== ',' || ch
== '\t' || ch
== ';');
182 while (idx
< MAX_NAME
- 1 &&
183 ch
!= EOF
&& ch
!= ' ' && ch
!= lineterm
&& ch
!= lineterm_alt
184 && ch
!= '\t' && ch
!= ':' && ch
!= ';')
190 if (ch
== EOF
&& idx
< 1) return ((char *)NULL
);
191 if (idx
>= 1 && ch
!= ':' ) ungetc (ch
, stream
);
192 if (idx
< 1 ) ident
[idx
++] = ch
; /* single-character token */
195 return (ident
); /* returns pointer to the token */
200 /*************************** linetoken *************************/
202 /* "linetoken" will get read all tokens until the EOL character from
203 * the given stream. This is used to get any arguments that can be
204 * more than one word (like Comment lines and FullName).
208 linetoken (FILE *stream
)
212 while ((ch
= fgetc (stream
)) == ' ' || ch
== '\t' );
215 while (idx
< MAX_NAME
- 1 &&
216 ch
!= EOF
&& ch
!= lineterm
&& ch
!= lineterm_alt
)
225 return (ident
); /* returns pointer to the token */
230 /*************************** recognize *************************/
232 /* This function tries to match a string to a known list of
233 * valid AFM entries (check the keyStrings array above).
234 * "ident" contains everything from white space through the
235 * next space, tab, or ":" character.
237 * The algorithm is a standard Knuth binary search.
241 recognize (register char *ident
)
249 while ((upper
>= lower
) && !found
)
251 midpoint
= (lower
+ upper
)/2;
252 if (keyStrings
[midpoint
] == NULL
)
254 cmpvalue
= strncmp (ident
, keyStrings
[midpoint
], MAX_NAME
);
259 upper
= midpoint
- 1;
261 lower
= midpoint
+ 1;
265 return (enum parseKey
) midpoint
;
271 /************************* parseGlobals *****************************/
273 /* This function is called by "parseFile". It will parse the AFM File
274 * up to the "StartCharMetrics" keyword, which essentially marks the
275 * end of the Global Font Information and the beginning of the character
276 * metrics information.
278 * If the caller of "parseFile" specified that it wanted the Global
279 * Font Information (as defined by the "AFM File Specification"
280 * document), then that information will be stored in the returned
283 * Any Global Font Information entries that are not found in a
284 * given file, will have the usual default initialization value
285 * for its type (i.e. entries of type int will be 0, etc).
287 * This function returns an error code specifying whether there was
288 * a premature EOF or a parsing error. This return value is used by
289 * parseFile to determine if there is more file to parse.
293 parseGlobals (FILE *fp
, register AFM_GlobalFontInfo
*gfi
)
295 BOOL cont
= TRUE
, save
= (gfi
!= NULL
);
297 register char *keyword
;
301 keyword
= token (fp
);
304 /* Have reached an early and unexpected EOF. */
305 /* Set flag and stop parsing */
307 error
= AFM_earlyEOF
;
308 break; /* get out of loop */
311 /* get tokens until the end of the Global Font info section */
312 /* without saving any of the data */
313 switch (recognize (keyword
))
315 case STARTCHARMETRICS
:
326 /* otherwise parse entire global font info section, */
327 /* saving the data */
328 switch (recognize (keyword
))
330 case STARTFONTMETRICS
:
331 keyword
= token (fp
);
332 gfi
->afmVersion
= (char *) malloc (strlen (keyword
) + 1);
333 strcpy (gfi
->afmVersion
, keyword
);
339 keyword
= linetoken (fp
);
342 keyword
= token (fp
);
343 gfi
->fontName
= (char *) malloc (strlen (keyword
) + 1);
344 strcpy (gfi
->fontName
, keyword
);
347 keyword
= token (fp
);
348 gfi
->encodingScheme
= (char *)
349 malloc (strlen (keyword
) + 1);
350 strcpy (gfi
->encodingScheme
, keyword
);
353 keyword
= linetoken (fp
);
354 gfi
->fullName
= (char *) malloc (strlen (keyword
) + 1);
355 strcpy (gfi
->fullName
, keyword
);
358 keyword
= linetoken (fp
);
359 gfi
->familyName
= (char *) malloc (strlen (keyword
) + 1);
360 strcpy (gfi
->familyName
, keyword
);
363 keyword
= token (fp
);
364 gfi
->weight
= (char *) malloc (strlen (keyword
) + 1);
365 strcpy (gfi
->weight
, keyword
);
368 keyword
= token (fp
);
369 gfi
->italicAngle
= atof (keyword
);
370 if (errno
== ERANGE
) error
= AFM_parseError
;
373 keyword
= token (fp
);
374 if (MATCH (keyword
, False
))
375 gfi
->isFixedPitch
= 0;
377 gfi
->isFixedPitch
= 1;
379 case UNDERLINEPOSITION
:
380 keyword
= token (fp
);
381 gfi
->underlinePosition
= atoi (keyword
);
383 case UNDERLINETHICKNESS
:
384 keyword
= token (fp
);
385 gfi
->underlineThickness
= atoi (keyword
);
388 keyword
= linetoken (fp
);
389 gfi
->version
= (char *) malloc (strlen (keyword
) + 1);
390 strcpy (gfi
->version
, keyword
);
393 keyword
= linetoken (fp
);
394 gfi
->notice
= (char *) malloc (strlen (keyword
) + 1);
395 strcpy (gfi
->notice
, keyword
);
398 keyword
= token (fp
);
399 gfi
->fontBBox
.llx
= atoi (keyword
);
400 keyword
= token (fp
);
401 gfi
->fontBBox
.lly
= atoi (keyword
);
402 keyword
= token (fp
);
403 gfi
->fontBBox
.urx
= atoi (keyword
);
404 keyword
= token (fp
);
405 gfi
->fontBBox
.ury
= atoi (keyword
);
408 keyword
= token (fp
);
409 gfi
->capHeight
= atoi (keyword
);
412 keyword
= token (fp
);
413 gfi
->xHeight
= atoi (keyword
);
416 keyword
= token (fp
);
417 gfi
->descender
= atoi (keyword
);
420 keyword
= token (fp
);
421 gfi
->ascender
= atoi (keyword
);
423 case STARTCHARMETRICS
:
432 error
= AFM_parseError
;
443 /************************* initializeArray ************************/
445 /* Unmapped character codes are (at Adobe Systems) assigned the
446 * width of the space character (if one exists) else they get the
447 * value of 250 ems. This function initializes all entries in the
448 * char widths array to have this value. Then any mapped character
449 * codes will be replaced with the width of the appropriate character
450 * when parsing the character metric section.
452 * This function parses the Character Metrics Section looking
453 * for a space character (by comparing character names). If found,
454 * the width of the space character will be used to initialize the
455 * values in the array of character widths.
457 * Before returning, the position of the read/write pointer of the
458 * file is reset to be where it was upon entering this function.
462 initializeArray (FILE *fp
, register int *cwi
)
464 BOOL cont
= TRUE
, found
= FALSE
;
465 long opos
= ftell (fp
);
466 int code
= 0, width
= 0, i
= 0, error
= 0;
467 register char *keyword
;
471 keyword
= token (fp
);
474 error
= AFM_earlyEOF
;
475 break; /* get out of loop */
477 switch (recognize (keyword
))
480 keyword
= linetoken (fp
);
483 code
= atoi (token (fp
));
486 width
= atoi (token (fp
));
489 keyword
= token (fp
);
490 if (MATCH (keyword
, Space
))
505 error
= AFM_parseError
;
513 for (i
= 0; i
< 256; ++i
)
520 } /* initializeArray */
523 /************************* parseCharWidths **************************/
525 /* This function is called by "parseFile". It will parse the AFM File
526 * up to the "EndCharMetrics" keyword. It will save the character
527 * width info (as opposed to all of the character metric information)
528 * if requested by the caller of parseFile. Otherwise, it will just
529 * parse through the section without saving any information.
531 * If data is to be saved, parseCharWidths is passed in a pointer
532 * to an array of widths that has already been initialized by the
533 * standard value for unmapped character codes. This function parses
534 * the Character Metrics section only storing the width information
535 * for the encoded characters into the array using the character code
536 * as the index into that array.
538 * This function returns an error code specifying whether there was
539 * a premature EOF or a parsing error. This return value is used by
540 * parseFile to determine if there is more file to parse.
544 parseCharWidths (FILE *fp
, register int *cwi
)
546 BOOL cont
= TRUE
, save
= (cwi
!= NULL
);
547 int pos
= 0, error
= AFM_ok
;
548 register char *keyword
;
552 keyword
= token (fp
);
553 /* Have reached an early and unexpected EOF. */
554 /* Set flag and stop parsing */
557 error
= AFM_earlyEOF
;
558 break; /* get out of loop */
561 /* get tokens until the end of the Char Metrics section without */
562 /* saving any of the data*/
563 switch (recognize (keyword
))
576 /* otherwise parse entire char metrics section, saving */
577 /* only the char x-width info */
578 switch (recognize (keyword
))
581 keyword
= linetoken (fp
);
584 keyword
= token (fp
);
585 pos
= atoi (keyword
);
588 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
589 keyword
= token (fp
); keyword
= token (fp
); /* eat values */
590 error
= AFM_parseError
;
593 keyword
= token (fp
);
594 if (pos
>= 0) /* ignore unmapped chars */
595 cwi
[pos
] = atoi (keyword
);
604 case CHARNAME
: /* eat values (so doesn't cause AFM_parseError) */
605 keyword
= token (fp
);
608 keyword
= token (fp
); keyword
= token (fp
);
609 keyword
= token (fp
); keyword
= token (fp
);
612 keyword
= token (fp
); keyword
= token (fp
);
616 error
= AFM_parseError
;
623 } /* parseCharWidths */
626 /************************* parseCharMetrics ************************/
628 /* This function is called by parseFile if the caller of parseFile
629 * requested that all character metric information be saved
630 * (as opposed to only the character width information).
632 * parseCharMetrics is passed in a pointer to an array of records
633 * to hold information on a per character basis. This function
634 * parses the Character Metrics section storing all character
635 * metric information for the ALL characters (mapped and unmapped)
638 * This function returns an error code specifying whether there was
639 * a premature EOF or a parsing error. This return value is used by
640 * parseFile to determine if there is more file to parse.
644 parseCharMetrics (FILE *fp
, register AFM_Font_info
*fi
)
646 BOOL cont
= TRUE
, firstTime
= TRUE
;
647 int error
= AFM_ok
, count
= 0;
648 register AFM_CharMetricInfo
*temp
= fi
->cmi
;
649 register char *keyword
;
653 keyword
= token (fp
);
656 error
= AFM_earlyEOF
;
657 break; /* get out of loop */
659 switch (recognize (keyword
))
662 keyword
= linetoken (fp
);
665 if (count
< fi
->numOfChars
)
671 temp
->code
= atoi (token (fp
));
676 warning ("Too many metrics.");
677 error
= AFM_parseError
;
682 temp
->wx
= atoi (token (fp
));
683 temp
->wy
= atoi (token (fp
));
686 temp
->wx
= atoi (token (fp
));
690 keyword
= token (fp
);
691 temp
->name
= (char *) malloc (strlen (keyword
) + 1);
692 strcpy (temp
->name
, keyword
);
696 temp
->charBBox
.llx
= atoi (token (fp
));
697 temp
->charBBox
.lly
= atoi (token (fp
));
698 temp
->charBBox
.urx
= atoi (token (fp
));
699 temp
->charBBox
.ury
= atoi (token (fp
));
703 AFM_Ligature
**tail
= & (temp
->ligs
);
704 AFM_Ligature
*node
= *tail
;
708 while (node
->next
!= NULL
)
710 tail
= & (node
->next
);
713 *tail
= (AFM_Ligature
*) calloc (1, sizeof (AFM_Ligature
));
714 keyword
= token (fp
);
715 (*tail
)->succ
= (char *) malloc (strlen (keyword
) + 1);
716 strcpy ((*tail
)->succ
, keyword
);
717 keyword
= token (fp
);
718 (*tail
)->lig
= (char *) malloc (strlen (keyword
) + 1);
719 strcpy ((*tail
)->lig
, keyword
);
730 warning ("Unknown token");
732 error
= AFM_parseError
;
737 if ((error
== AFM_ok
) && (count
!= fi
->numOfChars
))
739 warning ("Incorrect char count");
740 error
= AFM_parseError
;
744 } /* parseCharMetrics */
748 /************************* parseAFM_TrackKernData ***********************/
750 /* This function is called by "parseFile". It will parse the AFM File
751 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
752 * track kerning data if requested by the caller of parseFile.
754 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
755 * If data is to be saved, the FontInfo record will already contain
756 * a valid pointer to storage for the track kerning data.
758 * This function returns an error code specifying whether there was
759 * a premature EOF or a parsing error. This return value is used by
760 * parseFile to determine if there is more file to parse.
764 parseAFM_TrackKernData (FILE *fp
, register AFM_Font_info
*fi
)
766 BOOL cont
= TRUE
, save
= (fi
->tkd
!= NULL
);
767 int pos
= 0, error
= AFM_ok
, tcount
= 0;
768 register char *keyword
;
772 keyword
= token (fp
);
776 error
= AFM_earlyEOF
;
777 break; /* get out of loop */
780 /* get tokens until the end of the Track Kerning Data */
781 /* section without saving any of the data */
782 switch (recognize (keyword
))
796 /* otherwise parse entire Track Kerning Data section, */
797 /* saving the data */
798 switch (recognize (keyword
))
804 keyword
= linetoken (fp
);
807 if (tcount
< fi
->numOfTracks
)
809 keyword
= token (fp
);
810 fi
->tkd
[pos
].degree
= atoi (keyword
);
811 keyword
= token (fp
);
812 fi
->tkd
[pos
].minPtSize
= atof (keyword
);
813 if (errno
== ERANGE
) error
= AFM_parseError
;
814 keyword
= token (fp
);
815 fi
->tkd
[pos
].minKernAmt
= atof (keyword
);
816 if (errno
== ERANGE
) error
= AFM_parseError
;
817 keyword
= token (fp
);
818 fi
->tkd
[pos
].maxPtSize
= atof (keyword
);
819 if (errno
== ERANGE
) error
= AFM_parseError
;
820 keyword
= token (fp
);
821 fi
->tkd
[pos
++].maxKernAmt
= atof (keyword
);
822 if (errno
== ERANGE
) error
= AFM_parseError
;
827 error
= AFM_parseError
;
841 error
= AFM_parseError
;
846 if (error
== AFM_ok
&& tcount
!= fi
->numOfTracks
)
847 error
= AFM_parseError
;
851 } /* parseAFM_TrackKernData */
854 /************************* parseAFM_PairKernData ************************/
856 /* This function is called by "parseFile". It will parse the AFM File
857 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
858 * the pair kerning data if requested by the caller of parseFile.
860 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
861 * If data is to be saved, the FontInfo record will already contain
862 * a valid pointer to storage for the pair kerning data.
864 * This function returns an error code specifying whether there was
865 * a premature EOF or a parsing error. This return value is used by
866 * parseFile to determine if there is more file to parse.
870 parseAFM_PairKernData (FILE *fp
, register AFM_Font_info
*fi
)
872 BOOL cont
= TRUE
, save
= (fi
->pkd
!= NULL
);
873 int pos
= 0, error
= AFM_ok
, pcount
= 0;
874 register char *keyword
;
878 keyword
= token (fp
);
882 error
= AFM_earlyEOF
;
883 break; /* get out of loop */
886 /* get tokens until the end of the Pair Kerning Data */
887 /* section without saving any of the data */
888 switch (recognize (keyword
))
902 /* otherwise parse entire Pair Kerning Data section, */
903 /* saving the data */
904 switch (recognize (keyword
))
907 keyword
= linetoken (fp
);
910 if (pcount
< fi
->numOfPairs
)
912 keyword
= token (fp
);
913 fi
->pkd
[pos
].name1
= (char *)
914 malloc (strlen (keyword
) + 1);
915 strcpy (fi
->pkd
[pos
].name1
, keyword
);
916 keyword
= token (fp
);
917 fi
->pkd
[pos
].name2
= (char *)
918 malloc (strlen (keyword
) + 1);
919 strcpy (fi
->pkd
[pos
].name2
, keyword
);
920 keyword
= token (fp
);
921 fi
->pkd
[pos
].xamt
= atoi (keyword
);
922 keyword
= token (fp
);
923 fi
->pkd
[pos
++].yamt
= atoi (keyword
);
928 error
= AFM_parseError
;
933 if (pcount
< fi
->numOfPairs
)
935 keyword
= token (fp
);
936 fi
->pkd
[pos
].name1
= (char *)
937 malloc (strlen (keyword
) + 1);
938 strcpy (fi
->pkd
[pos
].name1
, keyword
);
939 keyword
= token (fp
);
940 fi
->pkd
[pos
].name2
= (char *)
941 malloc (strlen (keyword
) + 1);
942 strcpy (fi
->pkd
[pos
].name2
, keyword
);
943 keyword
= token (fp
);
944 fi
->pkd
[pos
++].xamt
= atoi (keyword
);
949 error
= AFM_parseError
;
963 error
= AFM_parseError
;
968 if (error
== AFM_ok
&& pcount
!= fi
->numOfPairs
)
969 error
= AFM_parseError
;
973 } /* parseAFM_PairKernData */
976 /************************* parseAFM_CompCharData **************************/
978 /* This function is called by "parseFile". It will parse the AFM File
979 * up to the "EndComposites" keyword. It will save the composite
980 * character data if requested by the caller of parseFile.
982 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
983 * a boolean representing if the data should be saved.
985 * This function will create the appropriate amount of storage for
986 * the composite character data and store a pointer to the storage
987 * in the FontInfo record.
989 * This function returns an error code specifying whether there was
990 * a premature EOF or a parsing error. This return value is used by
991 * parseFile to determine if there is more file to parse.
995 parseAFM_CompCharData (FILE *fp
, register AFM_Font_info
*fi
)
997 BOOL cont
= TRUE
, firstTime
= TRUE
, save
= (fi
->ccd
!= NULL
);
998 int pos
= 0, j
= 0, error
= AFM_ok
, ccount
= 0, pcount
= 0;
999 register char *keyword
;
1003 keyword
= token (fp
);
1004 if (keyword
== NULL
)
1005 /* Have reached an early and unexpected EOF. */
1006 /* Set flag and stop parsing */
1008 error
= AFM_earlyEOF
;
1009 break; /* get out of loop */
1011 if (ccount
> fi
->numOfComps
)
1013 error
= AFM_parseError
;
1014 break; /* get out of loop */
1017 /* get tokens until the end of the Composite Character info */
1018 /* section without saving any of the data */
1019 switch (recognize (keyword
))
1024 case ENDFONTMETRICS
:
1032 /* otherwise parse entire Composite Character info section, */
1033 /* saving the data */
1034 switch (recognize (keyword
))
1037 keyword
= linetoken (fp
);
1040 if (ccount
< fi
->numOfComps
)
1042 keyword
= token (fp
);
1043 if (pcount
!= fi
->ccd
[pos
].numOfPieces
)
1044 error
= AFM_parseError
;
1046 if (firstTime
) firstTime
= FALSE
;
1048 fi
->ccd
[pos
].ccName
= (char *)
1049 malloc (strlen (keyword
) + 1);
1050 strcpy (fi
->ccd
[pos
].ccName
, keyword
);
1051 keyword
= token (fp
);
1052 fi
->ccd
[pos
].numOfPieces
= atoi (keyword
);
1053 fi
->ccd
[pos
].pieces
= (AFM_Pcc
*)
1054 calloc (fi
->ccd
[pos
].numOfPieces
, sizeof (AFM_Pcc
));
1060 error
= AFM_parseError
;
1065 if (pcount
< fi
->ccd
[pos
].numOfPieces
)
1067 keyword
= token (fp
);
1068 fi
->ccd
[pos
].pieces
[j
].AFM_PccName
= (char *)
1069 malloc (strlen (keyword
) + 1);
1070 strcpy (fi
->ccd
[pos
].pieces
[j
].AFM_PccName
, keyword
);
1071 keyword
= token (fp
);
1072 fi
->ccd
[pos
].pieces
[j
].deltax
= atoi (keyword
);
1073 keyword
= token (fp
);
1074 fi
->ccd
[pos
].pieces
[j
++].deltay
= atoi (keyword
);
1078 error
= AFM_parseError
;
1083 case ENDFONTMETRICS
:
1089 error
= AFM_parseError
;
1094 if (error
== AFM_ok
&& ccount
!= fi
->numOfComps
)
1095 error
= AFM_parseError
;
1099 } /* parseAFM_CompCharData */
1104 /*************************** 'PUBLIC' FUNCTION ********************/
1107 AFM_free (AFM_Font_info
*fi
)
1110 free (fi
->gfi
->afmVersion
);
1111 free (fi
->gfi
->fontName
);
1112 free (fi
->gfi
->fullName
);
1113 free (fi
->gfi
->familyName
);
1114 free (fi
->gfi
->weight
);
1115 free (fi
->gfi
->version
);
1116 free (fi
->gfi
->notice
);
1117 free (fi
->gfi
->encodingScheme
);
1121 /* This contains just scalars. */
1126 for (i
= 0; i
< fi
->numOfChars
; i
++) {
1127 free (fi
->cmi
[i
].name
);
1128 while (fi
->cmi
[i
].ligs
) {
1130 tmp
= fi
->cmi
[i
].ligs
;
1134 fi
->cmi
[i
].ligs
= fi
->cmi
[i
].ligs
->next
;
1140 /* This contains just scalars. */
1145 for (i
= 0; i
< fi
->numOfPairs
; i
++) {
1146 free (fi
->pkd
[i
].name1
);
1147 free (fi
->pkd
[i
].name2
);
1154 for (i
= 0; i
< fi
->numOfComps
; i
++) {
1155 free (fi
->ccd
[i
].ccName
);
1156 for (j
= 0; j
< fi
->ccd
[i
].numOfPieces
; j
++) {
1157 free (fi
->ccd
[i
].pieces
[j
].AFM_PccName
);
1159 free (fi
->ccd
[i
].pieces
);
1168 /*************************** parseFile *****************************/
1170 /* parseFile is the only 'public' procedure available. It is called
1171 * from an application wishing to get information from an AFM file.
1172 * The caller of this function is responsible for locating and opening
1173 * an AFM file and handling all errors associated with that task.
1175 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1176 * to a (FontInfo *) variable (for which storage will be allocated and
1177 * the data requested filled in), and a mask specifying which
1178 * data from the AFM File should be saved in the FontInfo structure.
1180 * The file will be parsed and the requested data will be stored in
1181 * a record of type FontInfo (refer to ParseAFM.h).
1183 * parseFile returns an error code as defined in parseAFM.h.
1185 * The position of the read/write pointer associated with the file
1186 * pointer upon return of this function is undefined.
1190 AFM_parseFile (FILE *fp
, AFM_Font_info
**fi
, int flags
)
1193 int code
= AFM_ok
; /* return code from each of the parsing routines */
1194 int error
= AFM_ok
; /* used as the return code from this function */
1196 register char *keyword
; /* used to store a token */
1199 /* storage data for the global variable ident */
1201 ident
= (char *) calloc (MAX_NAME
, sizeof (char));
1204 error
= AFM_storageProblem
;
1208 (*fi
) = (AFM_Font_info
*) calloc (1, sizeof (AFM_Font_info
));
1211 error
= AFM_storageProblem
;
1217 (*fi
)->gfi
= (AFM_GlobalFontInfo
*) calloc (1,
1218 sizeof (AFM_GlobalFontInfo
));
1219 if ((*fi
)->gfi
== NULL
)
1221 error
= AFM_storageProblem
;
1226 /* The AFM File begins with Global Font Information. This section */
1227 /* will be parsed whether or not information should be saved. */
1228 code
= parseGlobals (fp
, (*fi
)->gfi
);
1233 /* The Global Font Information is followed by the Character Metrics */
1234 /* section. Which procedure is used to parse this section depends on */
1235 /* how much information should be saved. If all of the metrics info */
1236 /* is wanted, parseCharMetrics is called. If only the character widths */
1237 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1238 /* be called in the case that no character data is to be saved, just */
1239 /* to parse through the section. */
1241 if ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1243 (*fi
)->numOfChars
= atoi (token (fp
));
1244 if (flags
& (P_M
^ P_W
))
1246 (*fi
)->cmi
= (AFM_CharMetricInfo
*)
1247 calloc ((*fi
)->numOfChars
, sizeof (AFM_CharMetricInfo
));
1248 if ((*fi
)->cmi
== NULL
)
1250 error
= AFM_storageProblem
;
1253 code
= parseCharMetrics (fp
, *fi
);
1259 (*fi
)->cwi
= (int *) calloc (256, sizeof (int));
1260 if ((*fi
)->cwi
== NULL
)
1262 error
= AFM_storageProblem
;
1266 /* parse section regardless */
1267 code
= parseCharWidths (fp
, (*fi
)->cwi
);
1271 if ((error
!= AFM_earlyEOF
) && (code
< 0))
1274 /* The remaining sections of the AFM are optional. This code will */
1275 /* look at the next keyword in the file to determine what section */
1276 /* is next, and then allocate the appropriate amount of storage */
1277 /* for the data (if the data is to be saved) and call the */
1278 /* appropriate parsing routine to parse the section. */
1280 while ((code
!= normalEOF
) && (code
!= AFM_earlyEOF
))
1282 keyword
= token (fp
);
1283 if (keyword
== NULL
)
1284 /* Have reached an early and unexpected EOF. */
1285 /* Set flag and stop parsing */
1287 code
= AFM_earlyEOF
;
1288 break; /* get out of loop */
1290 switch (recognize (keyword
))
1296 case STARTTRACKKERN
:
1297 keyword
= token (fp
);
1300 (*fi
)->numOfTracks
= atoi (keyword
);
1301 (*fi
)->tkd
= (AFM_TrackKernData
*)
1302 calloc ((*fi
)->numOfTracks
, sizeof (AFM_TrackKernData
));
1303 if ((*fi
)->tkd
== NULL
)
1305 error
= AFM_storageProblem
;
1309 code
= parseAFM_TrackKernData (fp
, *fi
);
1311 case STARTKERNPAIRS
:
1312 keyword
= token (fp
);
1315 (*fi
)->numOfPairs
= atoi (keyword
);
1316 (*fi
)->pkd
= (AFM_PairKernData
*)
1317 calloc ((*fi
)->numOfPairs
, sizeof (AFM_PairKernData
));
1318 if ((*fi
)->pkd
== NULL
)
1320 error
= AFM_storageProblem
;
1324 code
= parseAFM_PairKernData (fp
, *fi
);
1326 case STARTCOMPOSITES
:
1327 keyword
= token (fp
);
1330 (*fi
)->numOfComps
= atoi (keyword
);
1331 (*fi
)->ccd
= (AFM_CompCharData
*)
1332 calloc ((*fi
)->numOfComps
, sizeof (AFM_CompCharData
));
1333 if ((*fi
)->ccd
== NULL
)
1335 error
= AFM_storageProblem
;
1339 code
= parseAFM_CompCharData (fp
, *fi
);
1341 case ENDFONTMETRICS
:
1346 code
= AFM_parseError
;
1350 if ((error
!= AFM_earlyEOF
) && (code
< 0))
1355 if ((error
!= AFM_earlyEOF
) && (code
< 0))
1358 if (ident
!= NULL
) { free (ident
); ident
= NULL
; }