Generate a more-or-less valid /FontDescriptor dictionary for non-standard
[sgt/halibut] / in_afm.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "halibut.h"
4 #include "paper.h"
5
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 error(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
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 error(err_afmkey, &in->pos, expected);
48 return FALSE;
49 }
50
51 void read_afm_file(input *in) {
52 char *line, *key, *val;
53 font_info *fi;
54
55 fi = snew(font_info);
56 fi->name = NULL;
57 fi->nglyphs = 0;
58 fi->glyphs = NULL;
59 fi->widths = NULL;
60 fi->kerns = newtree234(kern_cmp);
61 fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
62 fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
63 fi->stemh = fi->stemv = fi->italicangle = 0;
64 in->pos.line = 0;
65 line = afm_read_line(in);
66 if (!line || !afm_require_key(line, "StartFontMetrics", in))
67 goto giveup;
68 if (!(val = strtok(NULL, " \t"))) {
69 error(err_afmval, in->pos, "StartFontMetrics", 1);
70 goto giveup;
71 }
72 if (atof(val) >= 5.0) {
73 error(err_afmvers, &in->pos);
74 goto giveup;
75 }
76 sfree(line);
77 for (;;) {
78 line = afm_read_line(in);
79 if (line == NULL)
80 goto giveup;
81 key = strtok(line, " \t");
82 if (strcmp(key, "EndFontMetrics") == 0) {
83 fi->next = all_fonts;
84 all_fonts = fi;
85 fclose(in->currfp);
86 return;
87 } else if (strcmp(key, "FontName") == 0) {
88 if (!(val = strtok(NULL, " \t"))) {
89 error(err_afmval, &in->pos, key, 1);
90 goto giveup;
91 }
92 fi->name = dupstr(val);
93 } else if (strcmp(key, "FontBBox") == 0) {
94 int i;
95 for (i = 0; i < 3; i++) {
96 if (!(val = strtok(NULL, " \t"))) {
97 error(err_afmval, &in->pos, key, 4);
98 goto giveup;
99 }
100 fi->fontbbox[i] = atof(val);
101 }
102 } else if (strcmp(key, "CapHeight") == 0) {
103 if (!(val = strtok(NULL, " \t"))) {
104 error(err_afmval, &in->pos, key, 1);
105 goto giveup;
106 }
107 fi->capheight = atof(val);
108 } else if (strcmp(key, "XHeight") == 0) {
109 if (!(val = strtok(NULL, " \t"))) {
110 error(err_afmval, &in->pos, key, 1);
111 goto giveup;
112 }
113 fi->xheight = atof(val);
114 } else if (strcmp(key, "Ascender") == 0) {
115 if (!(val = strtok(NULL, " \t"))) {
116 error(err_afmval, &in->pos, key, 1);
117 goto giveup;
118 }
119 fi->ascent = atof(val);
120 } else if (strcmp(key, "Descender") == 0) {
121 if (!(val = strtok(NULL, " \t"))) {
122 error(err_afmval, &in->pos, key, 1);
123 goto giveup;
124 }
125 fi->descent = atof(val);
126 } else if (strcmp(key, "CapHeight") == 0) {
127 if (!(val = strtok(NULL, " \t"))) {
128 error(err_afmval, &in->pos, key, 1);
129 goto giveup;
130 }
131 fi->capheight = atof(val);
132 } else if (strcmp(key, "StdHW") == 0) {
133 if (!(val = strtok(NULL, " \t"))) {
134 error(err_afmval, &in->pos, key, 1);
135 goto giveup;
136 }
137 fi->stemh = atof(val);
138 } else if (strcmp(key, "StdVW") == 0) {
139 if (!(val = strtok(NULL, " \t"))) {
140 error(err_afmval, &in->pos, key, 1);
141 goto giveup;
142 }
143 fi->stemv = atof(val);
144 } else if (strcmp(key, "ItalicAngle") == 0) {
145 if (!(val = strtok(NULL, " \t"))) {
146 error(err_afmval, &in->pos, key, 1);
147 goto giveup;
148 }
149 fi->italicangle = atof(val);
150 } else if (strcmp(key, "StartCharMetrics") == 0) {
151 char const **glyphs;
152 int *widths;
153 int i;
154 if (!(val = strtok(NULL, " \t"))) {
155 error(err_afmval, &in->pos, key, 1);
156 goto giveup;
157 }
158 fi->nglyphs = atoi(val);
159 sfree(line);
160 glyphs = snewn(fi->nglyphs, char const *);
161 widths = snewn(fi->nglyphs, int);
162 for (i = 0; i < fi->nglyphs; i++) {
163 glyphs[i] = NULL;
164 line = afm_read_line(in);
165 if (line == NULL)
166 goto giveup;
167 key = strtok(line, " \t");
168 while (key != NULL) {
169 if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
170 if (!(val = strtok(NULL, " \t")) ||
171 !strcmp(val, ";")) {
172 error(err_afmval, &in->pos, key, 1);
173 goto giveup;
174 }
175 widths[i] = atoi(val);
176 } else if (strcmp(key, "N") == 0) {
177 if (!(val = strtok(NULL, " \t")) ||
178 !strcmp(val, ";")) {
179 error(err_afmval, &in->pos, key, 1);
180 goto giveup;
181 }
182 glyphs[i] = dupstr(val);
183 }
184 do {
185 key = strtok(NULL, " \t");
186 } while (key && strcmp(key, ";"));
187 key = strtok(NULL, " \t");
188 }
189 sfree(line);
190 }
191 line = afm_read_line(in);
192 if (!line || !afm_require_key(line, "EndCharMetrics", in))
193 goto giveup;
194 sfree(line);
195 fi->glyphs = glyphs;
196 fi->widths = widths;
197
198 for (i = 0; i < fi->nglyphs; i++) {
199 wchar_t ucs;
200 ucs = ps_glyph_to_unicode(fi->glyphs[i]);
201 if (ucs < 0xFFFF)
202 fi->bmp[ucs] = i;
203 }
204 font_index_glyphs(fi);
205 } else if (strcmp(key, "StartKernPairs") == 0 ||
206 strcmp(key, "StartKernPairs0") == 0) {
207 int nkerns, i;
208 kern_pair *kerns;
209 if (!(val = strtok(NULL, " \t"))) {
210 error(err_afmval, &in->pos, key, 1);
211 goto giveup;
212 }
213 nkerns = atoi(val);
214 sfree(line);
215 kerns = snewn(nkerns, kern_pair);
216 for (i = 0; i < nkerns; i++) {
217 line = afm_read_line(in);
218 if (line == NULL)
219 goto giveup;
220 key = strtok(line, " \t");
221 if (strcmp(key, "KPX") == 0) {
222 char *nl, *nr;
223 int l, r;
224 kern_pair *kp;
225 nl = strtok(NULL, " \t");
226 nr = strtok(NULL, " \t");
227 val = strtok(NULL, " \t");
228 if (!val) {
229 error(err_afmval, &in->pos, key, 3);
230 goto giveup;
231 }
232 l = find_glyph(fi, nl);
233 r = find_glyph(fi, nr);
234 if (l == -1 || r == -1) continue;
235 kp = snew(kern_pair);
236 kp->left = l;
237 kp->right = r;
238 kp->kern = atoi(val);
239 add234(fi->kerns, kp);
240 }
241 }
242 line = afm_read_line(in);
243 if (!line || !afm_require_key(line, "EndKernPairs", in))
244 goto giveup;
245 sfree(line);
246 }
247 }
248 giveup:
249 sfree(fi);
250 fclose(in->currfp);
251 return;
252 }