svn commit: r201248 - in head/lib/libarchive: . test

Tim Kientzle kientzle at FreeBSD.org
Wed Dec 30 06:12:04 UTC 2009


Author: kientzle
Date: Wed Dec 30 06:12:03 2009
New Revision: 201248
URL: http://svn.freebsd.org/changeset/base/201248

Log:
  UU decoder.  Now that libarchive can recursively taste input streams,
  you can do things like this:  tar xvf archive.tar.gz.uu

Added:
  head/lib/libarchive/archive_read_support_compression_uu.c   (contents, props changed)
  head/lib/libarchive/test/test_read_uu.c   (contents, props changed)
Modified:
  head/lib/libarchive/Makefile
  head/lib/libarchive/archive.h
  head/lib/libarchive/archive_read_support_compression_all.c
  head/lib/libarchive/test/Makefile

Modified: head/lib/libarchive/Makefile
==============================================================================
--- head/lib/libarchive/Makefile	Wed Dec 30 05:59:21 2009	(r201247)
+++ head/lib/libarchive/Makefile	Wed Dec 30 06:12:03 2009	(r201248)
@@ -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		\

Modified: head/lib/libarchive/archive.h
==============================================================================
--- head/lib/libarchive/archive.h	Wed Dec 30 05:59:21 2009	(r201247)
+++ head/lib/libarchive/archive.h	Wed Dec 30 06:12:03 2009	(r201248)
@@ -241,6 +241,7 @@ typedef int	archive_close_callback(struc
 #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_com
 				(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 *);

Modified: head/lib/libarchive/archive_read_support_compression_all.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_all.c	Wed Dec 30 05:59:21 2009	(r201247)
+++ head/lib/libarchive/archive_read_support_compression_all.c	Wed Dec 30 06:12:03 2009	(r201248)
@@ -44,6 +44,8 @@ archive_read_support_compression_all(str
 	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

Added: head/lib/libarchive/archive_read_support_compression_uu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/archive_read_support_compression_uu.c	Wed Dec 30 06:12:03 2009	(r201248)
@@ -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);
+}
+

Modified: head/lib/libarchive/test/Makefile
==============================================================================
--- head/lib/libarchive/test/Makefile	Wed Dec 30 05:59:21 2009	(r201247)
+++ head/lib/libarchive/test/Makefile	Wed Dec 30 06:12:03 2009	(r201248)
@@ -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			\

Added: head/lib/libarchive/test/test_read_uu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/test/test_read_uu.c	Wed Dec 30 06:12:03 2009	(r201248)
@@ -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 at libarchive Mon Jun  2 03:03:31 2008\n"
+"Return-Path: <uudecode at 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 at libarchive>; Mon, 2 Jun 2008 03:03:31 GMT\n"
+"        (envelope-from uudecode at libarchive)\n"
+"Received: (from uudecode at 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 at libarchive>\n"
+"Message-Id: <200806020303.m5233U3e006406 at libarchive>\n"
+"To: uudecode at 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);
+}
+


More information about the svn-src-head mailing list