1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "halibut.h"
4 #include "paper.h"
5 
afm_read_line(input * in)6 char *afm_read_line(input *in) {
7     int i, len = 256;
8     int c;
9     char *line;
10 
11     do {
12 	i = 0;
13 	in->pos.line++;
14 	c = getc(in->currfp);
15 	if (c == EOF) {
16 	    err_afmeof(&in->pos);
17 	    return NULL;
18 	}
19 	line = snewn(len, char);
20 	while (c != EOF && c != '\r' && c != '\n') {
21 	    if (i >= len - 1) {
22 		len += 256;
23 		line = sresize(line, len, char);
24 	    }
25 	    line[i++] = c;
26 	    c = getc(in->currfp);
27 	}
28 	if (c == '\r') {
29 	    /* Cope with CRLF terminated lines */
30 	    c = getc(in->currfp);
31 	    if (c != '\n' && c != EOF)
32 		ungetc(c, in->currfp);
33 	}
34 	line[i] = 0;
35     } while (line[(strspn(line, " \t"))] == 0 ||
36 	     strncmp(line, "Comment ", 8) == 0 ||
37 	     strncmp(line, "Comment\t", 8) == 0);
38 
39     return line;
40 }
41 
afm_require_key(char * line,char const * expected,input * in)42 static int afm_require_key(char *line, char const *expected, input *in) {
43     char *key = strtok(line, " \t");
44 
45     if (strcmp(key, expected) == 0)
46 	return TRUE;
47     err_afmkey(&in->pos, expected);
48     return FALSE;
49 }
50 
read_afm_file(input * in)51 void read_afm_file(input *in) {
52     char *line, *key, *val;
53     font_info *fi;
54     size_t i;
55 
56     fi = snew(font_info);
57     fi->name = NULL;
58     fi->widths = newtree234(width_cmp);
59     fi->fontfile = NULL;
60     fi->kerns = newtree234(kern_cmp);
61     fi->ligs = newtree234(lig_cmp);
62     fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
63     fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
64     fi->stemh = fi->stemv = fi->italicangle = 0;
65     for (i = 0; i < lenof(fi->bmp); i++)
66 	    fi->bmp[i] = 0xFFFF;
67     in->pos.line = 0;
68     line = afm_read_line(in);
69     if (!line || !afm_require_key(line, "StartFontMetrics", in))
70 	goto giveup;
71     if (!(val = strtok(NULL, " \t"))) {
72 	err_afmval(&in->pos, "StartFontMetrics", 1);
73 	goto giveup;
74     }
75     if (atof(val) >= 5.0) {
76 	err_afmvers(&in->pos);
77 	goto giveup;
78     }
79     sfree(line);
80     for (;;) {
81 	line = afm_read_line(in);
82 	if (line == NULL)
83 	    goto giveup;
84 	key = strtok(line, " \t");
85 	if (strcmp(key, "EndFontMetrics") == 0) {
86 	    fi->next = all_fonts;
87 	    all_fonts = fi;
88 	    fclose(in->currfp);
89 	    return;
90 	} else if (strcmp(key, "FontName") == 0) {
91 	    if (!(val = strtok(NULL, " \t"))) {
92 		err_afmval(&in->pos, key, 1);
93 		goto giveup;
94 	    }
95 	    fi->name = dupstr(val);
96 	} else if (strcmp(key, "FontBBox") == 0) {
97 	    int i;
98 	    for (i = 0; i < 3; i++) {
99 		if (!(val = strtok(NULL, " \t"))) {
100 		    err_afmval(&in->pos, key, 4);
101 		    goto giveup;
102 		}
103 		fi->fontbbox[i] = atof(val);
104 	    }
105 	} else if (strcmp(key, "CapHeight") == 0) {
106 	    if (!(val = strtok(NULL, " \t"))) {
107 		err_afmval(&in->pos, key, 1);
108 		goto giveup;
109 	    }
110 	    fi->capheight = atof(val);
111 	} else if (strcmp(key, "XHeight") == 0) {
112 	    if (!(val = strtok(NULL, " \t"))) {
113 		err_afmval(&in->pos, key, 1);
114 		goto giveup;
115 	    }
116 	    fi->xheight = atof(val);
117 	} else if (strcmp(key, "Ascender") == 0) {
118 	    if (!(val = strtok(NULL, " \t"))) {
119 		err_afmval(&in->pos, key, 1);
120 		goto giveup;
121 	    }
122 	    fi->ascent = atof(val);
123 	} else if (strcmp(key, "Descender") == 0) {
124 	    if (!(val = strtok(NULL, " \t"))) {
125 		err_afmval(&in->pos, key, 1);
126 		goto giveup;
127 	    }
128 	    fi->descent = atof(val);
129 	} else if (strcmp(key, "CapHeight") == 0) {
130 	    if (!(val = strtok(NULL, " \t"))) {
131 		err_afmval(&in->pos, key, 1);
132 		goto giveup;
133 	    }
134 	    fi->capheight = atof(val);
135 	} else if (strcmp(key, "StdHW") == 0) {
136 	    if (!(val = strtok(NULL, " \t"))) {
137 		err_afmval(&in->pos, key, 1);
138 		goto giveup;
139 	    }
140 	    fi->stemh = atof(val);
141 	} else if (strcmp(key, "StdVW") == 0) {
142 	    if (!(val = strtok(NULL, " \t"))) {
143 		err_afmval(&in->pos, key, 1);
144 		goto giveup;
145 	    }
146 	    fi->stemv = atof(val);
147 	} else if (strcmp(key, "ItalicAngle") == 0) {
148 	    if (!(val = strtok(NULL, " \t"))) {
149 		err_afmval(&in->pos, key, 1);
150 		goto giveup;
151 	    }
152 	    fi->italicangle = atof(val);
153 	} else if (strcmp(key, "StartCharMetrics") == 0) {
154 	    int nglyphs, i;
155 	    if (!(val = strtok(NULL, " \t"))) {
156 		err_afmval(&in->pos, key, 1);
157 		goto giveup;
158 	    }
159 	    nglyphs = atoi(val);
160 	    sfree(line);
161 	    for (i = 0; i < nglyphs; i++) {
162 		int width = 0;
163 		glyph g = NOGLYPH;
164 
165 		line = afm_read_line(in);
166 		if (line == NULL)
167 		    goto giveup;
168 		key = strtok(line, " \t");
169 		while (key != NULL) {
170 		    if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
171 			if (!(val = strtok(NULL, " \t")) ||
172 			    !strcmp(val, ";")) {
173 			    err_afmval(&in->pos, key, 1);
174 			    goto giveup;
175 			}
176 			width = atoi(val);
177 		    } else if (strcmp(key, "N") == 0) {
178 			if (!(val = strtok(NULL, " \t")) ||
179 			    !strcmp(val, ";")) {
180 			    err_afmval(&in->pos, key, 1);
181 			    goto giveup;
182 			}
183 			g = glyph_intern(val);
184 		    } else if (strcmp(key, "L") == 0) {
185 			glyph succ, lig;
186 			if (!(val = strtok(NULL, " \t")) ||
187 			    !strcmp(val, ";")) {
188 			    err_afmval(&in->pos, key, 1);
189 			    goto giveup;
190 			}
191 			succ = glyph_intern(val);
192 			if (!(val = strtok(NULL, " \t")) ||
193 			    !strcmp(val, ";")) {
194 			    err_afmval(&in->pos, key, 1);
195 			    goto giveup;
196 			}
197 			lig = glyph_intern(val);
198 			if (g != NOGLYPH && succ != NOGLYPH &&
199 			    lig != NOGLYPH) {
200 			    ligature *l = snew(ligature);
201 			    l->left = g;
202 			    l->right = succ;
203 			    l->lig = lig;
204 			    add234(fi->ligs, l);
205 			}
206 		    }
207 		    do {
208 			key = strtok(NULL, " \t");
209 		    } while (key && strcmp(key, ";"));
210 		    key = strtok(NULL, " \t");
211 		}
212 		sfree(line);
213 		if (width != 0 && g != NOGLYPH) {
214 		    wchar_t ucs;
215 		    glyph_width *w = snew(glyph_width);
216 		    w->glyph = g;
217 		    w->width = width;
218 		    add234(fi->widths, w);
219 		    ucs = ps_glyph_to_unicode(g);
220 		    if (ucs < 0xFFFF)
221 			fi->bmp[ucs] = g;
222 		}
223 	    }
224 	    line = afm_read_line(in);
225 	    if (!line || !afm_require_key(line, "EndCharMetrics", in))
226 		goto giveup;
227 	    sfree(line);
228 
229 	} else if (strcmp(key, "StartKernPairs") == 0 ||
230 		   strcmp(key, "StartKernPairs0") == 0) {
231 	    int nkerns, i;
232 	    if (!(val = strtok(NULL, " \t"))) {
233 		err_afmval(&in->pos, key, 1);
234 		goto giveup;
235 	    }
236 	    nkerns = atoi(val);
237 	    sfree(line);
238 	    for (i = 0; i < nkerns; i++) {
239 		line = afm_read_line(in);
240 		if (line == NULL)
241 		    goto giveup;
242 		key = strtok(line, " \t");
243 		if (strcmp(key, "KPX") == 0) {
244 		    char *nl, *nr;
245 		    int l, r;
246 		    kern_pair *kp;
247 		    nl = strtok(NULL, " \t");
248 		    nr = strtok(NULL, " \t");
249 		    val = strtok(NULL, " \t");
250 		    if (!val) {
251 			err_afmval(&in->pos, key, 3);
252 			goto giveup;
253 		    }
254 		    l = glyph_intern(nl);
255 		    r = glyph_intern(nr);
256 		    if (l == -1 || r == -1) continue;
257 		    kp = snew(kern_pair);
258 		    kp->left = l;
259 		    kp->right = r;
260 		    kp->kern = atoi(val);
261 		    add234(fi->kerns, kp);
262 		}
263 	    }
264 	    line = afm_read_line(in);
265 	    if (!line || !afm_require_key(line, "EndKernPairs", in))
266 		goto giveup;
267 	    sfree(line);
268 	}
269     }
270   giveup:
271     sfree(fi);
272     fclose(in->currfp);
273     return;
274 }
275