Blame libarchive/archive_read_support_filter_uu.c

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