Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libuu/uulib.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1998-2012 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
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* uuencode/uudecode methods
26
*/
27
28
static char id[] = "\n@(#)$Id: uulib (AT&T Research) 2003-01-07 $\0\n";
29
30
static const char lib[] = "libuu:uu";
31
32
#include "uulib.h"
33
34
#include <ctype.h>
35
#include <error.h>
36
#include <ls.h>
37
#include <modex.h>
38
#include <sfdisc.h>
39
40
#define UU_BEGIN "begin"
41
#define UU_BEGIN_LEN (sizeof(UU_BEGIN)-1)
42
43
#define UUIN 3
44
#define UUOUT 4
45
#define UUCHUNK 15
46
#define UULINE 76
47
48
#define UU_END (UCHAR_MAX)
49
#define UU_IGN (UCHAR_MAX-1)
50
#define UU_PAD (UCHAR_MAX-2)
51
52
typedef struct
53
{
54
const char* name;
55
unsigned long flag;
56
} Option_t;
57
58
static const Option_t options[] =
59
{
60
"text", UU_TEXT,
61
};
62
63
/*
64
* initialize the uu map from dp
65
*/
66
67
static unsigned char*
68
uu_map(register Uudata_t* dp, char* map)
69
{
70
register int c;
71
register char* p;
72
register unsigned char* m;
73
int x;
74
75
x = (dp->flags & UU_LENGTH) ? 0 : UU_IGN;
76
p = map;
77
memset(p, x, UCHAR_MAX + 2);
78
if (x)
79
{
80
p++;
81
p[dp->pad] = UU_PAD;
82
p[EOF] = UU_END;
83
}
84
for (m = (unsigned char*)dp->map; c = *m; m++)
85
p[c] = m - (unsigned char*)dp->map;
86
return (unsigned char*)p;
87
}
88
89
/*
90
* grab uu header from input
91
*/
92
93
static int
94
uu_header(register Uu_t* uu)
95
{
96
register char* s;
97
register int c;
98
int n;
99
int k;
100
Uumeth_t* meth;
101
char* t;
102
103
c = *UU_BEGIN;
104
for (;;)
105
{
106
if (!(s = sfgetr(uu->ip, '\n', 1)))
107
{
108
if (uu->disc->errorf)
109
(*uu->disc->errorf)(uu, uu->disc, 2, "unknown encoding");
110
break;
111
}
112
if (*s == c && !strncasecmp(s, UU_BEGIN, UU_BEGIN_LEN) && (meth = uumeth(s)))
113
{
114
s += UU_BEGIN_LEN + strlen(meth->id);
115
while (*s == '-')
116
{
117
for (t = ++s; isalnum(*s); s++);
118
k = s - t;
119
for (n = 0; n < elementsof(options); n++)
120
if (strlen(options[n].name) == k && !strncasecmp(options[n].name, t, k))
121
{
122
uu->flags |= options[n].flag;
123
break;
124
}
125
}
126
if (*s++ == ' ')
127
{
128
uu->mode = strperm(s, &t, 0) & ~(S_IXUSR|S_IXGRP|S_IXOTH);
129
if (*t++ == ' ')
130
{
131
if (!uu->path)
132
{
133
uu->path = strdup(t);
134
uu->flags |= UU_FREEPATH;
135
}
136
if (meth->name != uu->meth.name)
137
{
138
if (!(((Uudata_t*)uu->meth.data)->flags & UU_DEFAULT) && !streq(meth->id, uu->meth.id) && uu->disc->errorf)
139
(*uu->disc->errorf)(uu, uu->disc, 1, "switching to %s encoding", meth->name);
140
uu->meth = *meth;
141
}
142
return 0;
143
}
144
}
145
}
146
}
147
return -1;
148
}
149
150
/*
151
* uu encode input to output
152
*/
153
154
static int
155
uu_encode(register Uu_t* uu)
156
{
157
register char* e;
158
register char* p;
159
register unsigned char* m;
160
register int c;
161
register int c1;
162
register int c2;
163
register int c3;
164
register unsigned long b;
165
int length;
166
int nl;
167
int pad;
168
int text;
169
Uudata_t* dp;
170
struct stat st;
171
char buf[UUOUT * (UUCHUNK + 1)];
172
173
dp = (Uudata_t*)uu->meth.data;
174
m = (unsigned char*)dp->map;
175
length = !!(dp->flags & UU_LENGTH);
176
text = !!(uu->flags & UU_TEXT);
177
pad = dp->pad;
178
if (uu->flags & UU_HEADER)
179
{
180
if (fstat(sffileno(uu->ip), &st) || !(c = modex(st.st_mode) & 0777))
181
c = 0644;
182
sfprintf(uu->op, "%s%s%s %03o %s\n", UU_BEGIN, uu->meth.id, text ? "-text" : "", c, uu->path ? uu->path : "-");
183
}
184
if (length)
185
*buf = m[UUIN * UUCHUNK];
186
p = buf + length;
187
e = p + UUOUT * UUCHUNK;
188
nl = 0;
189
for (;;)
190
{
191
do {
192
if (nl)
193
{
194
nl = 0;
195
c1 = '\n';
196
goto get_2;
197
}
198
if ((c1 = sfgetc(uu->ip)) == EOF)
199
{
200
if (length)
201
*buf = m[((p - buf - length) / UUOUT) * UUIN];
202
goto eof;
203
}
204
if (text && c1 == '\n')
205
{
206
c1 = '\r';
207
c2 = '\n';
208
goto get_3;
209
}
210
get_2:
211
if ((c2 = sfgetc(uu->ip)) == EOF)
212
{
213
if (length)
214
*buf = m[((p - buf - length) / UUOUT) * UUIN + 1];
215
c2 = dp->fill;
216
c3 = dp->fill;
217
b = (c1 << 16) | (c2 << 8) | c3;
218
*p++ = m[b >> 18];
219
*p++ = m[(b >> 12) & 077];
220
*p++ = pad ? pad : m[(b >> 6) & 077];
221
*p++ = pad ? pad : m[b & 077];
222
goto eof;
223
}
224
if (text && c2 == '\n')
225
{
226
c2 = '\r';
227
c3 = '\n';
228
goto put_123;
229
}
230
get_3:
231
if ((c3 = sfgetc(uu->ip)) == EOF)
232
{
233
if (length)
234
*buf = m[((p - buf - length) / UUOUT) * UUIN + 2];
235
c3 = dp->fill;
236
b = (c1 << 16) | (c2 << 8) | c3;
237
*p++ = m[b >> 18];
238
*p++ = m[(b >> 12) & 077];
239
*p++ = m[(b >> 6) & 077];
240
*p++ = pad ? pad : m[b & 077];
241
goto eof;
242
}
243
if (text && c3 == '\n')
244
{
245
nl = 1;
246
c3 = '\r';
247
}
248
put_123:
249
b = (c1 << 16) | (c2 << 8) | c3;
250
*p++ = m[b >> 18];
251
*p++ = m[(b >> 12) & 077];
252
*p++ = m[(b >> 6) & 077];
253
*p++ = m[b & 077];
254
} while (p < e);
255
*p++ = '\n';
256
sfwrite(uu->op, buf, p - buf);
257
p = buf + length;
258
}
259
eof:
260
if (p > buf + length)
261
{
262
*p++ = '\n';
263
sfwrite(uu->op, buf, p - buf);
264
}
265
if (length)
266
sfprintf(uu->op, "%c\n", m[0]);
267
if (uu->flags & UU_HEADER)
268
sfputr(uu->op, dp->end, '\n');
269
return 0;
270
}
271
272
/*
273
* uu decode input to output
274
*/
275
276
static int
277
uu_decode(register Uu_t* uu)
278
{
279
register Uudata_t* dp;
280
register char* s;
281
register char* e;
282
register char* p;
283
register unsigned char* m;
284
register int c;
285
register unsigned long n;
286
int text;
287
int tl;
288
int x;
289
char* t;
290
char buf[UUIN * UUCHUNK + 1];
291
char map[UCHAR_MAX + 2];
292
293
dp = (Uudata_t*)uu->meth.data;
294
if (uu->path && (uu->flags & UU_CLOSEOUT) && (dp->flags & uu->flags & UU_HEADER) && chmod(uu->path, uu->mode) && uu->disc->errorf)
295
(*uu->disc->errorf)(uu, uu->disc, ERROR_SYSTEM|2, "%s: cannot change mode to %s", uu->path, fmtperm(uu->mode));
296
text = !!(uu->flags & UU_TEXT);
297
m = uu_map(dp, map);
298
if (dp->flags & UU_LENGTH)
299
{
300
t = (char*)dp->end;
301
tl = strlen(t) + 1;
302
while (((s = sfgetr(uu->ip, '\n', 0)) || (s = sfgetr(uu->ip, '\n', -1))) && ((n = sfvalue(uu->ip)) != tl || !strneq(s, t, tl - 1)))
303
if (c = m[*((unsigned char*)s++)])
304
{
305
if (c > sizeof(buf))
306
{
307
if (uu->disc->errorf)
308
(*uu->disc->errorf)(uu, uu->disc, 2, "input is not %s encoded", uu->meth.name);
309
return -1;
310
}
311
p = buf;
312
e = s + (c + UUIN - 1) / UUIN * UUOUT;
313
while (s < e)
314
{
315
n = m[*((unsigned char*)s++)];
316
n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
317
n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
318
n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
319
if (text)
320
{
321
if ((x = (n >> 16) & 0xFF) == '\r')
322
c--;
323
else
324
*p++ = x;
325
if ((x = (n >> 8) & 0xFF) == '\r')
326
c--;
327
else
328
*p++ = x;
329
if ((x = n & 0xFF) == '\r')
330
c--;
331
else
332
*p++ = x;
333
}
334
else
335
{
336
*p++ = (n >> 16);
337
*p++ = (n >> 8);
338
*p++ = n;
339
}
340
}
341
sfwrite(uu->op, buf, c);
342
}
343
if (!s && (uu->flags & UU_HEADER) && uu->disc->errorf)
344
(*uu->disc->errorf)(uu, uu->disc, 1, "end sequence `%s' omitted", t);
345
}
346
else
347
{
348
for (;;)
349
{
350
while ((c = m[sfgetc(uu->ip)]) >= 64)
351
if (c != UU_IGN)
352
goto pad;
353
n = c;
354
while ((c = m[sfgetc(uu->ip)]) >= 64)
355
if (c != UU_IGN)
356
{
357
if (uu->disc->errorf)
358
(*uu->disc->errorf)(uu, uu->disc, 1, "%c: extra input character ignored", c);
359
goto pad;
360
}
361
n = (n << 6) | c;
362
while ((c = m[sfgetc(uu->ip)]) >= 64)
363
if (c != UU_IGN)
364
{
365
if (text)
366
{
367
if ((x = (n >> 4) & 0xFF) != '\r')
368
sfputc(uu->op, x);
369
}
370
else sfputc(uu->op, n >> 4);
371
goto pad;
372
}
373
n = (n << 6) | c;
374
while ((c = m[sfgetc(uu->ip)]) >= 64)
375
if (c != UU_IGN)
376
{
377
if (text)
378
{
379
if ((x = (n >> 10) & 0xFF) != '\r')
380
sfputc(uu->op, x);
381
if ((x = (n >> 2) & 0xFF) != '\r')
382
sfputc(uu->op, x);
383
}
384
else
385
{
386
sfputc(uu->op, n >> 10);
387
sfputc(uu->op, n >> 2);
388
}
389
goto pad;
390
}
391
n = (n << 6) | c;
392
if (text)
393
{
394
if ((x = (n >> 16) & 0xFF) != '\r')
395
sfputc(uu->op, x);
396
if ((x = (n >> 8) & 0xFF) != '\r')
397
sfputc(uu->op, x);
398
if ((x = n & 0xFF) != '\r')
399
sfputc(uu->op, x);
400
}
401
else
402
{
403
sfputc(uu->op, (n >> 16));
404
sfputc(uu->op, (n >> 8));
405
sfputc(uu->op, (n));
406
}
407
}
408
pad:
409
n = c == UU_PAD;
410
while ((c = sfgetc(uu->ip)) != EOF)
411
if (c == dp->pad && ++n >= 4)
412
break;
413
if (n < 4 && (uu->flags & UU_HEADER) && uu->disc->errorf)
414
(*uu->disc->errorf)(uu, uu->disc, 1, "input end sequence `%s' omitted", dp->end);
415
}
416
return 0;
417
}
418
419
static const char hex[] = "0123456789ABCDEFabcdef";
420
421
/*
422
* quoted-printable encode input to output
423
*/
424
425
static int
426
qp_encode(register Uu_t* uu)
427
{
428
register unsigned char* s;
429
register unsigned char* e;
430
register char* b;
431
register char* x;
432
register int c;
433
char buf[UULINE + 1];
434
435
b = buf;
436
x = b + UULINE - 4;
437
while ((s = (unsigned char*)sfgetr(uu->ip, '\n', 0)) || (s = (unsigned char*)sfgetr(uu->ip, '\n', -1)))
438
{
439
e = s + sfvalue(uu->ip);
440
switch (*s)
441
{
442
case 'F':
443
if ((e - s) >= 5 && strneq((char*)s, "From ", 5))
444
{
445
c = *s++;
446
goto quote;
447
}
448
break;
449
case '.':
450
if ((e - s) == 2)
451
{
452
c = *s++;
453
goto quote;
454
}
455
break;
456
}
457
while (s < e)
458
{
459
if ((c = *s++) == '\n')
460
{
461
*b++ = c;
462
sfwrite(uu->op, buf, b - buf);
463
b = buf;
464
break;
465
}
466
if (b >= x)
467
{
468
*b++ = '=';
469
*b++ = '\n';
470
sfwrite(uu->op, buf, b - buf);
471
b = buf;
472
}
473
if (c == ' ' || c == '\t')
474
{
475
if (s < e && *s != '\n')
476
{
477
*b++ = c;
478
continue;
479
}
480
}
481
else if (isprint(c) && !iscntrl(c) && c != '=')
482
{
483
*b++ = c;
484
continue;
485
}
486
quote:
487
*b++ = '=';
488
*b++ = hex[(c >> 4) & 0xF];
489
*b++ = hex[c & 0xF];
490
}
491
}
492
if (b > buf)
493
{
494
*b++ = '=';
495
*b++ = '\n';
496
sfwrite(uu->op, buf, b - buf);
497
}
498
return 0;
499
}
500
501
/*
502
* quoted-printable decode input to output
503
*/
504
505
static int
506
qp_decode(register Uu_t* uu)
507
{
508
register unsigned char* s;
509
register unsigned char* b;
510
register unsigned char* x;
511
register int c;
512
register int d;
513
514
short xeh[UCHAR_MAX + 1];
515
516
for (c = 0; c < elementsof(xeh); c++)
517
xeh[c] = -1;
518
for (c = 0; c < elementsof(hex) - 1; c++)
519
xeh[hex[c]] = c >= 16 ? (c - 6) : c;
520
while (s = (unsigned char*)sfgetr(uu->ip, '\n', 1))
521
{
522
if (((b = s + sfvalue(uu->ip)) > s) && !*--b)
523
{
524
while (b > s && ((c = *(b - 1)) == ' ' || c == '\t'))
525
b--;
526
*b = 0;
527
}
528
x = b = s;
529
for (;;)
530
{
531
switch (c = *s++)
532
{
533
case 0:
534
*b++ = '\n';
535
break;
536
case '=':
537
if ((c = xeh[*s++]) < 0 || (d = xeh[*s++]) < 0)
538
break;
539
*b++ = (c << 4) | d;
540
continue;
541
default:
542
*b++ = c;
543
continue;
544
}
545
break;
546
}
547
sfwrite(uu->op, x, b - x);
548
}
549
return 0;
550
}
551
552
/*
553
* binhex based on
554
*
555
* xbin Version 2.3 09/30/85
556
* Dave Johnson, Brown University Computer Science
557
*/
558
559
#define BX_REPEAT 0x90
560
561
#define BX_OLD (UU_METHOD<<0)
562
563
typedef struct
564
{
565
int col;
566
int eof;
567
int last;
568
int repeat;
569
off_t size;
570
unsigned long crc;
571
unsigned char* qp;
572
unsigned char* qe;
573
unsigned char qbuf[3];
574
char map[UCHAR_MAX + 2];
575
} Bx_t;
576
577
/*
578
* add c to the binhex Q format crc
579
*/
580
581
static int
582
bx_q_crc(register Bx_t* bx, int c)
583
{
584
register int i = 8;
585
register unsigned int k = c;
586
register unsigned long crc = bx->crc;
587
588
while (i--)
589
{
590
k <<= 1;
591
if ((crc <<= 1) & 0x10000)
592
crc = (crc & 0xFFFF) ^ 0x1021;
593
crc ^= k >> 8;
594
k &= 0xFF;
595
}
596
bx->crc = crc;
597
return c;
598
}
599
600
/*
601
* return next binhex Q format char
602
*/
603
604
static int
605
bx_q_getc(register Uu_t* uu, register Bx_t* bx)
606
{
607
register int c;
608
register unsigned char* ip;
609
register unsigned char* ie;
610
register unsigned char* m;
611
int x;
612
unsigned long crc;
613
unsigned char ibuf[4];
614
615
if (bx->repeat > 0)
616
{
617
bx->repeat--;
618
return bx_q_crc(bx, bx->last);
619
}
620
if (bx->qp >= bx->qe)
621
{
622
if (bx->eof)
623
return EOF;
624
bx->qp = bx->qbuf;
625
m = (unsigned char*)bx->map + 1;
626
ie = (ip = ibuf) + sizeof(ibuf);
627
while (ip < ie)
628
{
629
while ((c = m[sfgetc(uu->ip)]) >= 64)
630
if (c != UU_IGN)
631
{
632
bx->eof = 1;
633
bx->qe = bx->qbuf;
634
if ((c = (ip - ibuf) - 1) <= 0)
635
return EOF;
636
bx->qe += c;
637
break;
638
}
639
*ip++ = c;
640
}
641
ip = ibuf;
642
ie = bx->qp;
643
ie[0] = (ip[0] << 2) | (ip[1] >> 4);
644
ie[1] = (ip[1] << 4) | (ip[2] >> 2);
645
ie[2] = (ip[2] << 6) | (ip[3] );
646
}
647
if ((c = *bx->qp++) == BX_REPEAT && !bx->repeat)
648
{
649
c = bx->last;
650
crc = bx->crc;
651
bx->repeat = -1;
652
x = bx_q_getc(uu, bx);
653
bx->crc = crc;
654
switch (x)
655
{
656
case EOF:
657
return EOF;
658
case 0:
659
bx->repeat = 0;
660
c = BX_REPEAT;
661
break;
662
case 1:
663
bx->repeat = 0;
664
break;
665
default:
666
bx->repeat = x - 2;
667
break;
668
}
669
}
670
return bx->last = bx_q_crc(bx, c);
671
}
672
673
/*
674
* return binhex Q format n byte int
675
*/
676
677
static long
678
bx_q_getn(register Uu_t* uu, register Bx_t* bx, register int n)
679
{
680
register long v = 0;
681
682
while (n--)
683
v = (v << 8) | bx_q_getc(uu, bx);
684
return v;
685
}
686
687
/*
688
* return binhex Q format buffer of size n
689
*/
690
691
static ssize_t
692
bx_q_gets(register Uu_t* uu, register Bx_t* bx, register char* s, size_t n)
693
{
694
register int c;
695
register char* e;
696
697
e = s + n;
698
while (s < e)
699
{
700
if ((c = bx_q_getc(uu, bx)) == EOF)
701
return -1;
702
*s++ = c;
703
}
704
return n;
705
}
706
707
/*
708
* low level for bx_q_putc()
709
*/
710
711
static int
712
bx_q_put(register Uu_t* uu, register Bx_t* bx, register int c)
713
{
714
register unsigned char* p;
715
register unsigned char* m;
716
717
*bx->qp++ = c;
718
if (bx->qp >= bx->qe)
719
{
720
m = (unsigned char*)((Uudata_t*)uu->meth.data)->map;
721
p = bx->qp = bx->qbuf;
722
c = (p[0] << 16) | (p[1] << 8) | p[2];
723
sfputc(uu->op, m[(c >> 18) & 0x3f]);
724
sfputc(uu->op, m[(c >> 12) & 0x3f]);
725
sfputc(uu->op, m[(c >> 6) & 0x3f]);
726
sfputc(uu->op, m[(c ) & 0x3f]);
727
if ((bx->col += 4) >= 63)
728
{
729
bx->col = 0;
730
sfputc(uu->op, '\n');
731
}
732
}
733
return 0;
734
}
735
736
/*
737
* output binhex Q format char
738
*/
739
740
static int
741
bx_q_putc(register Uu_t* uu, register Bx_t* bx, register int c)
742
{
743
if (c == bx->last)
744
{
745
if (!bx->repeat++)
746
{
747
bx_q_put(uu, bx, c);
748
bx_q_put(uu, bx, BX_REPEAT);
749
}
750
bx_q_crc(bx, c);
751
if (bx->repeat >= 0xFF)
752
{
753
bx_q_put(uu, bx, bx->repeat);
754
bx->repeat = 0;
755
bx->last = -1;
756
}
757
}
758
else
759
{
760
if (bx->repeat)
761
{
762
bx_q_put(uu, bx, bx->repeat);
763
bx->repeat = 0;
764
bx->last = -1;
765
}
766
if (c == BX_REPEAT)
767
{
768
bx_q_put(uu, bx, c);
769
bx_q_put(uu, bx, 0);
770
bx->last = -1;
771
}
772
else if (c == '\n' && (uu->flags & UU_TEXT))
773
{
774
bx_q_put(uu, bx, '\r');
775
bx_q_crc(bx, '\r');
776
bx_q_put(uu, bx, '\n');
777
bx->last = -1;
778
}
779
else
780
{
781
bx_q_put(uu, bx, c);
782
bx->last = c;
783
}
784
bx_q_crc(bx, c);
785
}
786
return 0;
787
}
788
789
/*
790
* output binhex Q format n byte int
791
*/
792
793
static int
794
bx_q_putn(register Uu_t* uu, register Bx_t* bx, register unsigned long v, int n)
795
{
796
switch (n)
797
{
798
case 4: bx_q_putc(uu, bx, (v >> 24) & 0xFF);
799
case 3: bx_q_putc(uu, bx, (v >> 16) & 0xFF);
800
case 2: bx_q_putc(uu, bx, (v >> 8) & 0xFF);
801
case 1: bx_q_putc(uu, bx, (v >> 0) & 0xFF);
802
}
803
return 0;
804
}
805
806
/*
807
* grab binhex header from input
808
*/
809
810
static int
811
bx_header(register Uu_t* uu)
812
{
813
register Bx_t* bx = (Bx_t*)(uu + 1);
814
Uudata_t* dp = (Uudata_t*)uu->meth.data;
815
register int c;
816
register int bol;
817
register char* s;
818
register char* m;
819
unsigned long crc;
820
unsigned long crx;
821
char buf[UCHAR_MAX + 2];
822
823
if (uu->flags & UU_HEADER)
824
do
825
{
826
if (!(s = sfgetr(uu->ip, '\n', 0)))
827
{
828
if (uu->disc->errorf)
829
(*uu->disc->errorf)(uu, uu->disc, 2, "unknown encoding");
830
return -1;
831
}
832
} while (*s != '(' || strncmp(s, "(This file", 10));
833
bol = 1;
834
for (;;)
835
{
836
switch (c = sfgetc(uu->ip))
837
{
838
case EOF:
839
return -1;
840
case '\n':
841
case '\r':
842
bol = 1;
843
break;
844
case ':':
845
if (bol)
846
{
847
/*
848
* Q format
849
*
850
* 1 n name length
851
* n s name
852
* 4 s type
853
* 4 s author
854
* 2 n flags
855
* 4 n data size
856
* 4 n resource size
857
* 2 n header checksum
858
*/
859
860
memset(s = bx->map, UU_END, sizeof(bx->map));
861
for (s++, m = (char*)dp->map; c = *m; m++)
862
s[c] = m - (char*)dp->map;
863
s['\n'] = UU_IGN;
864
s['\r'] = UU_IGN;
865
bx->qp = bx->qe = bx->qbuf + sizeof(bx->qbuf);
866
if ((c = bx_q_getc(uu, bx)) == EOF)
867
return -1;
868
if (bx_q_gets(uu, bx, buf, c + 1) < 0)
869
return -1;
870
if (!uu->path)
871
{
872
uu->path = strdup(buf);
873
uu->flags |= UU_FREEPATH;
874
}
875
if (bx_q_gets(uu, bx, buf, 4) < 0)
876
return -1;
877
if (bx_q_gets(uu, bx, buf, 4) < 0)
878
return -1;
879
bx_q_getn(uu, bx, 2);
880
bx->size = bx_q_getn(uu, bx, 4);
881
bx_q_getn(uu, bx, 4);
882
bx_q_crc(bx, 0);
883
bx_q_crc(bx, 0);
884
crc = bx->crc;
885
crx = bx_q_getn(uu, bx, 2);
886
if (crc != crx)
887
{
888
if (uu->disc->errorf)
889
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format header checksum mismatch", uu->meth.name);
890
return -1;
891
}
892
return 0;
893
}
894
break;
895
case '#':
896
if (bol)
897
{
898
/*
899
* old format
900
*/
901
902
sfungetc(uu->ip, c);
903
uu->flags |= BX_OLD;
904
905
/*
906
* #<TYPE><AUTH>$<flag>
907
*/
908
909
if (!sfgetr(uu->ip, '\n', 0))
910
return -1;
911
return 0;
912
}
913
break;
914
default:
915
bol = 0;
916
break;
917
}
918
}
919
}
920
921
/*
922
* old binhex line decode
923
*/
924
925
static int
926
bx_o_decode(register Uu_t* uu, Bx_t* bx, char* buf, register size_t n)
927
{
928
register int c;
929
register int d;
930
register unsigned long crc = bx->crc;
931
register unsigned char* m = (unsigned char*)bx->map;
932
register char* t = (char*)hex;
933
register unsigned char* s = (unsigned char*)buf;
934
935
memset(m, UU_END, sizeof(bx->map));
936
for (c = 0; c < elementsof(hex); c++)
937
m[t[c]] = c;
938
n <= 2;
939
while (n--)
940
{
941
if ((c = m[*s++]) == UU_END || (d = m[*s++]) == UU_END)
942
return -1;
943
crc += c = (c << 4) | d;
944
sfputc(uu->op, c);
945
}
946
bx->crc = crc;
947
return 0;
948
}
949
950
/*
951
* old binhex compressed line decode
952
*/
953
954
#define BX_O_MASK(c) (((c)-0x20)&0x3F)
955
#define BX_O_CRC(s,c) ((s=(s+c)&0xFF),(s=((s<<3)&0xFF)|(s>>13)))
956
957
static int
958
bx_c_decode(register Uu_t* uu, Bx_t* bx, register char* s, size_t n)
959
{
960
register int c;
961
register int oc;
962
register unsigned long crc;
963
char* e;
964
int ic;
965
char buf[SF_BUFSIZE];
966
967
crc = bx->crc;
968
oc = (BX_O_MASK(s[0]) << 2) | (BX_O_MASK(s[1]) >> 4);
969
ic = ((oc / 3) + 1) * 4;
970
if (ic > SF_BUFSIZE)
971
ic = SF_BUFSIZE;
972
if (n > SF_BUFSIZE)
973
n = SF_BUFSIZE;
974
memcpy(buf, s, n);
975
s = buf + n;
976
e = buf + ic;
977
while (s < e)
978
*s++ = ' ';
979
s = buf;
980
while ((oc -= 3) >= 0)
981
{
982
c = (BX_O_MASK(s[0]) << 2) | (BX_O_MASK(s[1]) >> 4);
983
BX_O_CRC(crc, c);
984
sfputc(uu->op, c);
985
c = (BX_O_MASK(s[1]) << 4) | (BX_O_MASK(s[2]) >> 2);
986
BX_O_CRC(crc, c);
987
sfputc(uu->op, c);
988
c = (BX_O_MASK(s[2]) << 6) | (BX_O_MASK(s[3]) );
989
BX_O_CRC(crc, c);
990
sfputc(uu->op, c);
991
s += 4;
992
}
993
bx->crc = crc;
994
return 0;
995
}
996
997
/*
998
* binhex decode input to output
999
*/
1000
1001
static int
1002
bx_decode(register Uu_t* uu)
1003
{
1004
register Bx_t* bx = (Bx_t*)(uu + 1);
1005
register off_t n;
1006
register int c;
1007
register char* s;
1008
unsigned long crc;
1009
int (*decode)(Uu_t*, Bx_t*, char*, size_t);
1010
1011
crc = 0x10000;
1012
bx->crc = 0;
1013
if (uu->flags & BX_OLD)
1014
{
1015
decode = bx_o_decode;
1016
c = 0;
1017
while (s = sfgetr(uu->ip, '\n', 0))
1018
if (*s++ == '*' && *s++ == '*' && *s++ == '*')
1019
{
1020
switch (*s)
1021
{
1022
case 'C':
1023
switch (s[1])
1024
{
1025
case 'O':
1026
if (c || strncmp(s, "COMPRESSED", 10))
1027
continue;
1028
decode = bx_c_decode;
1029
continue;
1030
case 'H':
1031
if (decode == bx_c_decode || strncmp(s, "CHECKSUM:", 9))
1032
continue;
1033
crc = bx->crc & 0xFF;
1034
bx->crc = strtoul(s + 9, NiL, 16) & 0xFF;
1035
break;
1036
case 'R':
1037
if (decode == bx_o_decode || strncmp(s, "CRC:", 4))
1038
continue;
1039
crc = bx->crc & 0xFFFF;
1040
bx->crc = strtoul(s + 4, NiL, 16) & 0xFFFF;
1041
break;
1042
default:
1043
continue;
1044
}
1045
break;
1046
case 'D':
1047
if (strncmp(s, "DATA", 4))
1048
continue;
1049
while (s = sfgetr(uu->ip, '\n', 0))
1050
{
1051
if (strneq(s, "***END", 6))
1052
break;
1053
if ((*decode)(uu, bx, s, sfvalue(uu->ip) - 1) < 0)
1054
return -1;
1055
}
1056
break;
1057
case 'R':
1058
if (c || strncmp(s, "RESOURCE", 8))
1059
continue;
1060
c = 1;
1061
continue;
1062
default:
1063
continue;
1064
}
1065
break;
1066
}
1067
}
1068
else
1069
{
1070
if ((n = bx->size) > 0)
1071
while (n--)
1072
{
1073
if ((c = bx_q_getc(uu, bx)) == EOF)
1074
return -1;
1075
sfputc(uu->op, c);
1076
}
1077
1078
/*
1079
* check the header crc
1080
*/
1081
1082
bx_q_crc(bx, 0);
1083
bx_q_crc(bx, 0);
1084
crc = bx->crc;
1085
bx->crc = bx_q_getn(uu, bx, 2);
1086
}
1087
if (crc != bx->crc)
1088
{
1089
if (uu->disc->errorf)
1090
{
1091
if (crc == 0x10000)
1092
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format checksum missing", uu->meth.name);
1093
else
1094
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format data checksum mismatch", uu->meth.name);
1095
}
1096
return -1;
1097
}
1098
return 0;
1099
}
1100
1101
/*
1102
* binhex encode input to output
1103
*/
1104
1105
static int
1106
bx_encode(register Uu_t* uu)
1107
{
1108
register Bx_t* bx = (Bx_t*)(uu + 1);
1109
register unsigned char* m;
1110
register int c;
1111
register int i;
1112
struct stat st;
1113
1114
bx->last = -1;
1115
bx->qp = bx->qbuf;
1116
bx->qe = bx->qbuf + sizeof(bx->qbuf);
1117
if (fstat(sffileno(uu->ip), &st))
1118
st.st_size = 0;
1119
sfprintf(uu->op, "(This file must be converted with BinHex 4.0)\n:");
1120
if (!(m = (unsigned char*)uu->path))
1121
m = (unsigned char*)"-";
1122
if ((c = strlen((char*)m)) > 63)
1123
c = 63;
1124
bx_q_putc(uu, bx, c);
1125
for (i = 0; i < c; i++)
1126
bx_q_putc(uu, bx, m[i]);
1127
bx_q_putc(uu, bx, 0);
1128
bx_q_putn(uu, bx, 0, 4);
1129
bx_q_putn(uu, bx, 0, 4);
1130
bx_q_putn(uu, bx, 0xF800, 2);
1131
bx_q_putn(uu, bx, st.st_size, 4);
1132
bx_q_putn(uu, bx, 0, 4);
1133
bx_q_crc(bx, 0);
1134
bx_q_crc(bx, 0);
1135
bx_q_putn(uu, bx, bx->crc, 2);
1136
bx->crc = 0;
1137
while ((c = sfgetc(uu->ip)) != EOF)
1138
bx_q_putc(uu, bx, c);
1139
bx_q_crc(bx, 0);
1140
bx_q_crc(bx, 0);
1141
bx_q_putn(uu, bx, bx->crc, 2);
1142
bx->crc = 0;
1143
bx_q_crc(bx, 0);
1144
bx_q_crc(bx, 0);
1145
bx_q_putn(uu, bx, bx->crc, 2);
1146
while (bx->qp != bx->qbuf)
1147
bx_q_putc(uu, bx, 0);
1148
sfputc(uu->op, ':');
1149
sfputc(uu->op, '\n');
1150
return 0;
1151
}
1152
1153
/*
1154
* cat input to output
1155
*/
1156
1157
static int
1158
cat(register Uu_t* uu)
1159
{
1160
return sfmove(uu->ip, uu->op, SF_UNBOUND, -1) >= 0 && sfeof(uu->ip) ? 0 : -1;
1161
}
1162
1163
static Uudata_t uu_posix =
1164
{
1165
"end",
1166
0,
1167
0,
1168
UU_HEADER|UU_LENGTH,
1169
0,
1170
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1171
};
1172
1173
static const Uudata_t uu_ucb =
1174
{
1175
"end",
1176
0,
1177
0156,
1178
UU_HEADER|UU_LENGTH,
1179
0,
1180
"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1181
};
1182
1183
static const Uudata_t uu_base64 =
1184
{
1185
"====",
1186
'=',
1187
0,
1188
0,
1189
0,
1190
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
1191
};
1192
1193
static const Uudata_t uu_bx =
1194
{
1195
0,
1196
0,
1197
0,
1198
UU_HEADER|UU_HEADERMUST,
1199
sizeof(Bx_t),
1200
"!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"
1201
};
1202
1203
static const Uumeth_t methods[] =
1204
{
1205
1206
{
1207
"posix", "uuencode", "",
1208
uu_header, uu_encode, uu_decode, (void*)&uu_posix
1209
},
1210
{
1211
"ucb", "bsd", "",
1212
uu_header, uu_encode, uu_decode, (void*)&uu_ucb
1213
},
1214
{
1215
"mime", "base64", "-base64",
1216
0, uu_encode, uu_decode, (void*)&uu_base64
1217
},
1218
{
1219
"quoted-printable", "qp", "",
1220
0, qp_encode, qp_decode, 0
1221
},
1222
{
1223
"binhex", "mac-binhex", "",
1224
bx_header, bx_encode, bx_decode, (void*)&uu_bx
1225
},
1226
{
1227
"sevenbit", "7bit", "",
1228
0, cat, cat, 0
1229
},
1230
1231
{ 0 }
1232
1233
};
1234
1235
/*
1236
* list the method names/alternates on fp
1237
*/
1238
1239
int
1240
uulist(Sfio_t* fp)
1241
{
1242
register const Uumeth_t* mp;
1243
1244
sfprintf(fp, "ENCODING ALIAS\n");
1245
for (mp = methods; mp->name; mp++)
1246
sfprintf(fp, "%-17s %s\n", mp->name, mp->alias);
1247
return 0;
1248
}
1249
1250
/*
1251
* return method pointer given name
1252
*/
1253
1254
Uumeth_t*
1255
uumeth(const char* name)
1256
{
1257
register const Uumeth_t* mp;
1258
register int c;
1259
register const char* v;
1260
register int vl;
1261
const char* np;
1262
1263
/*
1264
* first entry is the default
1265
*/
1266
1267
if (!name || !*name)
1268
{
1269
((Uudata_t*)methods->data)->flags |= UU_DEFAULT;
1270
return (Uumeth_t*)methods;
1271
}
1272
if ((*name == 'x' || *name == 'X') && *(name + 1) == '-')
1273
name += 2;
1274
if (*name == 'b' && !strncasecmp(name, UU_BEGIN, UU_BEGIN_LEN))
1275
{
1276
/*
1277
* id prefix match
1278
*/
1279
1280
if ((c = *(name += UU_BEGIN_LEN)) == ' ')
1281
return (Uumeth_t*)methods;
1282
for (mp = methods; mp->name; mp++)
1283
if (*mp->id == c && !strncasecmp(name, mp->id, strlen(mp->id)))
1284
return (Uumeth_t*)mp;
1285
if (c == '-')
1286
return (Uumeth_t*)methods;
1287
}
1288
else
1289
{
1290
c = *name;
1291
for (v = name + strlen(name); v > name && (isdigit(*(v - 1)) || *(v - 1) == '.'); v--);
1292
vl = *v ? (v - name) : 0;
1293
1294
/*
1295
* exact name or alias match
1296
*/
1297
1298
for (;;)
1299
{
1300
for (mp = methods; mp->name; mp++)
1301
if (*mp->name == c && (!strcasecmp(name, mp->name) || vl && !strncasecmp(name, mp->name, vl)) ||
1302
mp->alias && *mp->alias == c && (!strcasecmp(name, mp->alias) || vl && !strncasecmp(name, mp->alias, vl)))
1303
return (Uumeth_t*)mp;
1304
np = name;
1305
if (!(name = strchr(name, '/')))
1306
break;
1307
if (((c = *++name) == 'x' || *name == 'X') && *(name + 1) == '-')
1308
c = *(name += 2);
1309
if (vl)
1310
vl -= (name - np);
1311
}
1312
1313
/*
1314
* first char name match
1315
*/
1316
1317
for (mp = methods; mp->name; mp++)
1318
if (*mp->name == c)
1319
return (Uumeth_t*)mp;
1320
}
1321
return 0;
1322
}
1323
1324
/*
1325
* open an encode/decode handle
1326
*/
1327
1328
Uu_t*
1329
uuopen(Uudisc_t* disc, Uumeth_t* meth)
1330
{
1331
register Uu_t* uu;
1332
register Uudata_t* data;
1333
int extra;
1334
1335
if (data = (Uudata_t*)meth->data)
1336
extra = data->size;
1337
else
1338
extra = 0;
1339
if (!(uu = newof(0, Uu_t, 1, extra)))
1340
return 0;
1341
uu->id = lib;
1342
uu->disc = disc;
1343
uu->meth = *meth;
1344
return uu;
1345
}
1346
1347
/*
1348
* close an encode/decode handle
1349
*/
1350
1351
int
1352
uuclose(Uu_t* uu)
1353
{
1354
if (!uu)
1355
return -1;
1356
if ((uu->flags & UU_FREEPATH) && uu->path)
1357
free(uu->path);
1358
free(uu);
1359
return 0;
1360
}
1361
1362
/*
1363
* common encode/decode tail
1364
*/
1365
1366
static ssize_t
1367
uuop(register Uu_t* uu, Uu_f fun)
1368
{
1369
int n;
1370
ssize_t r;
1371
Sfoff_t p;
1372
1373
if (uu->count != SF_UNBOUND && ((p = sfseek(uu->ip, (Sfoff_t)0, SEEK_CUR)) < 0 || !(uu->ip = sfdcsubstream(NiL, uu->lp = uu->ip, p, uu->count))))
1374
{
1375
if (uu->disc->errorf)
1376
(*uu->disc->errorf)(uu, uu->disc, 2, "cannot initialize substream at %I*d for %I*d bytes", sizeof(p), p, sizeof(uu->count), uu->count);
1377
return -1;
1378
}
1379
p = sfseek(uu->op, (Sfoff_t)0, SEEK_CUR);
1380
n = (*fun)(uu);
1381
if (uu->lp)
1382
{
1383
sfclose(uu->ip);
1384
uu->ip = uu->lp;
1385
uu->lp = 0;
1386
}
1387
if (n < 0)
1388
r = -1;
1389
else if (sfsync(uu->op) || sferror(uu->op))
1390
{
1391
r = -1;
1392
if (uu->disc->errorf)
1393
(*uu->disc->errorf)(uu, uu->disc, 2, "write error");
1394
}
1395
else if (sferror(uu->ip))
1396
{
1397
r = -1;
1398
if (uu->disc->errorf)
1399
(*uu->disc->errorf)(uu, uu->disc, 2, "read error");
1400
}
1401
else
1402
r = sfseek(uu->op, (Sfoff_t)0, SEEK_CUR) - p;
1403
if (uu->flags & UU_CLOSEOUT)
1404
{
1405
uu->flags &= ~UU_CLOSEOUT;
1406
sfclose(uu->op);
1407
}
1408
return r;
1409
}
1410
1411
/*
1412
* encode n bytes (or all if SF_UNBOUND) from ip to op
1413
*/
1414
1415
ssize_t
1416
uuencode(register Uu_t* uu, Sfio_t* ip, Sfio_t* op, size_t n, const char* path)
1417
{
1418
if (!uu->meth.encodef)
1419
{
1420
if (uu->disc->errorf)
1421
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format encoding not supported", uu->meth.name);
1422
return -1;
1423
}
1424
if (!(uu->ip = ip) || !(uu->op = op))
1425
return -1;
1426
uu->count = n;
1427
if ((uu->flags & UU_FREEPATH) && uu->path)
1428
free(uu->path);
1429
uu->path = (char*)path;
1430
uu->flags = uu->disc->flags;
1431
return uuop(uu, uu->meth.encodef);
1432
}
1433
1434
/*
1435
* decode n bytes (or all if SF_UNBOUND) from ip to op
1436
*/
1437
1438
ssize_t
1439
uudecode(register Uu_t* uu, Sfio_t* ip, Sfio_t* op, size_t n, const char* path)
1440
{
1441
register char* s;
1442
unsigned char* m;
1443
int c;
1444
int headerpath;
1445
Uudata_t* data;
1446
const Uumeth_t* mp;
1447
char map[UCHAR_MAX + 2];
1448
1449
if (!uu->meth.decodef)
1450
{
1451
if (uu->disc->errorf)
1452
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format decoding not supported", uu->meth.name);
1453
return -1;
1454
}
1455
if (!(uu->ip = ip))
1456
return -1;
1457
uu->op = op;
1458
uu->count = n;
1459
if ((uu->flags & UU_FREEPATH) && uu->path)
1460
free(uu->path);
1461
uu->path = (char*)path;
1462
uu->flags = uu->disc->flags;
1463
data = (Uudata_t*)uu->meth.data;
1464
if (((uu->flags & UU_HEADER) || data && (data->flags & UU_HEADERMUST)) && uu->meth.headerf)
1465
{
1466
if ((*uu->meth.headerf)(uu))
1467
return -1;
1468
headerpath = 1;
1469
}
1470
else
1471
{
1472
headerpath = 0;
1473
if (data && (data->flags & UU_DEFAULT) && (c = sfgetc(uu->ip)) != EOF)
1474
{
1475
sfungetc(uu->ip, c);
1476
for (mp = methods; ((Uudata_t*)mp->data)->flags & UU_LENGTH; mp++)
1477
{
1478
m = uu_map((Uudata_t*)mp->data, map);
1479
if (m[c] > 0 && m[c] < (UUIN * UUCHUNK + 1))
1480
break;
1481
}
1482
if (mp > methods)
1483
{
1484
uu->meth = *mp;
1485
if (uu->disc->errorf)
1486
(*uu->disc->errorf)(uu, uu->disc, 1, "assuming %s encoding", mp->name);
1487
}
1488
}
1489
}
1490
if (!uu->op)
1491
{
1492
if (!uu->path && headerpath)
1493
{
1494
if (uu->disc->errorf)
1495
(*uu->disc->errorf)(uu, uu->disc, 2, "%s format header has no output file name", uu->meth.name);
1496
return -1;
1497
}
1498
if (!uu->path || !*uu->path || streq(uu->path, "-") || streq(uu->path, "/dev/stdout"))
1499
uu->op = sfstdout;
1500
else
1501
{
1502
if (headerpath && (uu->flags & UU_LOCAL))
1503
{
1504
for (s = uu->path; *s; s++)
1505
if (isspace(*s) || iscntrl(*s) || !isprint(*s) || *s == '/' || *s == '\\')
1506
*s = '_';
1507
s = uu->path;
1508
if (isalpha(s[0]) && s[1] == ':')
1509
s[1] = '_';
1510
}
1511
if (!(uu->op = sfopen(NiL, uu->path, "w")))
1512
{
1513
if (uu->disc->errorf)
1514
(*uu->disc->errorf)(uu, uu->disc, 2, "%s: cannot write", uu->path);
1515
return -1;
1516
}
1517
uu->flags |= UU_CLOSEOUT;
1518
}
1519
}
1520
return uuop(uu, uu->meth.decodef);
1521
}
1522
1523