44407fea |
1 | #include <stdio.h> |
2 | #include "halibut.h" |
3 | #include "paper.h" |
4 | |
c885c2ff |
5 | static char *pf_read_token(FILE *fp); |
6 | |
44407fea |
7 | void read_pfa_file(input *in) { |
c885c2ff |
8 | rdstringc rsc = { 0, 0, NULL }; |
9 | char *p; |
44407fea |
10 | size_t len; |
11 | char *fontname; |
12 | font_info *fi; |
c885c2ff |
13 | FILE *fp = in->currfp; |
14 | int c; |
44407fea |
15 | |
c885c2ff |
16 | in->pos.line = 0; |
17 | do { |
18 | c = fgetc(fp); |
19 | if (c == EOF) { |
20 | sfree(rsc.text); |
21 | error(err_pfeof, &in->pos); |
22 | return; |
23 | } |
24 | rdaddc(&rsc, c); |
25 | } while (c != 012 && c != 015); |
26 | p = rsc.text; |
27 | if ((p = strchr(p, ':')) == NULL) { |
28 | sfree(rsc.text); |
29 | error(err_pfhead, &in->pos); |
44407fea |
30 | return; |
c885c2ff |
31 | } |
32 | p++; |
44407fea |
33 | p += strspn(p, " \t"); |
34 | len = strcspn(p, " \t"); |
35 | fontname = snewn(len + 1, char); |
36 | memcpy(fontname, p, len); |
37 | fontname[len] = 0; |
c885c2ff |
38 | sfree(rsc.text); |
39 | |
44407fea |
40 | for (fi = all_fonts; fi; fi = fi->next) { |
41 | if (strcmp(fi->name, fontname) == 0) { |
42 | fi->fp = in->currfp; |
c885c2ff |
43 | fi->pos = in->pos; |
44 | fi->length1 = fi->length2 = 0; |
44407fea |
45 | sfree(fontname); |
46 | return; |
47 | } |
48 | } |
c885c2ff |
49 | error(err_pfnoafm, &in->pos, fontname); |
44407fea |
50 | fclose(in->currfp); |
51 | sfree(fontname); |
52 | } |
c885c2ff |
53 | |
54 | /* |
55 | * PostScript white space characters; PLRM3 table 3.1 |
56 | */ |
57 | static int pf_isspace(int c) { |
58 | return c == 000 || c == 011 || c == 012 || c == 014 || c == 015 || |
59 | c == ' '; |
60 | } |
61 | |
62 | /* |
63 | * PostScript special characters; PLRM3 page 27 |
64 | */ |
65 | static int pf_isspecial(int c) { |
66 | return c == '(' || c == ')' || c == '<' || c == '>' || c == '[' || |
67 | c == ']' || c == '{' || c == '}' || c == '/' || c == '%'; |
68 | } |
69 | |
70 | static long pf_length1(font_info *fi) { |
71 | FILE *fp = fi->fp; |
72 | char *tok; |
73 | |
74 | rewind(fp); |
75 | tok = pf_read_token(fp); |
76 | while (tok && strcmp(tok, "eexec") != 0) { |
77 | sfree(tok); |
78 | tok = pf_read_token(fp); |
79 | } |
80 | if (tok == NULL) { |
81 | error(err_pfeof, &fi->pos); |
82 | return 0; |
83 | } |
84 | return ftell(fp); |
85 | } |
86 | |
87 | /* |
88 | * Return the initial, unencrypted, part of a font. |
89 | */ |
90 | void pf_part1(font_info *fi, char **bufp, size_t *lenp) { |
91 | FILE *fp = fi->fp; |
92 | |
93 | if (fi->length1 == 0) |
94 | fi->length1 = pf_length1(fi); |
95 | rewind(fp); |
96 | *bufp = snewn(fi->length1, char); |
97 | *lenp = fi->length1; |
98 | if (fread(*bufp, 1, fi->length1, fp) != (size_t)fi->length1) { |
99 | error(err_pfeof, &fi->pos); |
100 | *lenp = 0; |
101 | sfree(*bufp); |
102 | *bufp = NULL; |
103 | } |
104 | } |
105 | |
106 | static int hexval(char c) { |
107 | if (c >= '0' && c <= '9') return c - '0'; |
108 | if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; |
109 | if (c >= 'a' && c <= 'f') return c - 'a' + 0xa; |
110 | return 0; |
111 | } |
112 | |
113 | /* |
114 | * Return the middle, encrypted, part of a font. |
115 | */ |
116 | void pf_part2(font_info *fi, char **bufp, size_t *lenp) { |
117 | FILE *fp = fi->fp; |
118 | rdstringc rsc = { 0, 0, NULL }; |
119 | char *tok, *p; |
120 | unsigned char nybble; |
121 | int havenybble = 0; |
122 | |
123 | if (fi->length1 == 0) |
124 | fi->length1 = pf_length1(fi); |
125 | fseek(fp, fi->length1, SEEK_SET); |
126 | tok = pf_read_token(fp); |
127 | while (tok && strcmp(tok, "cleartomark") != 0) { |
128 | for (p = tok; *p; p++) { |
129 | if (pf_isspace(*p)) continue; |
130 | if (!havenybble) |
131 | nybble = hexval(*p); |
132 | else |
133 | rdaddc(&rsc, (nybble << 4) | hexval(*p)); |
134 | havenybble = !havenybble; |
135 | } |
136 | sfree(tok); |
137 | tok = pf_read_token(fp); |
138 | } |
139 | if (tok == NULL) { |
140 | error(err_pfeof, &fi->pos); |
141 | *bufp = NULL; |
142 | *lenp = 0; |
143 | } |
144 | *bufp = rsc.text; |
145 | /* Trim off the trailing zeroes */ |
146 | if (rsc.pos >= 256) |
147 | *lenp = rsc.pos - 256; |
148 | else { |
149 | error(err_pfbad, &fi->pos); |
150 | *bufp = NULL; |
151 | *lenp = 0; |
152 | } |
153 | } |
154 | |
155 | static char *pf_read_litstring(FILE *fp) { |
156 | rdstringc rsc = { 0, 0, NULL }; |
157 | int depth = 1; |
158 | int c; |
159 | |
160 | rdaddc(&rsc, '('); |
161 | do { |
162 | c = fgetc(fp); |
163 | switch (c) { |
164 | case '(': |
165 | depth++; break; |
166 | case ')': |
167 | depth--; break; |
168 | case '\\': |
169 | rdaddc(&rsc, '\\'); |
170 | c = fgetc(fp); |
171 | break; |
172 | } |
173 | if (c != EOF) rdaddc(&rsc, c); |
174 | } while (depth > 0 && c != EOF); |
175 | return rsc.text; |
176 | } |
177 | |
178 | static char *pf_read_hexstring(FILE *fp) { |
179 | rdstringc rsc = { 0, 0, NULL }; |
180 | int c; |
181 | |
182 | rdaddc(&rsc, '<'); |
183 | do { |
184 | c = fgetc(fp); |
185 | if (c != EOF) rdaddc(&rsc, c); |
186 | } while (c != '>' && c != EOF); |
187 | return rsc.text; |
188 | } |
189 | |
190 | static char *pf_read_word(FILE *fp, int c) { |
191 | rdstringc rsc = { 0, 0, NULL }; |
192 | |
193 | rdaddc(&rsc, c); |
194 | if (c == '{' || c == '}' || c == '[' || c == ']') |
195 | return rsc.text; |
196 | for (;;) { |
197 | c = fgetc(fp); |
198 | if (pf_isspecial(c) || pf_isspace(c) || c == EOF) break; |
199 | rdaddc(&rsc, c); |
200 | } |
201 | if (pf_isspecial(c)) ungetc(c, fp); |
202 | return rsc.text; |
203 | } |
204 | |
205 | static char *pf_read_token(FILE *fp) { |
206 | int c; |
207 | |
208 | do { |
209 | c = fgetc(fp); |
210 | } while (pf_isspace(c)); |
211 | if (c == EOF) return NULL; |
212 | if (c == '%') { |
213 | do { |
214 | c = fgetc(fp); |
215 | } while (c != 012 && c != 015); |
216 | return pf_read_token(fp); |
217 | } |
218 | if (c == '(') return pf_read_litstring(fp); |
219 | if (c == '<') return pf_read_hexstring(fp); |
220 | return pf_read_word(fp, c); |
221 | } |