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 * uuencode familiy coders
26 */
27
28 #include <codex.h>
29 #include <ctype.h>
30
31 #define UUIN 3
32 #define UUOUT 4
33 #define UUCHUNK 15
34
35 #define UU_END (UCHAR_MAX)
36 #define UU_IGN (UCHAR_MAX-1)
37 #define UU_PAD (UCHAR_MAX-2)
38
39 typedef struct
40 {
41 int pad;
42 int fill;
43 int length;
44 const char map[65];
45 } Data_t;
46
47 typedef struct State_s
48 {
49 Codex_t* codex;
50
51 const Data_t* data;
52
53 unsigned char* bb;
54 unsigned char* bp;
55 unsigned char* bl;
56 unsigned char* be;
57 unsigned char* map;
58 unsigned char* pb;
59 unsigned char* pp;
60
61 int c1;
62 int c2;
63 int nl;
64 int string;
65 int text;
66
67 unsigned char mapbuf[UCHAR_MAX + 2];
68 unsigned char buf[SF_BUFSIZE];
69 unsigned char peek[UUIN];
70 } State_t;
71
72 static const Data_t uu_base64 =
73 {
74 '=',
75 0,
76 0,
77 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
78 };
79
80 static const Data_t uu_bsd =
81 {
82 0,
83 0156,
84 1,
85 "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
86 };
87
88 static const Data_t uu_posix =
89 {
90 0,
91 0,
92 1,
93 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
94 };
95
96 #define GETCHAR(p) ((p)->bp < (p)->be ? (int)*(p)->bp++ : fill(p))
97 #define PUTCHAR(p,s,e,c) ((s<e) ? (*s++=(c)) : (*p->pp++=(c)))
98
99 static int
fill(State_t * state)100 fill(State_t* state)
101 {
102 ssize_t r;
103
104 state->bp = state->buf;
105 if ((r = sfrd(state->codex->sp, state->bp, sizeof(state->buf), &state->codex->sfdisc)) <= 0)
106 {
107 state->be = state->bp;
108 return EOF;
109 }
110 state->be = state->bp + r;
111 return *state->bp++;
112 }
113
114 static int
flush(register State_t * state)115 flush(register State_t* state)
116 {
117 uint32_t b;
118 int c3;
119 int x;
120
121 x = 1;
122 if (state->c1 >= 0)
123 {
124 c3 = state->data->fill;
125 x++;
126 if (state->c2 < 0)
127 {
128 state->c2 = c3;
129 x++;
130 }
131 b = (state->c1 << 16) | (state->c2 << 8) | c3;
132 *state->bp++ = state->data->map[b >> 18];
133 *state->bp++ = state->data->map[(b >> 12) & 077];
134 *state->bp++ = x == 3 && state->data->pad ? state->data->pad : state->data->map[(b >> 6) & 077];
135 *state->bp++ = state->data->pad ? state->data->pad : state->data->map[b & 077];
136 state->c1 = state->c2 = -1;
137 }
138 if ((state->bl - state->bp) < UUOUT * UUCHUNK || state->bp > state->buf + !!state->bb)
139 {
140 if (state->bb)
141 *state->bb = state->data->map[((state->bp - state->bb - x) / UUOUT) * UUIN + 1];
142 if (state->string)
143 {
144 if (*(state->bp - 1) == '\n')
145 state->bp--;
146 }
147 else
148 {
149 if (*(state->bp - 1) != '\n')
150 *state->bp++ = '\n';
151 }
152 x = state->bp - state->buf;
153 state->bp = state->buf;
154 state->bl = state->bp + UUOUT * UUCHUNK;
155 if (sfwr(state->codex->sp, state->buf, x, &state->codex->sfdisc) != x)
156 return EOF;
157 }
158 return 0;
159 }
160
161 static int
uu_open(Codex_t * p,char * const args[],Codexnum_t flags)162 uu_open(Codex_t* p, char* const args[], Codexnum_t flags)
163 {
164 register State_t* state;
165 register char* s;
166 register char** a;
167 unsigned char* m;
168 unsigned char* q;
169 const Data_t* data;
170 int c;
171 int n;
172 int string;
173 int text;
174
175 data = &uu_posix;
176 string = text = 0;
177 a = (char**)args + 1;
178 while (s = *++a)
179 if (streq(s, "base64") || streq(s, "mime"))
180 data = &uu_base64;
181 else if (streq(s, "bsd") || streq(s, "ucb"))
182 data = &uu_bsd;
183 else if (streq(s, "posix"))
184 data = &uu_posix;
185 else if (streq(s, "string"))
186 {
187 if (data != &uu_base64)
188 {
189 if (p->disc->errorf)
190 (*p->disc->errorf)(NiL, p->disc, 2, "%s: %s: option valid for base64/mime only", p->meth->name, s);
191 return -1;
192 }
193 string = 1;
194 }
195 else if (streq(s, "text"))
196 text = 1;
197 else
198 {
199 if (p->disc->errorf)
200 (*p->disc->errorf)(NiL, p->disc, 2, "%s: %s: unknown option", p->meth->name, s);
201 return -1;
202 }
203 if (!(state = newof(0, State_t, 1, 0)))
204 {
205 if (p->disc->errorf)
206 (*p->disc->errorf)(NiL, p->disc, 2, "out of space");
207 return -1;
208 }
209 state->data = data;
210 state->string = string;
211 state->text = text;
212 if (p->flags & CODEX_DECODE)
213 {
214 n = data->length ? 0 : UU_IGN;
215 q = state->mapbuf;
216 memset(q, n, sizeof(state->mapbuf));
217 state->map = ++q;
218 q[EOF] = UU_END;
219 if (n)
220 q[data->pad] = UU_PAD;
221 for (m = (unsigned char*)data->map; c = *m; m++)
222 q[c] = m - (unsigned char*)data->map;
223 }
224 p->data = state;
225 state->codex = p;
226 return 0;
227 }
228
229 static int
uu_init(Codex_t * p)230 uu_init(Codex_t* p)
231 {
232 register State_t* state = (State_t*)p->data;
233 int n;
234
235 state->bp = state->buf;
236 if (p->flags & CODEX_ENCODE)
237 {
238 n = UUOUT * UUCHUNK + state->data->length + 1;
239 state->be = state->bp + (sizeof(state->buf) / n) * n;
240 if (state->data->length)
241 {
242 state->bb = state->bp;
243 *state->bp++ = state->data->map[UUIN * UUCHUNK];
244 }
245 state->bl = state->bp + UUOUT * UUCHUNK;
246 state->c1 = state->c2 = -1;
247 }
248 else
249 {
250 state->be = state->bp;
251 state->pb = state->pp = state->peek;
252 if (state->data->length)
253 state->nl = -1;
254 state->c1 = state->c2 = -1;
255 }
256 return 0;
257 }
258
259 static ssize_t
uu_read(Sfio_t * sp,void * buf,size_t n,Sfdisc_t * disc)260 uu_read(Sfio_t* sp, void* buf, size_t n, Sfdisc_t* disc)
261 {
262 register State_t* state = (State_t*)CODEX(disc)->data;
263 register char* s = (char*)buf;
264 register char* e = s + n;
265 register uint32_t b;
266 register int c;
267 register int x;
268
269 if (state->pb < state->pp)
270 {
271 while (s < e && state->pb < state->pp)
272 *s++ = *state->pb++;
273 if (state->pb == state->pp)
274 state->pb = state->pp = state->peek;
275 }
276 if (state->data->length)
277 while (s < e)
278 {
279 switch (c = GETCHAR(state))
280 {
281 case EOF:
282 goto done;
283 case '\n':
284 state->nl = -1;
285 continue;
286 }
287 if (state->nl < 0)
288 state->nl = state->map[c];
289 else if (state->nl > 0)
290 {
291 b = state->map[c];
292 if ((c = GETCHAR(state)) == EOF)
293 c = 0;
294 else
295 c = state->map[c];
296 b = (b << 6) | c;
297 if ((c = GETCHAR(state)) == EOF)
298 c = 0;
299 else
300 c = state->map[c];
301 b = (b << 6) | c;
302 if ((c = GETCHAR(state)) == EOF)
303 c = 0;
304 else
305 c = state->map[c];
306 b = (b << 6) | c;
307 if (state->text)
308 {
309 if ((c = (b >> 16) & 0xFF) != '\r')
310 PUTCHAR(state, s, e, c);
311 if ((c = (b >> 8) & 0xFF) != '\r')
312 PUTCHAR(state, s, e, c);
313 if ((c = b & 0xFF) != '\r')
314 PUTCHAR(state, s, e, c);
315 }
316 else
317 {
318 PUTCHAR(state, s, e, (b >> 16));
319 PUTCHAR(state, s, e, (b >> 8));
320 PUTCHAR(state, s, e, b);
321 }
322 if ((state->nl -= 3) < 0)
323 while (state->nl++ < 0)
324 s--;
325 }
326 }
327 else
328 while (s < e)
329 {
330 while ((c = state->map[GETCHAR(state)]) >= 64)
331 if (c != UU_IGN)
332 goto done;
333 b = c;
334 while ((c = state->map[GETCHAR(state)]) >= 64)
335 if (c != UU_IGN)
336 {
337 if (state->codex->disc->errorf)
338 (*state->codex->disc->errorf)(NiL, state->codex->disc, 1, "%c: extra input character ignored", c);
339 goto done;
340 }
341 b = (b << 6) | c;
342 while ((c = state->map[GETCHAR(state)]) >= 64)
343 if (c != UU_IGN)
344 {
345 if (state->text)
346 {
347 if ((x = (b >> 4) & 0xFF) != '\r')
348 PUTCHAR(state, s, e, x);
349 }
350 else
351 PUTCHAR(state, s, e, (b >> 4));
352 goto done;
353 }
354 b = (b << 6) | c;
355 while ((c = state->map[GETCHAR(state)]) >= 64)
356 if (c != UU_IGN)
357 {
358 if (state->text)
359 {
360 if ((x = (b >> 10) & 0xFF) != '\r')
361 PUTCHAR(state, s, e, x);
362 if ((x = (b >> 2) & 0xFF) != '\r')
363 PUTCHAR(state, s, e, x);
364 }
365 else
366 {
367 PUTCHAR(state, s, e, (b >> 10));
368 PUTCHAR(state, s, e, (b >> 2));
369 }
370 goto done;
371 }
372 b = (b << 6) | c;
373 if (state->text)
374 {
375 if ((x = (b >> 16) & 0xFF) != '\r')
376 PUTCHAR(state, s, e, x);
377 if ((x = (b >> 8) & 0xFF) != '\r')
378 PUTCHAR(state, s, e, x);
379 if ((x = b & 0xFF) != '\r')
380 PUTCHAR(state, s, e, x);
381 }
382 else
383 {
384 PUTCHAR(state, s, e, (b >> 16));
385 PUTCHAR(state, s, e, (b >> 8));
386 PUTCHAR(state, s, e, b);
387 }
388 }
389 done:
390 return s - (char*)buf;
391 }
392
393 static ssize_t
uu_write(Sfio_t * sp,const void * buf,size_t n,Sfdisc_t * disc)394 uu_write(Sfio_t* sp, const void* buf, size_t n, Sfdisc_t* disc)
395 {
396 register State_t* state = (State_t*)CODEX(disc)->data;
397 register unsigned char* s;
398 register unsigned char* e;
399 register uint32_t b;
400 register int c1;
401 register int c2;
402 register int c3;
403
404 s = (unsigned char*)buf;
405 e = s + n;
406 if ((c1 = state->c1) >= 0)
407 {
408 state->c1 = -1;
409 if ((c2 = state->c2) >= 0)
410 {
411 state->c2 = -1;
412 goto get_3;
413 }
414 goto get_2;
415 }
416 while (s < e)
417 {
418 do
419 {
420 if (state->nl)
421 {
422 state->nl = 0;
423 c1 = '\n';
424 goto get_2;
425 }
426 if (s >= e)
427 break;
428 c1 = *s++;
429 if (state->text && c1 == '\n')
430 {
431 c1 = '\r';
432 c2 = '\n';
433 goto get_3;
434 }
435 get_2:
436 if (s >= e)
437 {
438 state->c1 = c1;
439 return n;
440 }
441 c2 = *s++;
442 if (state->text && c2 == '\n')
443 {
444 c2 = '\r';
445 c3 = '\n';
446 goto put_123;
447 }
448 get_3:
449 if (s >= e)
450 {
451 state->c1 = c1;
452 state->c2 = c2;
453 return n;
454 }
455 c3 = *s++;
456 if (state->text && c3 == '\n')
457 {
458 state->nl = 1;
459 c3 = '\r';
460 }
461 put_123:
462 b = (c1 << 16) | (c2 << 8) | c3;
463 *state->bp++ = state->data->map[b >> 18];
464 *state->bp++ = state->data->map[(b >> 12) & 077];
465 *state->bp++ = state->data->map[(b >> 6) & 077];
466 *state->bp++ = state->data->map[b & 077];
467 } while (state->bp < state->bl);
468 if (!state->string)
469 *state->bp++ = '\n';
470 if (state->bp >= state->be)
471 {
472 if (sfwr(sp, state->buf, state->bp - state->buf, disc) != (state->bp - state->buf))
473 return -1;
474 state->bp = state->buf;
475 }
476 if (state->bb)
477 {
478 state->bb = state->bp;
479 *state->bp++ = state->data->map[UUIN * UUCHUNK];
480 }
481 state->bl = state->bp + UUOUT * UUCHUNK;
482 }
483 return n;
484 }
485
486 static int
uu_sync(Codex_t * p)487 uu_sync(Codex_t* p)
488 {
489 return (p->flags & CODEX_ENCODE) ? flush((State_t*)p->data) : 0;
490 }
491
492 Codexmeth_t codex_uu =
493 {
494 "uu",
495 "uuencode printable encoding.",
496 "[+posix?Posix \buuencode\b(1). This is the default.]"
497 "[+base64|mime?MIME base64 encoding.]"
498 "[+bsd|ucb?BSD \buuencode\b(1).]"
499 "[+string?Encode into a string with no separators (base64 only).]"
500 "[+text?Encode \\n => \\r\\n, decode \\r\\n => \\n.]"
501 "[+(version)?codex-uu (AT&T Research) 2010-01-15]"
502 "[+(author)?Glenn Fowler <gsf@research.att.com>]",
503 CODEX_DECODE|CODEX_ENCODE|CODEX_UU,
504 0,
505 0,
506 uu_open,
507 0,
508 uu_init,
509 0,
510 uu_read,
511 uu_write,
512 uu_sync,
513 0,
514 0,
515 0,
516 0,
517 CODEXNEXT(uu)
518 };
519
520 CODEXLIB(uu)
521