2
* Copyright (c) 2009 Michihiro NAKAJIMA
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#include "archive_platform.h"
27
__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_compression_uu.c 201248 2009-12-30 06:12:03Z kientzle $");
40
#include "archive_private.h"
41
#include "archive_read_private.h"
45
unsigned char *in_buff;
46
#define IN_BUFF_SIZE (1024)
49
unsigned char *out_buff;
50
#define OUT_BUFF_SIZE (64 * 1024)
52
#define ST_FIND_HEAD 0
55
#define ST_READ_BASE64 3
58
static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
59
struct archive_read_filter *filter);
60
static int uudecode_bidder_init(struct archive_read_filter *);
62
static ssize_t uudecode_filter_read(struct archive_read_filter *,
64
static int uudecode_filter_close(struct archive_read_filter *);
67
archive_read_support_compression_uu(struct archive *_a)
69
struct archive_read *a = (struct archive_read *)_a;
70
struct archive_read_filter_bidder *bidder;
72
bidder = __archive_read_get_bidder(a);
73
archive_clear_error(_a);
75
return (ARCHIVE_FATAL);
78
bidder->bid = uudecode_bidder_bid;
79
bidder->init = uudecode_bidder_init;
80
bidder->options = NULL;
85
static const unsigned char ascii[256] = {
86
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
87
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
88
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
89
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
90
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
91
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
92
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
93
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
94
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
95
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
96
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
97
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
98
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
100
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
101
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
104
static const unsigned char uuchar[256] = {
105
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
106
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
107
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
108
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
109
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
110
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
111
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
112
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
113
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
114
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
115
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
116
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
117
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
118
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
120
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
123
static const unsigned char base64[256] = {
124
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
125
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
126
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
127
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
128
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
129
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
130
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
131
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
132
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
133
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
134
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
135
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
136
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
137
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
138
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
142
static const int base64num[128] = {
143
0, 0, 0, 0, 0, 0, 0, 0,
144
0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
145
0, 0, 0, 0, 0, 0, 0, 0,
146
0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
147
0, 0, 0, 0, 0, 0, 0, 0,
148
0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
149
52, 53, 54, 55, 56, 57, 58, 59,
150
60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
151
0, 0, 1, 2, 3, 4, 5, 6,
152
7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
153
15, 16, 17, 18, 19, 20, 21, 22,
154
23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
155
0, 26, 27, 28, 29, 30, 31, 32,
156
33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
157
41, 42, 43, 44, 45, 46, 47, 48,
158
49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
162
get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
167
while (len < avail) {
169
case 0: /* Non-ascii character or control character. */
174
if (avail-len > 1 && b[1] == '\n') {
196
bid_get_line(struct archive_read_filter *filter,
197
const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
207
len = get_line(*b, *avail, nl);
209
* Read bytes more while it does not reach the end of line.
211
while (*nl == 0 && len == *avail && !quit) {
212
ssize_t diff = *ravail - *avail;
214
*b = __archive_read_filter_ahead(filter, 160 + *ravail, avail);
216
if (*ravail >= *avail)
218
/* Reading bytes reaches the end of file. */
219
*b = __archive_read_filter_ahead(filter, *avail, avail);
225
len = get_line(*b, *avail, nl);
230
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
233
uudecode_bidder_bid(struct archive_read_filter_bidder *self,
234
struct archive_read_filter *filter)
236
const unsigned char *b;
237
ssize_t avail, ravail;
242
(void)self; /* UNUSED */
244
b = __archive_read_filter_ahead(filter, 1, &avail);
251
len = bid_get_line(filter, &b, &avail, &ravail, &nl);
252
if (len < 0 || nl == 0)
253
return (0);/* Binary data. */
254
if (memcmp(b, "begin ", 6) == 0 && len - nl >= 11)
256
else if (memcmp(b, "begin-base64 ", 13) == 0 && len - nl >= 18)
261
if (l > 0 && (b[l] < '0' || b[l] > '7' ||
262
b[l+1] < '0' || b[l+1] > '7' ||
263
b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
274
len = bid_get_line(filter, &b, &avail, &ravail, &nl);
275
if (len < 0 || nl == 0)
276
return (0);/* There are non-ascii characters. */
282
/* Get a length of decoded bytes. */
283
l = UUDECODE(*b++); len--;
285
/* Normally, maximum length is 45(character 'M'). */
287
while (l && len-nl > 0) {
312
(uuchar[*b] || /* Check sum. */
313
(*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
318
if (avail && uuchar[*b])
319
return (firstline+30);
329
if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
330
return (firstline+40);
331
if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
332
return (firstline+40);
333
if (avail > 0 && base64[*b])
334
return (firstline+30);
341
uudecode_bidder_init(struct archive_read_filter *self)
343
struct uudecode *uudecode;
347
self->code = ARCHIVE_COMPRESSION_UU;
349
self->read = uudecode_filter_read;
350
self->skip = NULL; /* not supported */
351
self->close = uudecode_filter_close;
353
uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
354
out_buff = malloc(OUT_BUFF_SIZE);
355
in_buff = malloc(IN_BUFF_SIZE);
356
if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
357
archive_set_error(&self->archive->archive, ENOMEM,
358
"Can't allocate data for uudecode");
362
return (ARCHIVE_FATAL);
365
self->data = uudecode;
366
uudecode->in_buff = in_buff;
367
uudecode->in_cnt = 0;
368
uudecode->in_allocated = IN_BUFF_SIZE;
369
uudecode->out_buff = out_buff;
370
uudecode->state = ST_FIND_HEAD;
376
ensure_in_buff_size(struct archive_read_filter *self,
377
struct uudecode *uudecode, size_t size)
380
if (size > uudecode->in_allocated) {
384
newsize = uudecode->in_allocated << 1;
385
ptr = malloc(newsize);
387
newsize < uudecode->in_allocated) {
389
archive_set_error(&self->archive->archive,
391
"Can't allocate data for uudecode");
392
return (ARCHIVE_FATAL);
394
if (uudecode->in_cnt)
395
memmove(ptr, uudecode->in_buff,
397
free(uudecode->in_buff);
398
uudecode->in_buff = ptr;
399
uudecode->in_allocated = newsize;
405
uudecode_filter_read(struct archive_read_filter *self, const void **buff)
407
struct uudecode *uudecode;
408
const unsigned char *b, *d;
410
ssize_t avail_in, ravail;
413
ssize_t len, llen, nl;
415
uudecode = (struct uudecode *)self->data;
418
d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
419
if (d == NULL && avail_in < 0)
420
return (ARCHIVE_FATAL);
421
/* Quiet a code analyzer; make sure avail_in must be zero
427
out = uudecode->out_buff;
429
if (uudecode->in_cnt) {
431
* If there is remaining data which is saved by
432
* previous calling, use it first.
434
if (ensure_in_buff_size(self, uudecode,
435
avail_in + uudecode->in_cnt) != ARCHIVE_OK)
436
return (ARCHIVE_FATAL);
437
memcpy(uudecode->in_buff + uudecode->in_cnt,
439
d = uudecode->in_buff;
440
avail_in += uudecode->in_cnt;
441
uudecode->in_cnt = 0;
443
for (;used < avail_in; d += llen, used += llen) {
447
len = get_line(b, avail_in - used, &nl);
449
/* Non-ascii character is found. */
450
archive_set_error(&self->archive->archive,
452
"Insufficient compressed data");
453
return (ARCHIVE_FATAL);
458
* Save remaining data which does not contain
461
if (ensure_in_buff_size(self, uudecode, len)
463
return (ARCHIVE_FATAL);
464
if (uudecode->in_buff != b)
465
memmove(uudecode->in_buff, b, len);
466
uudecode->in_cnt = len;
468
/* Do not return 0; it means end-of-file.
469
* We should try to read bytes more. */
470
__archive_read_filter_consume(
471
self->upstream, ravail);
476
if (total + len * 2 > OUT_BUFF_SIZE)
478
switch (uudecode->state) {
481
if (len - nl > 13 && memcmp(b, "begin ", 6) == 0)
483
else if (len - nl > 18 &&
484
memcmp(b, "begin-base64 ", 13) == 0)
488
if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
489
b[l+1] >= '0' && b[l+1] <= '7' &&
490
b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
492
uudecode->state = ST_READ_UU;
494
uudecode->state = ST_READ_BASE64;
499
if (!uuchar[*b] || body <= 0) {
500
archive_set_error(&self->archive->archive,
502
"Insufficient compressed data");
503
return (ARCHIVE_FATAL);
505
/* Get length of undecoded bytes of curent line. */
509
archive_set_error(&self->archive->archive,
511
"Insufficient compressed data");
512
return (ARCHIVE_FATAL);
515
uudecode->state = ST_UUEND;
522
if (!uuchar[b[0]] || !uuchar[b[1]])
524
n = UUDECODE(*b++) << 18;
525
n |= UUDECODE(*b++) << 12;
526
*out++ = n >> 16; total++;
532
n |= UUDECODE(*b++) << 6;
533
*out++ = (n >> 8) & 0xFF; total++;
540
*out++ = n & 0xFF; total++;
545
archive_set_error(&self->archive->archive,
547
"Insufficient compressed data");
548
return (ARCHIVE_FATAL);
552
if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
553
uudecode->state = ST_FIND_HEAD;
555
archive_set_error(&self->archive->archive,
557
"Insufficient compressed data");
558
return (ARCHIVE_FATAL);
563
if (l >= 3 && b[0] == '=' && b[1] == '=' &&
565
uudecode->state = ST_FIND_HEAD;
572
if (!base64[b[0]] || !base64[b[1]])
574
n = base64num[*b++] << 18;
575
n |= base64num[*b++] << 12;
576
*out++ = n >> 16; total++;
584
n |= base64num[*b++] << 6;
585
*out++ = (n >> 8) & 0xFF; total++;
593
n |= base64num[*b++];
594
*out++ = n & 0xFF; total++;
598
if (l && *b != '=') {
599
archive_set_error(&self->archive->archive,
601
"Insufficient compressed data");
602
return (ARCHIVE_FATAL);
608
__archive_read_filter_consume(self->upstream, ravail);
610
*buff = uudecode->out_buff;
611
uudecode->total += total;
616
uudecode_filter_close(struct archive_read_filter *self)
618
struct uudecode *uudecode;
620
uudecode = (struct uudecode *)self->data;
621
free(uudecode->in_buff);
622
free(uudecode->out_buff);