mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-22 11:17:19 +00:00
e967c8b899
violated ECMA-119 (ISO9660): allow reserved4 to be 0x20 in PVD. This allows tar to read FreeBSD distribution ISO images created with makefs prior to NetBSD bin/45217 bugfix (up to 9.0-BETA1). In addition, merge following important bugfixes from libarchive's release/2.8 branch: Revision 2812: Merge 2811 from trunk: Don't try to verify that compression-level=0 produces larger results than the default compression, since this isn't true for all versions of liblzma. Revision 2817: Merge 2814 from trunk: Fix Issue 121 (mtree parser error) http://code.google.com/p/libarchive/issues/detail?id=121 Revision 2820: Fix issue 119. Change the file location check that a file location does not exceed volume block. New one is that a file content does not exceed volume block(end of an ISO image). It is better than previous check even if the issue did not happen. While reading an ISO image generated by an older version of mkisofs utility, a file location indicates the end the ISO image if its file size is zero and it is the last file of all files of the ISO image, so it is possible that the location value is the same as the number of the total block of the ISO image. http://code.google.com/p/libarchive/issues/detail?id=119 Revision 2955: Issue 134: Fix libarchive 2.8 crashing in archive_write_finish() when the open has failed and we're trying to write Zip format. http://code.google.com/p/libarchive/issues/detail?id=134 Revision 2958: Followup on Issue 134: 1) Port test_open_failure to libarchive 2.8 branch to test the problem reported in Issue 134. This test also shows that archive_read_open() sometimes fails to report open errors correctly. 2) Fix the bug in archive_read.c 3) Comment out the tests that close functions are invoked promptly when open fails; that's fully fixed in libarchive 3.0, but I don't think it's worth fixing here. Revision 3484: Use uintmax_t with %ju Revision 3487: Fix issue 163. Correctly allocate enough memory for a input buffer saved. http://code.google.com/p/libarchive/issues/detail?id=163 Revision 3542: Merge 2516, 2536 from trunk: Allow path table offset values of 0 and 18, which are used by some ISO writers. Reviewed by: kientzle Approved by: re (kib) MFC after: 3 days
638 lines
17 KiB
C
638 lines
17 KiB
C
/*-
|
|
* 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;
|
|
|
|
/*
|
|
* Calculate a new buffer size for in_buff.
|
|
* Increase its value until it has enough size we need.
|
|
*/
|
|
newsize = uudecode->in_allocated;
|
|
do {
|
|
if (newsize < IN_BUFF_SIZE*32)
|
|
newsize <<= 1;
|
|
else
|
|
newsize += IN_BUFF_SIZE;
|
|
} while (size > newsize);
|
|
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);
|
|
}
|
|
|