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