Duplicate fix of Kevin Lyles's bug from r7092.
[sgt/halibut] / in_pf.c
CommitLineData
44407fea 1#include <stdio.h>
2#include "halibut.h"
3#include "paper.h"
4
c885c2ff 5static char *pf_read_token(FILE *fp);
6
44407fea 7void 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 */
57static 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 */
65static int pf_isspecial(int c) {
66 return c == '(' || c == ')' || c == '<' || c == '>' || c == '[' ||
67 c == ']' || c == '{' || c == '}' || c == '/' || c == '%';
68}
69
70static 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 */
90void 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
106static 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 */
116void 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
155static 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
178static 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
190static 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
205static 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}