Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcodex/code-uu.c
1808 views
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 <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
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
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
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
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
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
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
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
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 <[email protected]>]",
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
522