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 != ';')
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)
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 */