UU decoder. Now that libarchive can recursively taste input streams,

you can do things like this:  tar xvf archive.tar.gz.uu
This commit is contained in:
Tim Kientzle 2009-12-30 06:12:03 +00:00
parent 0a1d787383
commit 8088bef24c
6 changed files with 767 additions and 0 deletions

View File

@ -51,6 +51,7 @@ SRCS= archive_check_magic.c \
archive_read_support_compression_gzip.c \
archive_read_support_compression_none.c \
archive_read_support_compression_program.c \
archive_read_support_compression_uu.c \
archive_read_support_compression_xz.c \
archive_read_support_format_all.c \
archive_read_support_format_ar.c \

View File

@ -241,6 +241,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
#define ARCHIVE_COMPRESSION_PROGRAM 4
#define ARCHIVE_COMPRESSION_LZMA 5
#define ARCHIVE_COMPRESSION_XZ 6
#define ARCHIVE_COMPRESSION_UU 7
/*
* Codes returned by archive_format.
@ -316,6 +317,7 @@ __LA_DECL int archive_read_support_compression_program_signature
(struct archive *, const char *,
const void * /* match */, size_t);
__LA_DECL int archive_read_support_compression_uu(struct archive *);
__LA_DECL int archive_read_support_compression_xz(struct archive *);
__LA_DECL int archive_read_support_format_all(struct archive *);

View File

@ -44,6 +44,8 @@ archive_read_support_compression_all(struct archive *a)
archive_read_support_compression_lzma(a);
/* Xz falls back to "unxz" command-line program. */
archive_read_support_compression_xz(a);
/* The decode code doesn't use an outside library. */
archive_read_support_compression_uu(a);
/* Note: We always return ARCHIVE_OK here, even if some of the
* above return ARCHIVE_WARN. The intent here is to enable

View File

@ -0,0 +1,627 @@
/*-
* Copyright (c) 2009 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
struct uudecode {
int64_t total;
unsigned char *in_buff;
#define IN_BUFF_SIZE (1024)
int in_cnt;
size_t in_allocated;
unsigned char *out_buff;
#define OUT_BUFF_SIZE (64 * 1024)
int state;
#define ST_FIND_HEAD 0
#define ST_READ_UU 1
#define ST_UUEND 2
#define ST_READ_BASE64 3
};
static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *filter);
static int uudecode_bidder_init(struct archive_read_filter *);
static ssize_t uudecode_filter_read(struct archive_read_filter *,
const void **);
static int uudecode_filter_close(struct archive_read_filter *);
int
archive_read_support_compression_uu(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
bidder = __archive_read_get_bidder(a);
archive_clear_error(_a);
if (bidder == NULL)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = uudecode_bidder_bid;
bidder->init = uudecode_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
}
static const unsigned char ascii[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
static const unsigned char uuchar[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
static const unsigned char base64[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
static const int base64num[128] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
0, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
0, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
};
static ssize_t
get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
{
ssize_t len;
len = 0;
while (len < avail) {
switch (ascii[*b]) {
case 0: /* Non-ascii character or control character. */
if (nlsize != NULL)
*nlsize = 0;
return (-1);
case '\r':
if (avail-len > 1 && b[1] == '\n') {
if (nlsize != NULL)
*nlsize = 2;
return (len+2);
}
/* FALL THROUGH */
case '\n':
if (nlsize != NULL)
*nlsize = 1;
return (len+1);
case 1:
b++;
len++;
break;
}
}
if (nlsize != NULL)
*nlsize = 0;
return (avail);
}
static ssize_t
bid_get_line(struct archive_read_filter *filter,
const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
{
ssize_t len;
int quit;
quit = 0;
if (*avail == 0) {
*nl = 0;
len = 0;
} else
len = get_line(*b, *avail, nl);
/*
* Read bytes more while it does not reach the end of line.
*/
while (*nl == 0 && len == *avail && !quit) {
ssize_t diff = *ravail - *avail;
*b = __archive_read_filter_ahead(filter, 160 + *ravail, avail);
if (*b == NULL) {
if (*ravail >= *avail)
return (0);
/* Reading bytes reaches the end of file. */
*b = __archive_read_filter_ahead(filter, *avail, avail);
quit = 1;
}
*ravail = *avail;
*b += diff;
*avail -= diff;
len = get_line(*b, *avail, nl);
}
return (len);
}
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
static int
uudecode_bidder_bid(struct archive_read_filter_bidder *self,
struct archive_read_filter *filter)
{
const unsigned char *b;
ssize_t avail, ravail;
ssize_t len, nl;
int l;
int firstline;
(void)self; /* UNUSED */
b = __archive_read_filter_ahead(filter, 1, &avail);
if (b == NULL)
return (0);
firstline = 20;
ravail = avail;
for (;;) {
len = bid_get_line(filter, &b, &avail, &ravail, &nl);
if (len < 0 || nl == 0)
return (0);/* Binary data. */
if (memcmp(b, "begin ", 6) == 0 && len - nl >= 11)
l = 6;
else if (memcmp(b, "begin-base64 ", 13) == 0 && len - nl >= 18)
l = 13;
else
l = 0;
if (l > 0 && (b[l] < '0' || b[l] > '7' ||
b[l+1] < '0' || b[l+1] > '7' ||
b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
l = 0;
b += len;
avail -= len;
if (l)
break;
firstline = 0;
}
if (!avail)
return (0);
len = bid_get_line(filter, &b, &avail, &ravail, &nl);
if (len < 0 || nl == 0)
return (0);/* There are non-ascii characters. */
avail -= len;
if (l == 6) {
if (!uuchar[*b])
return (0);
/* Get a length of decoded bytes. */
l = UUDECODE(*b++); len--;
if (l > 45)
/* Normally, maximum length is 45(character 'M'). */
return (0);
while (l && len-nl > 0) {
if (l > 0) {
if (!uuchar[*b++])
return (0);
if (!uuchar[*b++])
return (0);
len -= 2;
--l;
}
if (l > 0) {
if (!uuchar[*b++])
return (0);
--len;
--l;
}
if (l > 0) {
if (!uuchar[*b++])
return (0);
--len;
--l;
}
}
if (len-nl < 0)
return (0);
if (len-nl == 1 &&
(uuchar[*b] || /* Check sum. */
(*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
++b;
--len;
}
b += nl;
if (avail && uuchar[*b])
return (firstline+30);
}
if (l == 13) {
while (len-nl > 0) {
if (!base64[*b++])
return (0);
--len;
}
b += nl;
if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
return (firstline+40);
if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
return (firstline+40);
if (avail > 0 && base64[*b])
return (firstline+30);
}
return (0);
}
static int
uudecode_bidder_init(struct archive_read_filter *self)
{
struct uudecode *uudecode;
void *out_buff;
void *in_buff;
self->code = ARCHIVE_COMPRESSION_UU;
self->name = "uu";
self->read = uudecode_filter_read;
self->skip = NULL; /* not supported */
self->close = uudecode_filter_close;
uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
out_buff = malloc(OUT_BUFF_SIZE);
in_buff = malloc(IN_BUFF_SIZE);
if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
archive_set_error(&self->archive->archive, ENOMEM,
"Can't allocate data for uudecode");
free(uudecode);
free(out_buff);
free(in_buff);
return (ARCHIVE_FATAL);
}
self->data = uudecode;
uudecode->in_buff = in_buff;
uudecode->in_cnt = 0;
uudecode->in_allocated = IN_BUFF_SIZE;
uudecode->out_buff = out_buff;
uudecode->state = ST_FIND_HEAD;
return (ARCHIVE_OK);
}
static int
ensure_in_buff_size(struct archive_read_filter *self,
struct uudecode *uudecode, size_t size)
{
if (size > uudecode->in_allocated) {
unsigned char *ptr;
size_t newsize;
newsize = uudecode->in_allocated << 1;
ptr = malloc(newsize);
if (ptr == NULL ||
newsize < uudecode->in_allocated) {
free(ptr);
archive_set_error(&self->archive->archive,
ENOMEM,
"Can't allocate data for uudecode");
return (ARCHIVE_FATAL);
}
if (uudecode->in_cnt)
memmove(ptr, uudecode->in_buff,
uudecode->in_cnt);
free(uudecode->in_buff);
uudecode->in_buff = ptr;
uudecode->in_allocated = newsize;
}
return (ARCHIVE_OK);
}
static ssize_t
uudecode_filter_read(struct archive_read_filter *self, const void **buff)
{
struct uudecode *uudecode;
const unsigned char *b, *d;
unsigned char *out;
ssize_t avail_in, ravail;
ssize_t used;
ssize_t total;
ssize_t len, llen, nl;
uudecode = (struct uudecode *)self->data;
read_more:
d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
if (d == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
/* Quiet a code analyzer; make sure avail_in must be zero
* when d is NULL. */
if (d == NULL)
avail_in = 0;
used = 0;
total = 0;
out = uudecode->out_buff;
ravail = avail_in;
if (uudecode->in_cnt) {
/*
* If there is remaining data which is saved by
* previous calling, use it first.
*/
if (ensure_in_buff_size(self, uudecode,
avail_in + uudecode->in_cnt) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
memcpy(uudecode->in_buff + uudecode->in_cnt,
d, avail_in);
d = uudecode->in_buff;
avail_in += uudecode->in_cnt;
uudecode->in_cnt = 0;
}
for (;used < avail_in; d += llen, used += llen) {
int l, body;
b = d;
len = get_line(b, avail_in - used, &nl);
if (len < 0) {
/* Non-ascii character is found. */
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
llen = len;
if (nl == 0) {
/*
* Save remaining data which does not contain
* NL('\n','\r').
*/
if (ensure_in_buff_size(self, uudecode, len)
!= ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (uudecode->in_buff != b)
memmove(uudecode->in_buff, b, len);
uudecode->in_cnt = len;
if (total == 0) {
/* Do not return 0; it means end-of-file.
* We should try to read bytes more. */
__archive_read_filter_consume(
self->upstream, ravail);
goto read_more;
}
break;
}
if (total + len * 2 > OUT_BUFF_SIZE)
break;
switch (uudecode->state) {
default:
case ST_FIND_HEAD:
if (len - nl > 13 && memcmp(b, "begin ", 6) == 0)
l = 6;
else if (len - nl > 18 &&
memcmp(b, "begin-base64 ", 13) == 0)
l = 13;
else
l = 0;
if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
b[l+1] >= '0' && b[l+1] <= '7' &&
b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
if (l == 6)
uudecode->state = ST_READ_UU;
else
uudecode->state = ST_READ_BASE64;
}
break;
case ST_READ_UU:
body = len - nl;
if (!uuchar[*b] || body <= 0) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
/* Get length of undecoded bytes of curent line. */
l = UUDECODE(*b++);
body--;
if (l > body) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
if (l == 0) {
uudecode->state = ST_UUEND;
break;
}
while (l > 0) {
int n = 0;
if (l > 0) {
if (!uuchar[b[0]] || !uuchar[b[1]])
break;
n = UUDECODE(*b++) << 18;
n |= UUDECODE(*b++) << 12;
*out++ = n >> 16; total++;
--l;
}
if (l > 0) {
if (!uuchar[b[0]])
break;
n |= UUDECODE(*b++) << 6;
*out++ = (n >> 8) & 0xFF; total++;
--l;
}
if (l > 0) {
if (!uuchar[b[0]])
break;
n |= UUDECODE(*b++);
*out++ = n & 0xFF; total++;
--l;
}
}
if (l) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
break;
case ST_UUEND:
if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
uudecode->state = ST_FIND_HEAD;
else {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
break;
case ST_READ_BASE64:
l = len - nl;
if (l >= 3 && b[0] == '=' && b[1] == '=' &&
b[2] == '=') {
uudecode->state = ST_FIND_HEAD;
break;
}
while (l > 0) {
int n = 0;
if (l > 0) {
if (!base64[b[0]] || !base64[b[1]])
break;
n = base64num[*b++] << 18;
n |= base64num[*b++] << 12;
*out++ = n >> 16; total++;
l -= 2;
}
if (l > 0) {
if (*b == '=')
break;
if (!base64[*b])
break;
n |= base64num[*b++] << 6;
*out++ = (n >> 8) & 0xFF; total++;
--l;
}
if (l > 0) {
if (*b == '=')
break;
if (!base64[*b])
break;
n |= base64num[*b++];
*out++ = n & 0xFF; total++;
--l;
}
}
if (l && *b != '=') {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
break;
}
}
__archive_read_filter_consume(self->upstream, ravail);
*buff = uudecode->out_buff;
uudecode->total += total;
return (total);
}
static int
uudecode_filter_close(struct archive_read_filter *self)
{
struct uudecode *uudecode;
uudecode = (struct uudecode *)self->data;
free(uudecode->in_buff);
free(uudecode->out_buff);
free(uudecode);
return (ARCHIVE_OK);
}

View File

@ -78,6 +78,7 @@ TESTS= \
test_read_pax_truncated.c \
test_read_position.c \
test_read_truncated.c \
test_read_uu.c \
test_tar_filenames.c \
test_tar_large.c \
test_ustar_filenames.c \

View File

@ -0,0 +1,134 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2009 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static const char archive[] = {
"begin 644 test_read_uu.Z\n"
"M'YV0+@`('$BPH,&#\"!,J7,BP(4(8$&_4J`$\"`,08$F%4O)AQ(\\2/(#7&@#%C\n"
"M!@T8-##.L`$\"QL@:-F(``%'#H<V;.'/J!%!G#ITP<BS\"H).FS<Z$1(T>/1A2\n"
"IHU\"0%9=*G4JUJM6K6+-JW<JUJ]>O8,.*'4NVK-FS:-.J7<NVK=NW9P$`\n"
"`\n"
"end\n"
};
static const char archive64[] = {
"begin-base64 644 test_read_uu.Z\n"
"H52QLgAIHEiwoMGDCBMqXMiwIUIYEG/UqAECAMQYEmFUvJhxI8SPIDXGgDFjBg0YNDDOsAECxsga\n"
"NmIAAFHDoc2bOHPqBFBnDp0wcizCoJOmzc6ERI0ePRhSo1CQFZdKnUq1qtWrWLNq3cq1q9evYMOK\n"
"HUu2rNmzaNOqXcu2rdu3ZwE=\n"
"====\n"
};
static const char extradata[] = {
"From uudecode@libarchive Mon Jun 2 03:03:31 2008\n"
"Return-Path: <uudecode@libarchive>\n"
"Received: from libarchive (localhost [127.0.0.1])\n"
" by libarchive (8.14.2/8.14.2) with ESMTP id m5233UT1006448\n"
" for <uudecode@libarchive>; Mon, 2 Jun 2008 03:03:31 GMT\n"
" (envelope-from uudecode@libarchive)\n"
"Received: (from uudecode@localhost)\n"
" by libarchive (8.14.2/8.14.2/Submit) id m5233U3e006406\n"
" for uudecode; Mon, 2 Jun 2008 03:03:30 GMT\n"
" (envelope-from root)\n"
"Date: Mon, 2 Jun 2008 03:03:30 GMT\n"
"From: Libarchive Test <uudecode@libarchive>\n"
"Message-Id: <200806020303.m5233U3e006406@libarchive>\n"
"To: uudecode@libarchive\n"
"Subject: Libarchive uudecode test\n"
"\n"
"* Redistribution and use in source and binary forms, with or without\n"
"* modification, are permitted provided that the following conditions\n"
"* are met:\n"
"\n"
"01234567890abcdeghijklmnopqrstuvwxyz\n"
"01234567890ABCEFGHIJKLMNOPQRSTUVWXYZ\n"
"\n"
};
static void
test_read_uu_sub(const char *uudata, size_t uusize)
{
struct archive_entry *ae;
struct archive *a;
char *buff;
int extra;
assert(NULL != (buff = malloc(uusize + 64 * 1024)));
if (buff == NULL)
return;
for (extra = 0; extra <= 64; extra = extra==0?1:extra*2) {
size_t size = extra * 1024;
char *p = buff;
/* Add extra text size of which is from 1K bytes to
* 64Kbytes before uuencoded data. */
while (size) {
if (size > sizeof(extradata)-1) {
memcpy(p, extradata, sizeof(extradata)-1);
p += sizeof(extradata)-1;
size -= sizeof(extradata)-1;
} else {
memcpy(p, extradata, size-1);
p += size-1;
*p++ = '\n';/* the last of extra text must have
* '\n' character. */
break;
}
}
memcpy(p, uudata, uusize);
size = extra * 1024 + uusize;
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK,
archive_read_support_compression_all(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK,
read_open_memory(a, buff, size, 2));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_next_header(a, &ae));
failure("archive_compression_name(a)=\"%s\"",
archive_compression_name(a));
assertEqualInt(archive_compression(a),
ARCHIVE_COMPRESSION_COMPRESS);
failure("archive_format_name(a)=\"%s\"",
archive_format_name(a));
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
}
free(buff);
}
DEFINE_TEST(test_read_uu)
{
/* Read the traditional uuencoded data. */
test_read_uu_sub(archive, sizeof(archive)-1);
/* Read the Base64 uuencoded data. */
test_read_uu_sub(archive64, sizeof(archive64)-1);
}