2 * Copyright (c) 2009-2011 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$");
40 #include "archive_private.h"
41 #include "archive_read_private.h"
43 /* Maximum lookahead during bid phase */
44 #define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
48 unsigned char *in_buff;
49 #define IN_BUFF_SIZE (1024)
52 unsigned char *out_buff;
53 #define OUT_BUFF_SIZE (64 * 1024)
55 #define ST_FIND_HEAD 0
58 #define ST_READ_BASE64 3
62 static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
63 struct archive_read_filter *filter);
64 static int uudecode_bidder_init(struct archive_read_filter *);
66 static ssize_t uudecode_filter_read(struct archive_read_filter *,
68 static int uudecode_filter_close(struct archive_read_filter *);
70 #if ARCHIVE_VERSION_NUMBER < 4000000
71 /* Deprecated; remove in libarchive 4.0 */
73 archive_read_support_compression_uu(struct archive *a)
75 return archive_read_support_filter_uu(a);
80 archive_read_support_filter_uu(struct archive *_a)
82 struct archive_read *a = (struct archive_read *)_a;
83 struct archive_read_filter_bidder *bidder;
85 archive_check_magic(_a, ARCHIVE_READ_MAGIC,
86 ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
88 if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
89 return (ARCHIVE_FATAL);
93 bidder->bid = uudecode_bidder_bid;
94 bidder->init = uudecode_bidder_init;
95 bidder->options = NULL;
100 static const unsigned char ascii[256] = {
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
105 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
106 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
107 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
108 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
119 static const unsigned char uuchar[256] = {
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
122 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
125 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
126 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
138 static const unsigned char base64[256] = {
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
143 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
144 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
145 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
146 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
157 static const int base64num[128] = {
158 0, 0, 0, 0, 0, 0, 0, 0,
159 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
160 0, 0, 0, 0, 0, 0, 0, 0,
161 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
162 0, 0, 0, 0, 0, 0, 0, 0,
163 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
164 52, 53, 54, 55, 56, 57, 58, 59,
165 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
166 0, 0, 1, 2, 3, 4, 5, 6,
167 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
168 15, 16, 17, 18, 19, 20, 21, 22,
169 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
170 0, 26, 27, 28, 29, 30, 31, 32,
171 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
172 41, 42, 43, 44, 45, 46, 47, 48,
173 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
177 get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
182 while (len < avail) {
184 case 0: /* Non-ascii character or control character. */
189 if (avail-len > 1 && b[1] == '\n') {
211 bid_get_line(struct archive_read_filter *filter,
212 const unsigned char **b, ssize_t *avail, ssize_t *ravail,
213 ssize_t *nl, size_t* nbytes_read)
223 len = get_line(*b, *avail, nl);
226 * Read bytes more while it does not reach the end of line.
228 while (*nl == 0 && len == *avail && !quit &&
229 *nbytes_read < UUENCODE_BID_MAX_READ) {
230 ssize_t diff = *ravail - *avail;
231 size_t nbytes_req = (*ravail+1023) & ~1023U;
234 /* Increase reading bytes if it is not enough to at least
236 if (nbytes_req < (size_t)*ravail + 160)
239 *b = __archive_read_filter_ahead(filter, nbytes_req, avail);
241 if (*ravail >= *avail)
243 /* Reading bytes reaches the end of a stream. */
244 *b = __archive_read_filter_ahead(filter, *avail, avail);
247 *nbytes_read = *avail;
251 tested = len;/* Skip some bytes we already determinated. */
252 len = get_line(*b + tested, *avail - tested, nl);
259 #define UUDECODE(c) (((c) - 0x20) & 0x3f)
262 uudecode_bidder_bid(struct archive_read_filter_bidder *self,
263 struct archive_read_filter *filter)
265 const unsigned char *b;
266 ssize_t avail, ravail;
272 (void)self; /* UNUSED */
274 b = __archive_read_filter_ahead(filter, 1, &avail);
282 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
283 if (len < 0 || nl == 0)
284 return (0); /* No match found. */
285 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
287 else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
292 if (l > 0 && (b[l] < '0' || b[l] > '7' ||
293 b[l+1] < '0' || b[l+1] > '7' ||
294 b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
303 /* Do not read more than UUENCODE_BID_MAX_READ bytes */
304 if (nbytes_read >= UUENCODE_BID_MAX_READ)
309 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
310 if (len < 0 || nl == 0)
311 return (0);/* There are non-ascii characters. */
318 /* Get a length of decoded bytes. */
319 l = UUDECODE(*b++); len--;
321 /* Normally, maximum length is 45(character 'M'). */
324 return (0); /* Line too short. */
332 (uuchar[*b] || /* Check sum. */
333 (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
338 if (avail && uuchar[*b])
339 return (firstline+30);
340 } else if (l == 13) {
341 /* "begin-base64 " */
349 if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
350 return (firstline+40);
351 if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
352 return (firstline+40);
353 if (avail > 0 && base64[*b])
354 return (firstline+30);
361 uudecode_bidder_init(struct archive_read_filter *self)
363 struct uudecode *uudecode;
367 self->code = ARCHIVE_FILTER_UU;
369 self->read = uudecode_filter_read;
370 self->skip = NULL; /* not supported */
371 self->close = uudecode_filter_close;
373 uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
374 out_buff = malloc(OUT_BUFF_SIZE);
375 in_buff = malloc(IN_BUFF_SIZE);
376 if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
377 archive_set_error(&self->archive->archive, ENOMEM,
378 "Can't allocate data for uudecode");
382 return (ARCHIVE_FATAL);
385 self->data = uudecode;
386 uudecode->in_buff = in_buff;
387 uudecode->in_cnt = 0;
388 uudecode->in_allocated = IN_BUFF_SIZE;
389 uudecode->out_buff = out_buff;
390 uudecode->state = ST_FIND_HEAD;
396 ensure_in_buff_size(struct archive_read_filter *self,
397 struct uudecode *uudecode, size_t size)
400 if (size > uudecode->in_allocated) {
405 * Calculate a new buffer size for in_buff.
406 * Increase its value until it has enough size we need.
408 newsize = uudecode->in_allocated;
410 if (newsize < IN_BUFF_SIZE*32)
413 newsize += IN_BUFF_SIZE;
414 } while (size > newsize);
415 /* Allocate the new buffer. */
416 ptr = malloc(newsize);
419 archive_set_error(&self->archive->archive,
421 "Can't allocate data for uudecode");
422 return (ARCHIVE_FATAL);
424 /* Move the remaining data in in_buff into the new buffer. */
425 if (uudecode->in_cnt)
426 memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
427 /* Replace in_buff with the new buffer. */
428 free(uudecode->in_buff);
429 uudecode->in_buff = ptr;
430 uudecode->in_allocated = newsize;
436 uudecode_filter_read(struct archive_read_filter *self, const void **buff)
438 struct uudecode *uudecode;
439 const unsigned char *b, *d;
441 ssize_t avail_in, ravail;
444 ssize_t len, llen, nl;
446 uudecode = (struct uudecode *)self->data;
449 d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
450 if (d == NULL && avail_in < 0)
451 return (ARCHIVE_FATAL);
452 /* Quiet a code analyzer; make sure avail_in must be zero
458 out = uudecode->out_buff;
460 if (uudecode->state == ST_IGNORE) {
464 if (uudecode->in_cnt) {
466 * If there is remaining data which is saved by
467 * previous calling, use it first.
469 if (ensure_in_buff_size(self, uudecode,
470 avail_in + uudecode->in_cnt) != ARCHIVE_OK)
471 return (ARCHIVE_FATAL);
472 memcpy(uudecode->in_buff + uudecode->in_cnt,
474 d = uudecode->in_buff;
475 avail_in += uudecode->in_cnt;
476 uudecode->in_cnt = 0;
478 for (;used < avail_in; d += llen, used += llen) {
482 len = get_line(b, avail_in - used, &nl);
484 /* Non-ascii character is found. */
485 if (uudecode->state == ST_FIND_HEAD &&
486 (uudecode->total > 0 || total > 0)) {
487 uudecode->state = ST_IGNORE;
491 archive_set_error(&self->archive->archive,
493 "Insufficient compressed data");
494 return (ARCHIVE_FATAL);
497 if ((nl == 0) && (uudecode->state != ST_UUEND)) {
498 if (total == 0 && ravail <= 0) {
499 /* There is nothing more to read, fail */
500 archive_set_error(&self->archive->archive,
501 ARCHIVE_ERRNO_FILE_FORMAT,
502 "Missing format data");
503 return (ARCHIVE_FATAL);
506 * Save remaining data which does not contain
509 if (ensure_in_buff_size(self, uudecode, len)
511 return (ARCHIVE_FATAL);
512 if (uudecode->in_buff != b)
513 memmove(uudecode->in_buff, b, len);
514 uudecode->in_cnt = (int)len;
516 /* Do not return 0; it means end-of-file.
517 * We should try to read bytes more. */
518 __archive_read_filter_consume(
519 self->upstream, ravail);
525 switch (uudecode->state) {
528 /* Do not read more than UUENCODE_BID_MAX_READ bytes */
529 if (total + len >= UUENCODE_BID_MAX_READ) {
530 archive_set_error(&self->archive->archive,
531 ARCHIVE_ERRNO_FILE_FORMAT,
532 "Invalid format data");
533 return (ARCHIVE_FATAL);
535 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
537 else if (len - nl >= 18 &&
538 memcmp(b, "begin-base64 ", 13) == 0)
542 if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
543 b[l+1] >= '0' && b[l+1] <= '7' &&
544 b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
546 uudecode->state = ST_READ_UU;
548 uudecode->state = ST_READ_BASE64;
552 if (total + len * 2 > OUT_BUFF_SIZE)
555 if (!uuchar[*b] || body <= 0) {
556 archive_set_error(&self->archive->archive,
558 "Insufficient compressed data");
559 return (ARCHIVE_FATAL);
561 /* Get length of undecoded bytes of current line. */
565 archive_set_error(&self->archive->archive,
567 "Insufficient compressed data");
568 return (ARCHIVE_FATAL);
571 uudecode->state = ST_UUEND;
578 if (!uuchar[b[0]] || !uuchar[b[1]])
580 n = UUDECODE(*b++) << 18;
581 n |= UUDECODE(*b++) << 12;
582 *out++ = n >> 16; total++;
588 n |= UUDECODE(*b++) << 6;
589 *out++ = (n >> 8) & 0xFF; total++;
596 *out++ = n & 0xFF; total++;
601 archive_set_error(&self->archive->archive,
603 "Insufficient compressed data");
604 return (ARCHIVE_FATAL);
608 if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
609 uudecode->state = ST_FIND_HEAD;
611 archive_set_error(&self->archive->archive,
613 "Insufficient compressed data");
614 return (ARCHIVE_FATAL);
618 if (total + len * 2 > OUT_BUFF_SIZE)
621 if (l >= 3 && b[0] == '=' && b[1] == '=' &&
623 uudecode->state = ST_FIND_HEAD;
630 if (!base64[b[0]] || !base64[b[1]])
632 n = base64num[*b++] << 18;
633 n |= base64num[*b++] << 12;
634 *out++ = n >> 16; total++;
642 n |= base64num[*b++] << 6;
643 *out++ = (n >> 8) & 0xFF; total++;
651 n |= base64num[*b++];
652 *out++ = n & 0xFF; total++;
656 if (l && *b != '=') {
657 archive_set_error(&self->archive->archive,
659 "Insufficient compressed data");
660 return (ARCHIVE_FATAL);
666 if (ravail < avail_in)
667 used -= avail_in - ravail;
668 __archive_read_filter_consume(self->upstream, used);
670 *buff = uudecode->out_buff;
671 uudecode->total += total;
676 uudecode_filter_close(struct archive_read_filter *self)
678 struct uudecode *uudecode;
680 uudecode = (struct uudecode *)self->data;
681 free(uudecode->in_buff);
682 free(uudecode->out_buff);