| /*- |
| * 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: head/lib/libarchive/archive_read_support_compression_uu.c 201248 2009-12-30 06:12:03Z kientzle $"); |
| |
| #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); |
| } |
| |