1/*- 2 * Copyright (c) 2009-2011 Michihiro NAKAJIMA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "archive_platform.h" 27 28#ifdef HAVE_ERRNO_H 29#include <errno.h> 30#endif 31#ifdef HAVE_STDLIB_H 32#include <stdlib.h> 33#endif 34#ifdef HAVE_STRING_H 35#include <string.h> 36#endif 37 38#include "archive.h" 39#include "archive_entry.h" 40#include "archive_private.h" 41#include "archive_read_private.h" 42 43/* Maximum lookahead during bid phase */ 44#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */ 45 46struct uudecode { 47 int64_t total; 48 unsigned char *in_buff; 49#define IN_BUFF_SIZE (1024) 50 int in_cnt; 51 size_t in_allocated; 52 unsigned char *out_buff; 53#define OUT_BUFF_SIZE (64 * 1024) 54 int state; 55#define ST_FIND_HEAD 0 56#define ST_READ_UU 1 57#define ST_UUEND 2 58#define ST_READ_BASE64 3 59#define ST_IGNORE 4 60 mode_t mode; 61 int mode_set; 62 char *name; 63}; 64 65static int uudecode_bidder_bid(struct archive_read_filter_bidder *, 66 struct archive_read_filter *filter); 67static int uudecode_bidder_init(struct archive_read_filter *); 68 69static int uudecode_read_header(struct archive_read_filter *, 70 struct archive_entry *entry); 71static ssize_t uudecode_filter_read(struct archive_read_filter *, 72 const void **); 73static int uudecode_filter_close(struct archive_read_filter *); 74 75#if ARCHIVE_VERSION_NUMBER < 4000000 76/* Deprecated; remove in libarchive 4.0 */ 77int 78archive_read_support_compression_uu(struct archive *a) 79{ 80 return archive_read_support_filter_uu(a); 81} 82#endif 83 84static const struct archive_read_filter_bidder_vtable 85uudecode_bidder_vtable = { 86 .bid = uudecode_bidder_bid, 87 .init = uudecode_bidder_init, 88}; 89 90int 91archive_read_support_filter_uu(struct archive *_a) 92{ 93 struct archive_read *a = (struct archive_read *)_a; 94 95 return __archive_read_register_bidder(a, NULL, "uu", 96 &uudecode_bidder_vtable); 97} 98 99static const unsigned char ascii[256] = { 100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */ 101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ 104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 105 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ 106 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 107 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */ 108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 116}; 117 118static const unsigned char uuchar[256] = { 119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 121 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 122 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ 123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ 125 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */ 126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */ 127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 135}; 136 137static const unsigned char base64[256] = { 138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */ 141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */ 142 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */ 144 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 145 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */ 146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 154}; 155 156static const int base64num[128] = { 157 0, 0, 0, 0, 0, 0, 0, 0, 158 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 159 0, 0, 0, 0, 0, 0, 0, 0, 160 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 161 0, 0, 0, 0, 0, 0, 0, 0, 162 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */ 163 52, 53, 54, 55, 56, 57, 58, 59, 164 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */ 165 0, 0, 1, 2, 3, 4, 5, 6, 166 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */ 167 15, 16, 17, 18, 19, 20, 21, 22, 168 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */ 169 0, 26, 27, 28, 29, 30, 31, 32, 170 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */ 171 41, 42, 43, 44, 45, 46, 47, 48, 172 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */ 173}; 174 175static ssize_t 176get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize) 177{ 178 ssize_t len; 179 180 len = 0; 181 while (len < avail) { 182 switch (ascii[*b]) { 183 case 0: /* Non-ascii character or control character. */ 184 if (nlsize != NULL) 185 *nlsize = 0; 186 return (-1); 187 case '\r': 188 if (avail-len > 1 && b[1] == '\n') { 189 if (nlsize != NULL) 190 *nlsize = 2; 191 return (len+2); 192 } 193 /* FALL THROUGH */ 194 case '\n': 195 if (nlsize != NULL) 196 *nlsize = 1; 197 return (len+1); 198 case 1: 199 b++; 200 len++; 201 break; 202 } 203 } 204 if (nlsize != NULL) 205 *nlsize = 0; 206 return (avail); 207} 208 209static ssize_t 210bid_get_line(struct archive_read_filter *filter, 211 const unsigned char **b, ssize_t *avail, ssize_t *ravail, 212 ssize_t *nl, size_t* nbytes_read) 213{ 214 ssize_t len; 215 int quit; 216 217 quit = 0; 218 if (*avail == 0) { 219 *nl = 0; 220 len = 0; 221 } else 222 len = get_line(*b, *avail, nl); 223 224 /* 225 * Read bytes more while it does not reach the end of line. 226 */ 227 while (*nl == 0 && len == *avail && !quit && 228 *nbytes_read < UUENCODE_BID_MAX_READ) { 229 ssize_t diff = *ravail - *avail; 230 size_t nbytes_req = (*ravail+1023) & ~1023U; 231 ssize_t tested; 232 233 /* Increase reading bytes if it is not enough to at least 234 * new two lines. */ 235 if (nbytes_req < (size_t)*ravail + 160) 236 nbytes_req <<= 1; 237 238 *b = __archive_read_filter_ahead(filter, nbytes_req, avail); 239 if (*b == NULL) { 240 if (*ravail >= *avail) 241 return (0); 242 /* Reading bytes reaches the end of a stream. */ 243 *b = __archive_read_filter_ahead(filter, *avail, avail); 244 quit = 1; 245 } 246 *nbytes_read = *avail; 247 *ravail = *avail; 248 *b += diff; 249 *avail -= diff; 250 tested = len;/* Skip some bytes we already determined. */ 251 len = get_line(*b + tested, *avail - tested, nl); 252 if (len >= 0) 253 len += tested; 254 } 255 return (len); 256} 257 258#define UUDECODE(c) (((c) - 0x20) & 0x3f) 259 260static int 261uudecode_bidder_bid(struct archive_read_filter_bidder *self, 262 struct archive_read_filter *filter) 263{ 264 const unsigned char *b; 265 ssize_t avail, ravail; 266 ssize_t len, nl; 267 int l; 268 int firstline; 269 size_t nbytes_read; 270 271 (void)self; /* UNUSED */ 272 273 b = __archive_read_filter_ahead(filter, 1, &avail); 274 if (b == NULL) 275 return (0); 276 277 firstline = 20; 278 ravail = avail; 279 nbytes_read = avail; 280 for (;;) { 281 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read); 282 if (len < 0 || nl == 0) 283 return (0); /* No match found. */ 284 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) 285 l = 6; 286 else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0) 287 l = 13; 288 else 289 l = 0; 290 291 if (l > 0 && (b[l] < '0' || b[l] > '7' || 292 b[l+1] < '0' || b[l+1] > '7' || 293 b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' ')) 294 l = 0; 295 296 b += len; 297 avail -= len; 298 if (l) 299 break; 300 firstline = 0; 301 302 /* Do not read more than UUENCODE_BID_MAX_READ bytes */ 303 if (nbytes_read >= UUENCODE_BID_MAX_READ) 304 return (0); 305 } 306 if (!avail) 307 return (0); 308 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read); 309 if (len < 0 || nl == 0) 310 return (0);/* There are non-ascii characters. */ 311 avail -= len; 312 313 if (l == 6) { 314 /* "begin " */ 315 if (!uuchar[*b]) 316 return (0); 317 /* Get a length of decoded bytes. */ 318 l = UUDECODE(*b++); len--; 319 if (l > 45) 320 /* Normally, maximum length is 45(character 'M'). */ 321 return (0); 322 if (l > len - nl) 323 return (0); /* Line too short. */ 324 while (l) { 325 if (!uuchar[*b++]) 326 return (0); 327 --len; 328 --l; 329 } 330 if (len-nl == 1 && 331 (uuchar[*b] || /* Check sum. */ 332 (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */ 333 ++b; 334 --len; 335 } 336 b += nl; 337 if (avail && uuchar[*b]) 338 return (firstline+30); 339 } else if (l == 13) { 340 /* "begin-base64 " */ 341 while (len-nl > 0) { 342 if (!base64[*b++]) 343 return (0); 344 --len; 345 } 346 b += nl; 347 348 if (avail >= 5 && memcmp(b, "====\n", 5) == 0) 349 return (firstline+40); 350 if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0) 351 return (firstline+40); 352 if (avail > 0 && base64[*b]) 353 return (firstline+30); 354 } 355 356 return (0); 357} 358 359static const struct archive_read_filter_vtable 360uudecode_reader_vtable = { 361 .read = uudecode_filter_read, 362 .close = uudecode_filter_close, 363 .read_header = uudecode_read_header 364}; 365 366static int 367uudecode_bidder_init(struct archive_read_filter *self) 368{ 369 struct uudecode *uudecode; 370 void *out_buff; 371 void *in_buff; 372 373 self->code = ARCHIVE_FILTER_UU; 374 self->name = "uu"; 375 376 uudecode = (struct uudecode *)calloc(1, sizeof(*uudecode)); 377 out_buff = malloc(OUT_BUFF_SIZE); 378 in_buff = malloc(IN_BUFF_SIZE); 379 if (uudecode == NULL || out_buff == NULL || in_buff == NULL) { 380 archive_set_error(&self->archive->archive, ENOMEM, 381 "Can't allocate data for uudecode"); 382 free(uudecode); 383 free(out_buff); 384 free(in_buff); 385 return (ARCHIVE_FATAL); 386 } 387 388 self->data = uudecode; 389 uudecode->in_buff = in_buff; 390 uudecode->in_cnt = 0; 391 uudecode->in_allocated = IN_BUFF_SIZE; 392 uudecode->out_buff = out_buff; 393 uudecode->state = ST_FIND_HEAD; 394 uudecode->mode_set = 0; 395 uudecode->name = NULL; 396 self->vtable = &uudecode_reader_vtable; 397 398 return (ARCHIVE_OK); 399} 400 401static int 402ensure_in_buff_size(struct archive_read_filter *self, 403 struct uudecode *uudecode, size_t size) 404{ 405 406 if (size > uudecode->in_allocated) { 407 unsigned char *ptr; 408 size_t newsize; 409 410 /* 411 * Calculate a new buffer size for in_buff. 412 * Increase its value until it has enough size we need. 413 */ 414 newsize = uudecode->in_allocated; 415 do { 416 if (newsize < IN_BUFF_SIZE*32) 417 newsize <<= 1; 418 else 419 newsize += IN_BUFF_SIZE; 420 } while (size > newsize); 421 /* Allocate the new buffer. */ 422 ptr = malloc(newsize); 423 if (ptr == NULL) { 424 free(ptr); 425 archive_set_error(&self->archive->archive, 426 ENOMEM, 427 "Can't allocate data for uudecode"); 428 return (ARCHIVE_FATAL); 429 } 430 /* Move the remaining data in in_buff into the new buffer. */ 431 if (uudecode->in_cnt) 432 memmove(ptr, uudecode->in_buff, uudecode->in_cnt); 433 /* Replace in_buff with the new buffer. */ 434 free(uudecode->in_buff); 435 uudecode->in_buff = ptr; 436 uudecode->in_allocated = newsize; 437 } 438 return (ARCHIVE_OK); 439} 440 441static int 442uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry) 443{ 444 445 struct uudecode *uudecode; 446 uudecode = (struct uudecode *)self->data; 447 448 if (uudecode->mode_set != 0) 449 archive_entry_set_mode(entry, S_IFREG | uudecode->mode); 450 451 if (uudecode->name != NULL) 452 archive_entry_set_pathname(entry, uudecode->name); 453 454 return (ARCHIVE_OK); 455} 456 457static ssize_t 458uudecode_filter_read(struct archive_read_filter *self, const void **buff) 459{ 460 struct uudecode *uudecode; 461 const unsigned char *b, *d; 462 unsigned char *out; 463 ssize_t avail_in, ravail; 464 ssize_t used; 465 ssize_t total; 466 ssize_t len, llen, nl, namelen; 467 468 uudecode = (struct uudecode *)self->data; 469 470read_more: 471 d = __archive_read_filter_ahead(self->upstream, 1, &avail_in); 472 if (d == NULL && avail_in < 0) 473 return (ARCHIVE_FATAL); 474 /* Quiet a code analyzer; make sure avail_in must be zero 475 * when d is NULL. */ 476 if (d == NULL) 477 avail_in = 0; 478 used = 0; 479 total = 0; 480 out = uudecode->out_buff; 481 ravail = avail_in; 482 if (uudecode->state == ST_IGNORE) { 483 used = avail_in; 484 goto finish; 485 } 486 if (uudecode->in_cnt) { 487 /* 488 * If there is remaining data which is saved by 489 * previous calling, use it first. 490 */ 491 if (ensure_in_buff_size(self, uudecode, 492 avail_in + uudecode->in_cnt) != ARCHIVE_OK) 493 return (ARCHIVE_FATAL); 494 memcpy(uudecode->in_buff + uudecode->in_cnt, 495 d, avail_in); 496 d = uudecode->in_buff; 497 avail_in += uudecode->in_cnt; 498 uudecode->in_cnt = 0; 499 } 500 for (;used < avail_in; d += llen, used += llen) { 501 int64_t l, body; 502 503 b = d; 504 len = get_line(b, avail_in - used, &nl); 505 if (len < 0) { 506 /* Non-ascii character is found. */ 507 if (uudecode->state == ST_FIND_HEAD && 508 (uudecode->total > 0 || total > 0)) { 509 uudecode->state = ST_IGNORE; 510 used = avail_in; 511 goto finish; 512 } 513 archive_set_error(&self->archive->archive, 514 ARCHIVE_ERRNO_MISC, 515 "Insufficient compressed data"); 516 return (ARCHIVE_FATAL); 517 } 518 llen = len; 519 if ((nl == 0) && (uudecode->state != ST_UUEND)) { 520 if (total == 0 && ravail <= 0) { 521 /* There is nothing more to read, fail */ 522 archive_set_error(&self->archive->archive, 523 ARCHIVE_ERRNO_FILE_FORMAT, 524 "Missing format data"); 525 return (ARCHIVE_FATAL); 526 } 527 /* 528 * Save remaining data which does not contain 529 * NL('\n','\r'). 530 */ 531 if (ensure_in_buff_size(self, uudecode, len) 532 != ARCHIVE_OK) 533 return (ARCHIVE_FATAL); 534 if (uudecode->in_buff != b) 535 memmove(uudecode->in_buff, b, len); 536 uudecode->in_cnt = (int)len; 537 if (total == 0) { 538 /* Do not return 0; it means end-of-file. 539 * We should try to read bytes more. */ 540 __archive_read_filter_consume( 541 self->upstream, ravail); 542 goto read_more; 543 } 544 used += len; 545 break; 546 } 547 switch (uudecode->state) { 548 default: 549 case ST_FIND_HEAD: 550 /* Do not read more than UUENCODE_BID_MAX_READ bytes */ 551 if (total + len >= UUENCODE_BID_MAX_READ) { 552 archive_set_error(&self->archive->archive, 553 ARCHIVE_ERRNO_FILE_FORMAT, 554 "Invalid format data"); 555 return (ARCHIVE_FATAL); 556 } 557 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) 558 l = 6; 559 else if (len - nl >= 18 && 560 memcmp(b, "begin-base64 ", 13) == 0) 561 l = 13; 562 else 563 l = 0; 564 if (l != 0 && b[l] >= '0' && b[l] <= '7' && 565 b[l+1] >= '0' && b[l+1] <= '7' && 566 b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { 567 if (l == 6) 568 uudecode->state = ST_READ_UU; 569 else 570 uudecode->state = ST_READ_BASE64; 571 uudecode->mode = (mode_t)( 572 ((int)(b[l] - '0') * 64) + 573 ((int)(b[l+1] - '0') * 8) + 574 (int)(b[l+2] - '0')); 575 uudecode->mode_set = 1; 576 namelen = len - nl - 4 - l; 577 if (namelen > 1) { 578 if (uudecode->name != NULL) 579 free(uudecode->name); 580 uudecode->name = malloc(namelen + 1); 581 if (uudecode->name == NULL) { 582 archive_set_error( 583 &self->archive->archive, 584 ENOMEM, 585 "Can't allocate data for uudecode"); 586 return (ARCHIVE_FATAL); 587 } 588 strncpy(uudecode->name, 589 (const char *)(b + l + 4), 590 namelen); 591 uudecode->name[namelen] = '\0'; 592 } 593 } 594 break; 595 case ST_READ_UU: 596 if (total + len * 2 > OUT_BUFF_SIZE) 597 goto finish; 598 body = len - nl; 599 if (!uuchar[*b] || body <= 0) { 600 archive_set_error(&self->archive->archive, 601 ARCHIVE_ERRNO_MISC, 602 "Insufficient compressed data"); 603 return (ARCHIVE_FATAL); 604 } 605 /* Get length of undecoded bytes of current line. */ 606 l = UUDECODE(*b++); 607 body--; 608 if (l > body) { 609 archive_set_error(&self->archive->archive, 610 ARCHIVE_ERRNO_MISC, 611 "Insufficient compressed data"); 612 return (ARCHIVE_FATAL); 613 } 614 if (l == 0) { 615 uudecode->state = ST_UUEND; 616 break; 617 } 618 while (l > 0) { 619 int n = 0; 620 621 if (!uuchar[b[0]] || !uuchar[b[1]]) 622 break; 623 n = UUDECODE(*b++) << 18; 624 n |= UUDECODE(*b++) << 12; 625 *out++ = n >> 16; total++; 626 --l; 627 628 if (l > 0) { 629 if (!uuchar[b[0]]) 630 break; 631 n |= UUDECODE(*b++) << 6; 632 *out++ = (n >> 8) & 0xFF; total++; 633 --l; 634 } 635 if (l > 0) { 636 if (!uuchar[b[0]]) 637 break; 638 n |= UUDECODE(*b++); 639 *out++ = n & 0xFF; total++; 640 --l; 641 } 642 } 643 if (l) { 644 archive_set_error(&self->archive->archive, 645 ARCHIVE_ERRNO_MISC, 646 "Insufficient compressed data"); 647 return (ARCHIVE_FATAL); 648 } 649 break; 650 case ST_UUEND: 651 if (len - nl == 3 && memcmp(b, "end ", 3) == 0) 652 uudecode->state = ST_FIND_HEAD; 653 else { 654 archive_set_error(&self->archive->archive, 655 ARCHIVE_ERRNO_MISC, 656 "Insufficient compressed data"); 657 return (ARCHIVE_FATAL); 658 } 659 break; 660 case ST_READ_BASE64: 661 if (total + len * 2 > OUT_BUFF_SIZE) 662 goto finish; 663 l = len - nl; 664 if (l >= 3 && b[0] == '=' && b[1] == '=' && 665 b[2] == '=') { 666 uudecode->state = ST_FIND_HEAD; 667 break; 668 } 669 while (l > 0) { 670 int n = 0; 671 672 if (!base64[b[0]] || !base64[b[1]]) 673 break; 674 n = base64num[*b++] << 18; 675 n |= base64num[*b++] << 12; 676 *out++ = n >> 16; total++; 677 l -= 2; 678 679 if (l > 0) { 680 if (*b == '=') 681 break; 682 if (!base64[*b]) 683 break; 684 n |= base64num[*b++] << 6; 685 *out++ = (n >> 8) & 0xFF; total++; 686 --l; 687 } 688 if (l > 0) { 689 if (*b == '=') 690 break; 691 if (!base64[*b]) 692 break; 693 n |= base64num[*b++]; 694 *out++ = n & 0xFF; total++; 695 --l; 696 } 697 } 698 if (l && *b != '=') { 699 archive_set_error(&self->archive->archive, 700 ARCHIVE_ERRNO_MISC, 701 "Insufficient compressed data"); 702 return (ARCHIVE_FATAL); 703 } 704 break; 705 } 706 } 707finish: 708 if (ravail < avail_in) 709 used -= avail_in - ravail; 710 __archive_read_filter_consume(self->upstream, used); 711 712 *buff = uudecode->out_buff; 713 uudecode->total += total; 714 return (total); 715} 716 717static int 718uudecode_filter_close(struct archive_read_filter *self) 719{ 720 struct uudecode *uudecode; 721 722 uudecode = (struct uudecode *)self->data; 723 free(uudecode->in_buff); 724 free(uudecode->out_buff); 725 free(uudecode->name); 726 free(uudecode); 727 728 return (ARCHIVE_OK); 729} 730 731