]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add uudecode filter.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Tue, 20 Oct 2009 06:16:28 +0000 (02:16 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Tue, 20 Oct 2009 06:16:28 +0000 (02:16 -0400)
SVN-Revision: 1542

Makefile.am
libarchive/CMakeLists.txt
libarchive/archive.h
libarchive/archive_read_support_compression_all.c
libarchive/archive_read_support_compression_uu.c [new file with mode: 0644]
libarchive/test/CMakeLists.txt
libarchive/test/test_read_uu.c [new file with mode: 0644]

index e1e18f63fbcbf0123d6cb90fbe956ab37f9bc74f..bfde942d51f1e82f5692cbdf388a6dc3f398b25f 100644 (file)
@@ -123,6 +123,7 @@ libarchive_la_SOURCES=                                              \
        libarchive/archive_read_support_compression_gzip.c      \
        libarchive/archive_read_support_compression_none.c      \
        libarchive/archive_read_support_compression_program.c   \
+       libarchive/archive_read_support_compression_uu.c        \
        libarchive/archive_read_support_compression_xz.c        \
        libarchive/archive_read_support_format_all.c            \
        libarchive/archive_read_support_format_ar.c             \
@@ -280,6 +281,7 @@ libarchive_test_SOURCES=                                    \
        libarchive/test/test_read_pax_truncated.c               \
        libarchive/test/test_read_position.c                    \
        libarchive/test/test_read_truncated.c                   \
+       libarchive/test/test_read_uu.c                          \
        libarchive/test/test_tar_filenames.c                    \
        libarchive/test/test_tar_large.c                        \
        libarchive/test/test_ustar_filenames.c                  \
index 60fbeec46ce153af72405ab17c18e6c82a7929a4..d7c81845025316f104fe350d6d2ca54b0cd4e717 100644 (file)
@@ -44,6 +44,7 @@ SET(libarchive_SOURCES
   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
index 6e1ae99259f0b13e5e991b61fedfeb643f50a67f..ce6edbb3f5693eae2a1a1aca64d80531c950011d 100644 (file)
@@ -232,6 +232,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.
@@ -307,6 +308,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 *);
index dcd6a31ca9a8b498c32a73284b91bb6c683b5d0c..f4708ca8102a39a7941b279de1444d0e2dbf8bc5 100644 (file)
@@ -44,6 +44,8 @@ archive_read_support_compression_all(struct archive *a)
        archive_read_support_compression_lzma(a);
        /* Xz falls back to "unxz" command-line program. */
        archive_read_support_compression_xz(a);
+       /* The decode code doesn't use an outside library. */
+       archive_read_support_compression_uu(a);
 
        /* Note: We always return ARCHIVE_OK here, even if some of the
         * above return ARCHIVE_WARN.  The intent here is to enable
diff --git a/libarchive/archive_read_support_compression_uu.c b/libarchive/archive_read_support_compression_uu.c
new file mode 100644 (file)
index 0000000..d88113f
--- /dev/null
@@ -0,0 +1,578 @@
+/*-
+ * 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"
+
+#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);
+}
+
+#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;
+       ssize_t len, nl;
+       int l;
+       int firstline;
+
+       (void)self; /* UNUSED */
+
+       b = __archive_read_filter_ahead(filter, 1, &avail);
+       if (b == NULL)
+               return (0);
+
+       l = 0;
+       firstline = 20;
+       while (avail) {
+               if (memcmp(b, "begin ", 6) == 0 && avail > 11)
+                       l = 6;
+               else if (memcmp(b, "begin-base64 ", 13) == 0 && avail > 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;
+
+               len = get_line(b, avail, &nl);
+               if (len < 0 || nl == 0)
+                       return (0);/* Binary data. */
+               b += len;
+               avail -= len;
+               if (l)
+                       break;
+               firstline = 0;
+       }
+       if (!avail)
+               return (0);
+       len = get_line(b, avail, &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;
+       ssize_t used;
+       ssize_t total;
+       ssize_t len, llen, nl;
+
+       uudecode = (struct uudecode *)self->data;
+
+       d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+       if (d == NULL && avail_in < 0)
+               return (ARCHIVE_FATAL);
+       used = 0;
+       total = 0;
+       out = uudecode->out_buff;
+       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);
+                       memcpy(uudecode->in_buff, b, len);
+                       uudecode->in_cnt = len;
+                       used += len;
+                       break;
+               }
+               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,
+                           len + uudecode->in_cnt) != ARCHIVE_OK)
+                               return (ARCHIVE_FATAL);
+                       memcpy(uudecode->in_buff + uudecode->in_cnt,
+                           b, len);
+                       b = uudecode->in_buff;
+                       len += uudecode->in_cnt;
+                       uudecode->in_cnt = 0;
+               }
+               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, used);
+
+       *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);
+}
+
index 4b585f6fdd29d79e60ffe240c1f2f9f0743f7e81..bc6eff6f550ae2bd0bd904834f4ff2abbf5f6d4c 100644 (file)
@@ -79,6 +79,7 @@ IF(ENABLE_TEST)
     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
diff --git a/libarchive/test/test_read_uu.c b/libarchive/test/test_read_uu.c
new file mode 100644 (file)
index 0000000..45b3bd7
--- /dev/null
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * 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"
+
+static unsigned char archive[] = {
+0x62,0x65,0x67,0x69,0x6e,0x20,0x36,0x34,
+0x34,0x20,0x74,0x65,0x73,0x74,0x5f,0x72,
+0x65,0x61,0x64,0x5f,0x75,0x75,0x2e,0x5a,
+0x0a,0x4d,0x27,0x59,0x56,0x30,0x2b,0x40,
+0x60,0x28,0x27,0x24,0x42,0x50,0x48,0x2c,
+0x26,0x23,0x22,0x21,0x2c,0x4a,0x37,0x2c,
+0x42,0x50,0x28,0x34,0x28,0x38,0x24,0x26,
+0x5f,0x34,0x4a,0x60,0x24,0x22,0x60,0x2c,
+0x30,0x38,0x24,0x46,0x25,0x34,0x4f,0x29,
+0x41,0x51,0x28,0x5c,0x32,0x2f,0x28,0x23,
+0x37,0x26,0x40,0x23,0x25,0x43,0x0a,0x4d,
+0x21,0x40,0x54,0x38,0x2d,0x23,0x23,0x2e,
+0x4c,0x60,0x24,0x22,0x51,0x4c,0x40,0x3a,
+0x2d,0x46,0x28,0x60,0x60,0x25,0x27,0x23,
+0x48,0x3c,0x56,0x3b,0x2e,0x27,0x2f,0x4a,
+0x21,0x25,0x21,0x47,0x23,0x49,0x54,0x50,
+0x3c,0x42,0x53,0x22,0x48,0x29,0x2e,0x46,
+0x53,0x3c,0x5a,0x24,0x31,0x28,0x54,0x3e,
+0x2f,0x31,0x41,0x32,0x0a,0x49,0x48,0x55,
+0x22,0x30,0x25,0x39,0x3d,0x2a,0x47,0x34,
+0x4a,0x55,0x4a,0x4d,0x36,0x4b,0x36,0x2b,
+0x2d,0x4a,0x57,0x3c,0x4a,0x55,0x4a,0x5d,
+0x3e,0x4f,0x38,0x2c,0x2e,0x2a,0x27,0x34,
+0x4e,0x56,0x4b,0x2d,0x46,0x53,0x3a,0x2d,
+0x2e,0x4a,0x37,0x3c,0x4e,0x56,0x4b,0x3d,
+0x4e,0x57,0x39,0x50,0x24,0x60,0x0a,0x60,
+0x0a,0x65,0x6e,0x64,0x0a
+};
+
+DEFINE_TEST(test_read_uu)
+{
+       struct archive_entry *ae;
+       struct archive *a;
+       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,
+           archive_read_open_memory(a, archive, sizeof(archive)));
+       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));
+#if ARCHIVE_VERSION_NUMBER < 2000000
+       archive_read_finish(a);
+#else
+       assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+#endif
+}
+
+