1228753Smm/*- 2228753Smm * Copyright (c) 2009 Michihiro NAKAJIMA 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#ifdef HAVE_ERRNO_H 30228753Smm#include <errno.h> 31228753Smm#endif 32228753Smm#ifdef HAVE_STDLIB_H 33228753Smm#include <stdlib.h> 34228753Smm#endif 35228753Smm#ifdef HAVE_STRING_H 36228753Smm#include <string.h> 37228753Smm#endif 38228753Smm 39228753Smm#include "archive.h" 40228753Smm#include "archive_private.h" 41228753Smm#include "archive_read_private.h" 42228753Smm 43228753Smmstruct uudecode { 44228753Smm int64_t total; 45228753Smm unsigned char *in_buff; 46228753Smm#define IN_BUFF_SIZE (1024) 47228753Smm int in_cnt; 48228753Smm size_t in_allocated; 49228753Smm unsigned char *out_buff; 50228753Smm#define OUT_BUFF_SIZE (64 * 1024) 51228753Smm int state; 52228753Smm#define ST_FIND_HEAD 0 53228753Smm#define ST_READ_UU 1 54228753Smm#define ST_UUEND 2 55228753Smm#define ST_READ_BASE64 3 56228753Smm}; 57228753Smm 58228753Smmstatic int uudecode_bidder_bid(struct archive_read_filter_bidder *, 59228753Smm struct archive_read_filter *filter); 60228753Smmstatic int uudecode_bidder_init(struct archive_read_filter *); 61228753Smm 62228753Smmstatic ssize_t uudecode_filter_read(struct archive_read_filter *, 63228753Smm const void **); 64228753Smmstatic int uudecode_filter_close(struct archive_read_filter *); 65228753Smm 66228753Smmint 67228753Smmarchive_read_support_compression_uu(struct archive *_a) 68228753Smm{ 69228753Smm struct archive_read *a = (struct archive_read *)_a; 70228753Smm struct archive_read_filter_bidder *bidder; 71228753Smm 72228753Smm bidder = __archive_read_get_bidder(a); 73228753Smm archive_clear_error(_a); 74228753Smm if (bidder == NULL) 75228753Smm return (ARCHIVE_FATAL); 76228753Smm 77228753Smm bidder->data = NULL; 78228753Smm bidder->bid = uudecode_bidder_bid; 79228753Smm bidder->init = uudecode_bidder_init; 80228753Smm bidder->options = NULL; 81228753Smm bidder->free = NULL; 82228753Smm return (ARCHIVE_OK); 83228753Smm} 84228753Smm 85228753Smmstatic const unsigned char ascii[256] = { 86228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */ 87228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 88228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 89228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ 90228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 91228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ 92228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 93228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */ 94228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 95228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 96228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 97228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 98228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 99228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 100228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 101228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 102228753Smm}; 103228753Smm 104228753Smmstatic const unsigned char uuchar[256] = { 105228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 106228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 107228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 108228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ 109228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 110228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ 111228753Smm 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */ 112228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */ 113228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 114228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 115228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 116228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 117228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 118228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 119228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 120228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 121228753Smm}; 122228753Smm 123228753Smmstatic const unsigned char base64[256] = { 124228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 125228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 126228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */ 127228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */ 128228753Smm 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 129228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */ 130228753Smm 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 131228753Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */ 132228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 133228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 134228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 135228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 136228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 137228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 138228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 139228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 140228753Smm}; 141228753Smm 142228753Smmstatic const int base64num[128] = { 143228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 144228753Smm 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 145228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 146228753Smm 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 147228753Smm 0, 0, 0, 0, 0, 0, 0, 0, 148228753Smm 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */ 149228753Smm 52, 53, 54, 55, 56, 57, 58, 59, 150228753Smm 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */ 151228753Smm 0, 0, 1, 2, 3, 4, 5, 6, 152228753Smm 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */ 153228753Smm 15, 16, 17, 18, 19, 20, 21, 22, 154228753Smm 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */ 155228753Smm 0, 26, 27, 28, 29, 30, 31, 32, 156228753Smm 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */ 157228753Smm 41, 42, 43, 44, 45, 46, 47, 48, 158228753Smm 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */ 159228753Smm}; 160228753Smm 161228753Smmstatic ssize_t 162228753Smmget_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize) 163228753Smm{ 164228753Smm ssize_t len; 165228753Smm 166228753Smm len = 0; 167228753Smm while (len < avail) { 168228753Smm switch (ascii[*b]) { 169228753Smm case 0: /* Non-ascii character or control character. */ 170228753Smm if (nlsize != NULL) 171228753Smm *nlsize = 0; 172228753Smm return (-1); 173228753Smm case '\r': 174228753Smm if (avail-len > 1 && b[1] == '\n') { 175228753Smm if (nlsize != NULL) 176228753Smm *nlsize = 2; 177228753Smm return (len+2); 178228753Smm } 179228753Smm /* FALL THROUGH */ 180228753Smm case '\n': 181228753Smm if (nlsize != NULL) 182228753Smm *nlsize = 1; 183228753Smm return (len+1); 184228753Smm case 1: 185228753Smm b++; 186228753Smm len++; 187228753Smm break; 188228753Smm } 189228753Smm } 190228753Smm if (nlsize != NULL) 191228753Smm *nlsize = 0; 192228753Smm return (avail); 193228753Smm} 194228753Smm 195228753Smmstatic ssize_t 196228753Smmbid_get_line(struct archive_read_filter *filter, 197228753Smm const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl) 198228753Smm{ 199228753Smm ssize_t len; 200228753Smm int quit; 201228753Smm 202228753Smm quit = 0; 203228753Smm if (*avail == 0) { 204228753Smm *nl = 0; 205228753Smm len = 0; 206228753Smm } else 207228753Smm len = get_line(*b, *avail, nl); 208228753Smm /* 209228753Smm * Read bytes more while it does not reach the end of line. 210228753Smm */ 211228753Smm while (*nl == 0 && len == *avail && !quit) { 212228753Smm ssize_t diff = *ravail - *avail; 213228753Smm 214228753Smm *b = __archive_read_filter_ahead(filter, 160 + *ravail, avail); 215228753Smm if (*b == NULL) { 216228753Smm if (*ravail >= *avail) 217228753Smm return (0); 218228753Smm /* Reading bytes reaches the end of file. */ 219228753Smm *b = __archive_read_filter_ahead(filter, *avail, avail); 220228753Smm quit = 1; 221228753Smm } 222228753Smm *ravail = *avail; 223228753Smm *b += diff; 224228753Smm *avail -= diff; 225228753Smm len = get_line(*b, *avail, nl); 226228753Smm } 227228753Smm return (len); 228228753Smm} 229228753Smm 230228753Smm#define UUDECODE(c) (((c) - 0x20) & 0x3f) 231228753Smm 232228753Smmstatic int 233228753Smmuudecode_bidder_bid(struct archive_read_filter_bidder *self, 234228753Smm struct archive_read_filter *filter) 235228753Smm{ 236228753Smm const unsigned char *b; 237228753Smm ssize_t avail, ravail; 238228753Smm ssize_t len, nl; 239228753Smm int l; 240228753Smm int firstline; 241228753Smm 242228753Smm (void)self; /* UNUSED */ 243228753Smm 244228753Smm b = __archive_read_filter_ahead(filter, 1, &avail); 245228753Smm if (b == NULL) 246228753Smm return (0); 247228753Smm 248228753Smm firstline = 20; 249228753Smm ravail = avail; 250228753Smm for (;;) { 251228753Smm len = bid_get_line(filter, &b, &avail, &ravail, &nl); 252228753Smm if (len < 0 || nl == 0) 253228753Smm return (0);/* Binary data. */ 254228753Smm if (memcmp(b, "begin ", 6) == 0 && len - nl >= 11) 255228753Smm l = 6; 256228753Smm else if (memcmp(b, "begin-base64 ", 13) == 0 && len - nl >= 18) 257228753Smm l = 13; 258228753Smm else 259228753Smm l = 0; 260228753Smm 261228753Smm if (l > 0 && (b[l] < '0' || b[l] > '7' || 262228753Smm b[l+1] < '0' || b[l+1] > '7' || 263228753Smm b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' ')) 264228753Smm l = 0; 265228753Smm 266228753Smm b += len; 267228753Smm avail -= len; 268228753Smm if (l) 269228753Smm break; 270228753Smm firstline = 0; 271228753Smm } 272228753Smm if (!avail) 273228753Smm return (0); 274228753Smm len = bid_get_line(filter, &b, &avail, &ravail, &nl); 275228753Smm if (len < 0 || nl == 0) 276228753Smm return (0);/* There are non-ascii characters. */ 277228753Smm avail -= len; 278228753Smm 279228753Smm if (l == 6) { 280228753Smm if (!uuchar[*b]) 281228753Smm return (0); 282228753Smm /* Get a length of decoded bytes. */ 283228753Smm l = UUDECODE(*b++); len--; 284228753Smm if (l > 45) 285228753Smm /* Normally, maximum length is 45(character 'M'). */ 286228753Smm return (0); 287228753Smm while (l && len-nl > 0) { 288228753Smm if (l > 0) { 289228753Smm if (!uuchar[*b++]) 290228753Smm return (0); 291228753Smm if (!uuchar[*b++]) 292228753Smm return (0); 293228753Smm len -= 2; 294228753Smm --l; 295228753Smm } 296228753Smm if (l > 0) { 297228753Smm if (!uuchar[*b++]) 298228753Smm return (0); 299228753Smm --len; 300228753Smm --l; 301228753Smm } 302228753Smm if (l > 0) { 303228753Smm if (!uuchar[*b++]) 304228753Smm return (0); 305228753Smm --len; 306228753Smm --l; 307228753Smm } 308228753Smm } 309228753Smm if (len-nl < 0) 310228753Smm return (0); 311228753Smm if (len-nl == 1 && 312228753Smm (uuchar[*b] || /* Check sum. */ 313228753Smm (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */ 314228753Smm ++b; 315228753Smm --len; 316228753Smm } 317228753Smm b += nl; 318228753Smm if (avail && uuchar[*b]) 319228753Smm return (firstline+30); 320228753Smm } 321228753Smm if (l == 13) { 322228753Smm while (len-nl > 0) { 323228753Smm if (!base64[*b++]) 324228753Smm return (0); 325228753Smm --len; 326228753Smm } 327228753Smm b += nl; 328228753Smm 329228753Smm if (avail >= 5 && memcmp(b, "====\n", 5) == 0) 330228753Smm return (firstline+40); 331228753Smm if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0) 332228753Smm return (firstline+40); 333228753Smm if (avail > 0 && base64[*b]) 334228753Smm return (firstline+30); 335228753Smm } 336228753Smm 337228753Smm return (0); 338228753Smm} 339228753Smm 340228753Smmstatic int 341228753Smmuudecode_bidder_init(struct archive_read_filter *self) 342228753Smm{ 343228753Smm struct uudecode *uudecode; 344228753Smm void *out_buff; 345228753Smm void *in_buff; 346228753Smm 347228753Smm self->code = ARCHIVE_COMPRESSION_UU; 348228753Smm self->name = "uu"; 349228753Smm self->read = uudecode_filter_read; 350228753Smm self->skip = NULL; /* not supported */ 351228753Smm self->close = uudecode_filter_close; 352228753Smm 353228753Smm uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1); 354228753Smm out_buff = malloc(OUT_BUFF_SIZE); 355228753Smm in_buff = malloc(IN_BUFF_SIZE); 356228753Smm if (uudecode == NULL || out_buff == NULL || in_buff == NULL) { 357228753Smm archive_set_error(&self->archive->archive, ENOMEM, 358228753Smm "Can't allocate data for uudecode"); 359228753Smm free(uudecode); 360228753Smm free(out_buff); 361228753Smm free(in_buff); 362228753Smm return (ARCHIVE_FATAL); 363228753Smm } 364228753Smm 365228753Smm self->data = uudecode; 366228753Smm uudecode->in_buff = in_buff; 367228753Smm uudecode->in_cnt = 0; 368228753Smm uudecode->in_allocated = IN_BUFF_SIZE; 369228753Smm uudecode->out_buff = out_buff; 370228753Smm uudecode->state = ST_FIND_HEAD; 371228753Smm 372228753Smm return (ARCHIVE_OK); 373228753Smm} 374228753Smm 375228753Smmstatic int 376228753Smmensure_in_buff_size(struct archive_read_filter *self, 377228753Smm struct uudecode *uudecode, size_t size) 378228753Smm{ 379228753Smm 380228753Smm if (size > uudecode->in_allocated) { 381228753Smm unsigned char *ptr; 382228753Smm size_t newsize; 383228753Smm 384228753Smm /* 385228753Smm * Calculate a new buffer size for in_buff. 386228753Smm * Increase its value until it has enough size we need. 387228753Smm */ 388228753Smm newsize = uudecode->in_allocated; 389228753Smm do { 390228753Smm if (newsize < IN_BUFF_SIZE*32) 391228753Smm newsize <<= 1; 392228753Smm else 393228753Smm newsize += IN_BUFF_SIZE; 394228753Smm } while (size > newsize); 395228753Smm ptr = malloc(newsize); 396228753Smm if (ptr == NULL || 397228753Smm newsize < uudecode->in_allocated) { 398228753Smm free(ptr); 399228753Smm archive_set_error(&self->archive->archive, 400228753Smm ENOMEM, 401228753Smm "Can't allocate data for uudecode"); 402228753Smm return (ARCHIVE_FATAL); 403228753Smm } 404228753Smm if (uudecode->in_cnt) 405228753Smm memmove(ptr, uudecode->in_buff, 406228753Smm uudecode->in_cnt); 407228753Smm free(uudecode->in_buff); 408228753Smm uudecode->in_buff = ptr; 409228753Smm uudecode->in_allocated = newsize; 410228753Smm } 411228753Smm return (ARCHIVE_OK); 412228753Smm} 413228753Smm 414228753Smmstatic ssize_t 415228753Smmuudecode_filter_read(struct archive_read_filter *self, const void **buff) 416228753Smm{ 417228753Smm struct uudecode *uudecode; 418228753Smm const unsigned char *b, *d; 419228753Smm unsigned char *out; 420228753Smm ssize_t avail_in, ravail; 421228753Smm ssize_t used; 422228753Smm ssize_t total; 423228753Smm ssize_t len, llen, nl; 424228753Smm 425228753Smm uudecode = (struct uudecode *)self->data; 426228753Smm 427228753Smmread_more: 428228753Smm d = __archive_read_filter_ahead(self->upstream, 1, &avail_in); 429228753Smm if (d == NULL && avail_in < 0) 430228753Smm return (ARCHIVE_FATAL); 431228753Smm /* Quiet a code analyzer; make sure avail_in must be zero 432228753Smm * when d is NULL. */ 433228753Smm if (d == NULL) 434228753Smm avail_in = 0; 435228753Smm used = 0; 436228753Smm total = 0; 437228753Smm out = uudecode->out_buff; 438228753Smm ravail = avail_in; 439228753Smm if (uudecode->in_cnt) { 440228753Smm /* 441228753Smm * If there is remaining data which is saved by 442228753Smm * previous calling, use it first. 443228753Smm */ 444228753Smm if (ensure_in_buff_size(self, uudecode, 445228753Smm avail_in + uudecode->in_cnt) != ARCHIVE_OK) 446228753Smm return (ARCHIVE_FATAL); 447228753Smm memcpy(uudecode->in_buff + uudecode->in_cnt, 448228753Smm d, avail_in); 449228753Smm d = uudecode->in_buff; 450228753Smm avail_in += uudecode->in_cnt; 451228753Smm uudecode->in_cnt = 0; 452228753Smm } 453228753Smm for (;used < avail_in; d += llen, used += llen) { 454228753Smm int l, body; 455228753Smm 456228753Smm b = d; 457228753Smm len = get_line(b, avail_in - used, &nl); 458228753Smm if (len < 0) { 459228753Smm /* Non-ascii character is found. */ 460228753Smm archive_set_error(&self->archive->archive, 461228753Smm ARCHIVE_ERRNO_MISC, 462228753Smm "Insufficient compressed data"); 463228753Smm return (ARCHIVE_FATAL); 464228753Smm } 465228753Smm llen = len; 466228753Smm if (nl == 0) { 467228753Smm /* 468228753Smm * Save remaining data which does not contain 469228753Smm * NL('\n','\r'). 470228753Smm */ 471228753Smm if (ensure_in_buff_size(self, uudecode, len) 472228753Smm != ARCHIVE_OK) 473228753Smm return (ARCHIVE_FATAL); 474228753Smm if (uudecode->in_buff != b) 475228753Smm memmove(uudecode->in_buff, b, len); 476228753Smm uudecode->in_cnt = len; 477228753Smm if (total == 0) { 478228753Smm /* Do not return 0; it means end-of-file. 479228753Smm * We should try to read bytes more. */ 480228753Smm __archive_read_filter_consume( 481228753Smm self->upstream, ravail); 482228753Smm goto read_more; 483228753Smm } 484228753Smm break; 485228753Smm } 486228753Smm if (total + len * 2 > OUT_BUFF_SIZE) 487228753Smm break; 488228753Smm switch (uudecode->state) { 489228753Smm default: 490228753Smm case ST_FIND_HEAD: 491228753Smm if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) 492228753Smm l = 6; 493228753Smm else if (len - nl >= 18 && 494228753Smm memcmp(b, "begin-base64 ", 13) == 0) 495228753Smm l = 13; 496228753Smm else 497228753Smm l = 0; 498228753Smm if (l != 0 && b[l] >= '0' && b[l] <= '7' && 499228753Smm b[l+1] >= '0' && b[l+1] <= '7' && 500228753Smm b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { 501228753Smm if (l == 6) 502228753Smm uudecode->state = ST_READ_UU; 503228753Smm else 504228753Smm uudecode->state = ST_READ_BASE64; 505228753Smm } 506228753Smm break; 507228753Smm case ST_READ_UU: 508228753Smm body = len - nl; 509228753Smm if (!uuchar[*b] || body <= 0) { 510228753Smm archive_set_error(&self->archive->archive, 511228753Smm ARCHIVE_ERRNO_MISC, 512228753Smm "Insufficient compressed data"); 513228753Smm return (ARCHIVE_FATAL); 514228753Smm } 515228753Smm /* Get length of undecoded bytes of curent line. */ 516228753Smm l = UUDECODE(*b++); 517228753Smm body--; 518228753Smm if (l > body) { 519228753Smm archive_set_error(&self->archive->archive, 520228753Smm ARCHIVE_ERRNO_MISC, 521228753Smm "Insufficient compressed data"); 522228753Smm return (ARCHIVE_FATAL); 523228753Smm } 524228753Smm if (l == 0) { 525228753Smm uudecode->state = ST_UUEND; 526228753Smm break; 527228753Smm } 528228753Smm while (l > 0) { 529228753Smm int n = 0; 530228753Smm 531228753Smm if (l > 0) { 532228753Smm if (!uuchar[b[0]] || !uuchar[b[1]]) 533228753Smm break; 534228753Smm n = UUDECODE(*b++) << 18; 535228753Smm n |= UUDECODE(*b++) << 12; 536228753Smm *out++ = n >> 16; total++; 537228753Smm --l; 538228753Smm } 539228753Smm if (l > 0) { 540228753Smm if (!uuchar[b[0]]) 541228753Smm break; 542228753Smm n |= UUDECODE(*b++) << 6; 543228753Smm *out++ = (n >> 8) & 0xFF; total++; 544228753Smm --l; 545228753Smm } 546228753Smm if (l > 0) { 547228753Smm if (!uuchar[b[0]]) 548228753Smm break; 549228753Smm n |= UUDECODE(*b++); 550228753Smm *out++ = n & 0xFF; total++; 551228753Smm --l; 552228753Smm } 553228753Smm } 554228753Smm if (l) { 555228753Smm archive_set_error(&self->archive->archive, 556228753Smm ARCHIVE_ERRNO_MISC, 557228753Smm "Insufficient compressed data"); 558228753Smm return (ARCHIVE_FATAL); 559228753Smm } 560228753Smm break; 561228753Smm case ST_UUEND: 562228753Smm if (len - nl == 3 && memcmp(b, "end ", 3) == 0) 563228753Smm uudecode->state = ST_FIND_HEAD; 564228753Smm else { 565228753Smm archive_set_error(&self->archive->archive, 566228753Smm ARCHIVE_ERRNO_MISC, 567228753Smm "Insufficient compressed data"); 568228753Smm return (ARCHIVE_FATAL); 569228753Smm } 570228753Smm break; 571228753Smm case ST_READ_BASE64: 572228753Smm l = len - nl; 573228753Smm if (l >= 3 && b[0] == '=' && b[1] == '=' && 574228753Smm b[2] == '=') { 575228753Smm uudecode->state = ST_FIND_HEAD; 576228753Smm break; 577228753Smm } 578228753Smm while (l > 0) { 579228753Smm int n = 0; 580228753Smm 581228753Smm if (l > 0) { 582228753Smm if (!base64[b[0]] || !base64[b[1]]) 583228753Smm break; 584228753Smm n = base64num[*b++] << 18; 585228753Smm n |= base64num[*b++] << 12; 586228753Smm *out++ = n >> 16; total++; 587228753Smm l -= 2; 588228753Smm } 589228753Smm if (l > 0) { 590228753Smm if (*b == '=') 591228753Smm break; 592228753Smm if (!base64[*b]) 593228753Smm break; 594228753Smm n |= base64num[*b++] << 6; 595228753Smm *out++ = (n >> 8) & 0xFF; total++; 596228753Smm --l; 597228753Smm } 598228753Smm if (l > 0) { 599228753Smm if (*b == '=') 600228753Smm break; 601228753Smm if (!base64[*b]) 602228753Smm break; 603228753Smm n |= base64num[*b++]; 604228753Smm *out++ = n & 0xFF; total++; 605228753Smm --l; 606228753Smm } 607228753Smm } 608228753Smm if (l && *b != '=') { 609228753Smm archive_set_error(&self->archive->archive, 610228753Smm ARCHIVE_ERRNO_MISC, 611228753Smm "Insufficient compressed data"); 612228753Smm return (ARCHIVE_FATAL); 613228753Smm } 614228753Smm break; 615228753Smm } 616228753Smm } 617228753Smm 618228753Smm __archive_read_filter_consume(self->upstream, ravail); 619228753Smm 620228753Smm *buff = uudecode->out_buff; 621228753Smm uudecode->total += total; 622228753Smm return (total); 623228753Smm} 624228753Smm 625228753Smmstatic int 626228753Smmuudecode_filter_close(struct archive_read_filter *self) 627228753Smm{ 628228753Smm struct uudecode *uudecode; 629228753Smm 630228753Smm uudecode = (struct uudecode *)self->data; 631228753Smm free(uudecode->in_buff); 632228753Smm free(uudecode->out_buff); 633228753Smm free(uudecode); 634228753Smm 635228753Smm return (ARCHIVE_OK); 636228753Smm} 637228753Smm 638