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:
parent
0a1d787383
commit
8088bef24c
@ -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 \
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
627
lib/libarchive/archive_read_support_compression_uu.c
Normal file
627
lib/libarchive/archive_read_support_compression_uu.c
Normal 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);
|
||||
}
|
||||
|
@ -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 \
|
||||
|
134
lib/libarchive/test/test_read_uu.c
Normal file
134
lib/libarchive/test/test_read_uu.c
Normal 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user