1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 2003-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23
24 /*
25 * quoted printable coder
26 */
27
28 #include <codex.h>
29 #include <ctype.h>
30 #include <ccode.h>
31
32 #define LINE 76
33 #define BUFFER SF_BUFSIZE
34
35 typedef struct State_s
36 {
37 Codex_t* codex;
38
39 unsigned char* bp;
40 unsigned char* be;
41
42 unsigned char* pp;
43 unsigned char prv[5];
44
45 short xxx;
46 short xeh[UCHAR_MAX+1];
47
48 int col;
49
50 unsigned char buf[LINE + BUFFER + 1];
51 } State_t;
52
53 static const char hex[] = "0123456789ABCDEFabcdef";
54
55 #define GETCHAR(p) ((p)->bp < (p)->be ? (int)*(p)->bp++ : fill(p))
56 #define PUTCHAR(p,c) ((p)->bp < (p)->be ? (int)(*(p)->bp++=(c)) : flush(p,c))
57
58 static int
fill(State_t * state)59 fill(State_t* state)
60 {
61 ssize_t r;
62
63 state->bp = state->buf + LINE;
64 if ((r = sfrd(state->codex->sp, state->bp, BUFFER, &state->codex->sfdisc)) <= 0)
65 {
66 state->be = state->bp;
67 return EOF;
68 }
69 state->be = state->bp + r;
70 return *state->bp++;
71 }
72
73 static int
flush(register State_t * state,int c)74 flush(register State_t* state, int c)
75 {
76 size_t n;
77
78 if (c < 0 && state->col)
79 {
80 state->col = 0;
81 PUTCHAR(state, '=');
82 PUTCHAR(state, '\n');
83 }
84 if (state->bp && (n = state->bp - state->buf) && sfwr(state->codex->sp, state->buf, n, &state->codex->sfdisc) != n)
85 return EOF;
86 state->be = (state->bp = state->buf) + sizeof(state->buf);
87 if (c >= 0)
88 *state->bp++ = c;
89 return 0;
90 }
91
92 static int
qp_open(Codex_t * p,char * const args[],Codexnum_t flags)93 qp_open(Codex_t* p, char* const args[], Codexnum_t flags)
94 {
95 register State_t* state;
96 register int i;
97
98 if (!(state = newof(0, State_t, 1, 0)))
99 {
100 if (p->disc->errorf)
101 (*p->disc->errorf)(NiL, p->disc, 2, "out of space");
102 return -1;
103 }
104 if (flags & CODEX_DECODE)
105 {
106 for (i = -1; i < elementsof(state->xeh); i++)
107 state->xeh[i] = -1;
108 for (i = 0; i < elementsof(hex) - 1; i++)
109 state->xeh[hex[i]] = i >= 16 ? (i - 6) : i;
110 }
111 p->data = state;
112 state->codex = p;
113 return 0;
114 }
115
116 static ssize_t
qp_read(Sfio_t * sp,void * buf,size_t n,Sfdisc_t * disc)117 qp_read(Sfio_t* sp, void* buf, size_t n, Sfdisc_t* disc)
118 {
119 register State_t* state = (State_t*)CODEX(disc)->data;
120 register char* s = (char*)buf;
121 register char* e = s + n;
122 register char* x;
123 register int c;
124 register int d;
125
126 x = 0;
127 while (s < e)
128 {
129 switch (c = GETCHAR(state))
130 {
131 case '=':
132 if ((c = GETCHAR(state)) == '\n')
133 continue;
134 if ((d = state->xeh[c]) != EOF && (c = state->xeh[GETCHAR(state)]) != EOF)
135 {
136 c |= (d << 4);
137 x = 0;
138 break;
139 }
140 /*FALLTHROUGH*/
141 case EOF:
142 return s - (char*)buf;
143 case '\n':
144 if (x)
145 {
146 s = x;
147 x = 0;
148 }
149 break;
150 case ' ':
151 case '\t':
152 case '\r':
153 if (!x)
154 x = s;
155 break;
156 default:
157 x = 0;
158 break;
159 }
160 *s++ = c;
161 }
162 if (x)
163 while (s > x && state->bp > state->buf)
164 *--state->bp = *--s;
165 return s - (char*)buf;
166 }
167
168 static ssize_t
qp_write(Sfio_t * sp,const void * buf,size_t n,Sfdisc_t * disc)169 qp_write(Sfio_t* sp, const void* buf, size_t n, Sfdisc_t* disc)
170 {
171 register State_t* state = (State_t*)CODEX(disc)->data;
172 register unsigned char* s;
173 register unsigned char* e;
174 register int c;
175 register int col;
176
177 again:
178 if (state->pp)
179 {
180 s = state->prv;
181 e = state->pp;
182 state->col = 0;
183 }
184 else
185 {
186 s = (unsigned char*)buf;
187 e = s + n;
188 col = state->col;
189 }
190 for (;;)
191 {
192 if (s >= e)
193 {
194 if (state->pp)
195 {
196 state->pp = 0;
197 state->col = col;
198 goto again;
199 }
200 break;
201 }
202 c = *s++;
203 if (!col++)
204 {
205 if (c == 'F')
206 {
207 if ((e - s) < 4)
208 {
209 s--;
210 col--;
211 state->pp = state->prv;
212 for (c = 0; c < (e - s); ++c)
213 *state->pp++ = s[c];
214 break;
215 }
216 else if (s[0] == 'r' && s[1] == 'o' && s[2] == 'm' && s[3] == ' ')
217 goto quote;
218 }
219 else if (c == '.')
220 {
221 if ((e - s) < 1)
222 {
223 s--;
224 col--;
225 state->pp = state->prv;
226 *state->pp++ = c;
227 break;
228 }
229 else if (s[0] == '\r' || s[0] == '\n')
230 goto quote;
231 }
232 }
233 if (c == '\n')
234 {
235 col = 0;
236 PUTCHAR(state, c);
237 continue;
238 }
239 else if (col >= (LINE - 4))
240 {
241 col = 0;
242 PUTCHAR(state, '=');
243 PUTCHAR(state, '\n');
244 }
245 if (c == ' ' || c == '\t')
246 {
247 if ((e - s) < 1)
248 {
249 s--;
250 col--;
251 state->pp = state->prv;
252 *state->pp++ = c;
253 break;
254 }
255 else if (s[0] == '\r' || s[0] == '\n')
256 goto quote;
257 else
258 {
259 if (c == '\t')
260 col |= 7;
261 PUTCHAR(state, c);
262 continue;
263 }
264 }
265 #if CC_NATIVE == CC_ASCII
266 else if (c >= 0x21 && c <= 0x7e && c != '=')
267 #else
268 else if (isprint(c) && !iscntrl(c) && c != '=')
269 #endif
270 {
271 PUTCHAR(state, c);
272 continue;
273 }
274 quote:
275 col += 2;
276 PUTCHAR(state, '=');
277 PUTCHAR(state, hex[(c >> 4) & 0xF]);
278 PUTCHAR(state, hex[c & 0xF]);
279 }
280 state->col = col;
281 return n;
282 }
283
284 static int
qp_sync(Codex_t * p)285 qp_sync(Codex_t* p)
286 {
287 return flush((State_t*)p->data, -1);
288 }
289
290 Codexmeth_t codex_qp =
291 {
292 "qp",
293 "quoted printable encoding.",
294 "[+(version)?codex-qp (AT&T Research) 1998-11-11]"
295 "[+(author)?Glenn Fowler <gsf@research.att.com>]",
296 CODEX_DECODE|CODEX_ENCODE|CODEX_UU,
297 0,
298 0,
299 qp_open,
300 0,
301 0,
302 0,
303 qp_read,
304 qp_write,
305 qp_sync,
306 0,
307 0,
308 0,
309 0,
310 CODEXNEXT(qp)
311 };
312
313 CODEXLIB(qp)
314