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 46 struct 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 62 static int uudecode_bidder_bid(struct archive_read_filter_bidder *, 63 struct archive_read_filter *filter); 64 static int uudecode_bidder_init(struct archive_read_filter *); 65 66 static ssize_t uudecode_filter_read(struct archive_read_filter *, 67 const void **); 68 static int uudecode_filter_close(struct archive_read_filter *); 69 70 #if ARCHIVE_VERSION_NUMBER < 4000000 71 /* Deprecated; remove in libarchive 4.0 */ 72 int 73 archive_read_support_compression_uu(struct archive *a) 74 { 75 return archive_read_support_filter_uu(a); 76 } 77 #endif 78 79 int 80 archive_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 100 static 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 119 static 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 138 static 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 157 static 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 176 static ssize_t 177 get_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 210 static ssize_t 211 bid_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 261 static int 262 uudecode_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 /* "begin " */ 316 if (!uuchar[*b]) 317 return (0); 318 /* Get a length of decoded bytes. */ 319 l = UUDECODE(*b++); len--; 320 if (l > 45) 321 /* Normally, maximum length is 45(character 'M'). */ 322 return (0); 323 if (l > len - nl) 324 return (0); /* Line too short. */ 325 while (l) { 326 if (!uuchar[*b++]) 327 return (0); 328 --len; 329 --l; 330 } 331 if (len-nl == 1 && 332 (uuchar[*b] || /* Check sum. */ 333 (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */ 334 ++b; 335 --len; 336 } 337 b += nl; 338 if (avail && uuchar[*b]) 339 return (firstline+30); 340 } else if (l == 13) { 341 /* "begin-base64 " */ 342 while (len-nl > 0) { 343 if (!base64[*b++]) 344 return (0); 345 --len; 346 } 347 b += nl; 348 349 if (avail >= 5 && memcmp(b, "====\n", 5) == 0) 350 return (firstline+40); 351 if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0) 352 return (firstline+40); 353 if (avail > 0 && base64[*b]) 354 return (firstline+30); 355 } 356 357 return (0); 358 } 359 360 static int 361 uudecode_bidder_init(struct archive_read_filter *self) 362 { 363 struct uudecode *uudecode; 364 void *out_buff; 365 void *in_buff; 366 367 self->code = ARCHIVE_FILTER_UU; 368 self->name = "uu"; 369 self->read = uudecode_filter_read; 370 self->skip = NULL; /* not supported */ 371 self->close = uudecode_filter_close; 372 373 uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1); 374 out_buff = malloc(OUT_BUFF_SIZE); 375 in_buff = malloc(IN_BUFF_SIZE); 376 if (uudecode == NULL || out_buff == NULL || in_buff == NULL) { 377 archive_set_error(&self->archive->archive, ENOMEM, 378 "Can't allocate data for uudecode"); 379 free(uudecode); 380 free(out_buff); 381 free(in_buff); 382 return (ARCHIVE_FATAL); 383 } 384 385 self->data = uudecode; 386 uudecode->in_buff = in_buff; 387 uudecode->in_cnt = 0; 388 uudecode->in_allocated = IN_BUFF_SIZE; 389 uudecode->out_buff = out_buff; 390 uudecode->state = ST_FIND_HEAD; 391 392 return (ARCHIVE_OK); 393 } 394 395 static int 396 ensure_in_buff_size(struct archive_read_filter *self, 397 struct uudecode *uudecode, size_t size) 398 { 399 400 if (size > uudecode->in_allocated) { 401 unsigned char *ptr; 402 size_t newsize; 403 404 /* 405 * Calculate a new buffer size for in_buff. 406 * Increase its value until it has enough size we need. 407 */ 408 newsize = uudecode->in_allocated; 409 do { 410 if (newsize < IN_BUFF_SIZE*32) 411 newsize <<= 1; 412 else 413 newsize += IN_BUFF_SIZE; 414 } while (size > newsize); 415 /* Allocate the new buffer. */ 416 ptr = malloc(newsize); 417 if (ptr == NULL) { 418 free(ptr); 419 archive_set_error(&self->archive->archive, 420 ENOMEM, 421 "Can't allocate data for uudecode"); 422 return (ARCHIVE_FATAL); 423 } 424 /* Move the remaining data in in_buff into the new buffer. */ 425 if (uudecode->in_cnt) 426 memmove(ptr, uudecode->in_buff, uudecode->in_cnt); 427 /* Replace in_buff with the new buffer. */ 428 free(uudecode->in_buff); 429 uudecode->in_buff = ptr; 430 uudecode->in_allocated = newsize; 431 } 432 return (ARCHIVE_OK); 433 } 434 435 static ssize_t 436 uudecode_filter_read(struct archive_read_filter *self, const void **buff) 437 { 438 struct uudecode *uudecode; 439 const unsigned char *b, *d; 440 unsigned char *out; 441 ssize_t avail_in, ravail; 442 ssize_t used; 443 ssize_t total; 444 ssize_t len, llen, nl; 445 446 uudecode = (struct uudecode *)self->data; 447 448 read_more: 449 d = __archive_read_filter_ahead(self->upstream, 1, &avail_in); 450 if (d == NULL && avail_in < 0) 451 return (ARCHIVE_FATAL); 452 /* Quiet a code analyzer; make sure avail_in must be zero 453 * when d is NULL. */ 454 if (d == NULL) 455 avail_in = 0; 456 used = 0; 457 total = 0; 458 out = uudecode->out_buff; 459 ravail = avail_in; 460 if (uudecode->state == ST_IGNORE) { 461 used = avail_in; 462 goto finish; 463 } 464 if (uudecode->in_cnt) { 465 /* 466 * If there is remaining data which is saved by 467 * previous calling, use it first. 468 */ 469 if (ensure_in_buff_size(self, uudecode, 470 avail_in + uudecode->in_cnt) != ARCHIVE_OK) 471 return (ARCHIVE_FATAL); 472 memcpy(uudecode->in_buff + uudecode->in_cnt, 473 d, avail_in); 474 d = uudecode->in_buff; 475 avail_in += uudecode->in_cnt; 476 uudecode->in_cnt = 0; 477 } 478 for (;used < avail_in; d += llen, used += llen) { 479 int64_t l, body; 480 481 b = d; 482 len = get_line(b, avail_in - used, &nl); 483 if (len < 0) { 484 /* Non-ascii character is found. */ 485 if (uudecode->state == ST_FIND_HEAD && 486 (uudecode->total > 0 || total > 0)) { 487 uudecode->state = ST_IGNORE; 488 used = avail_in; 489 goto finish; 490 } 491 archive_set_error(&self->archive->archive, 492 ARCHIVE_ERRNO_MISC, 493 "Insufficient compressed data"); 494 return (ARCHIVE_FATAL); 495 } 496 llen = len; 497 if ((nl == 0) && (uudecode->state != ST_UUEND)) { 498 if (total == 0 && ravail <= 0) { 499 /* There is nothing more to read, fail */ 500 archive_set_error(&self->archive->archive, 501 ARCHIVE_ERRNO_FILE_FORMAT, 502 "Missing format data"); 503 return (ARCHIVE_FATAL); 504 } 505 /* 506 * Save remaining data which does not contain 507 * NL('\n','\r'). 508 */ 509 if (ensure_in_buff_size(self, uudecode, len) 510 != ARCHIVE_OK) 511 return (ARCHIVE_FATAL); 512 if (uudecode->in_buff != b) 513 memmove(uudecode->in_buff, b, len); 514 uudecode->in_cnt = (int)len; 515 if (total == 0) { 516 /* Do not return 0; it means end-of-file. 517 * We should try to read bytes more. */ 518 __archive_read_filter_consume( 519 self->upstream, ravail); 520 goto read_more; 521 } 522 used += len; 523 break; 524 } 525 switch (uudecode->state) { 526 default: 527 case ST_FIND_HEAD: 528 /* Do not read more than UUENCODE_BID_MAX_READ bytes */ 529 if (total + len >= UUENCODE_BID_MAX_READ) { 530 archive_set_error(&self->archive->archive, 531 ARCHIVE_ERRNO_FILE_FORMAT, 532 "Invalid format data"); 533 return (ARCHIVE_FATAL); 534 } 535 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) 536 l = 6; 537 else if (len - nl >= 18 && 538 memcmp(b, "begin-base64 ", 13) == 0) 539 l = 13; 540 else 541 l = 0; 542 if (l != 0 && b[l] >= '0' && b[l] <= '7' && 543 b[l+1] >= '0' && b[l+1] <= '7' && 544 b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { 545 if (l == 6) 546 uudecode->state = ST_READ_UU; 547 else 548 uudecode->state = ST_READ_BASE64; 549 } 550 break; 551 case ST_READ_UU: 552 if (total + len * 2 > OUT_BUFF_SIZE) 553 goto finish; 554 body = len - nl; 555 if (!uuchar[*b] || body <= 0) { 556 archive_set_error(&self->archive->archive, 557 ARCHIVE_ERRNO_MISC, 558 "Insufficient compressed data"); 559 return (ARCHIVE_FATAL); 560 } 561 /* Get length of undecoded bytes of current line. */ 562 l = UUDECODE(*b++); 563 body--; 564 if (l > body) { 565 archive_set_error(&self->archive->archive, 566 ARCHIVE_ERRNO_MISC, 567 "Insufficient compressed data"); 568 return (ARCHIVE_FATAL); 569 } 570 if (l == 0) { 571 uudecode->state = ST_UUEND; 572 break; 573 } 574 while (l > 0) { 575 int n = 0; 576 577 if (!uuchar[b[0]] || !uuchar[b[1]]) 578 break; 579 n = UUDECODE(*b++) << 18; 580 n |= UUDECODE(*b++) << 12; 581 *out++ = n >> 16; total++; 582 --l; 583 584 if (l > 0) { 585 if (!uuchar[b[0]]) 586 break; 587 n |= UUDECODE(*b++) << 6; 588 *out++ = (n >> 8) & 0xFF; total++; 589 --l; 590 } 591 if (l > 0) { 592 if (!uuchar[b[0]]) 593 break; 594 n |= UUDECODE(*b++); 595 *out++ = n & 0xFF; total++; 596 --l; 597 } 598 } 599 if (l) { 600 archive_set_error(&self->archive->archive, 601 ARCHIVE_ERRNO_MISC, 602 "Insufficient compressed data"); 603 return (ARCHIVE_FATAL); 604 } 605 break; 606 case ST_UUEND: 607 if (len - nl == 3 && memcmp(b, "end ", 3) == 0) 608 uudecode->state = ST_FIND_HEAD; 609 else { 610 archive_set_error(&self->archive->archive, 611 ARCHIVE_ERRNO_MISC, 612 "Insufficient compressed data"); 613 return (ARCHIVE_FATAL); 614 } 615 break; 616 case ST_READ_BASE64: 617 if (total + len * 2 > OUT_BUFF_SIZE) 618 goto finish; 619 l = len - nl; 620 if (l >= 3 && b[0] == '=' && b[1] == '=' && 621 b[2] == '=') { 622 uudecode->state = ST_FIND_HEAD; 623 break; 624 } 625 while (l > 0) { 626 int n = 0; 627 628 if (!base64[b[0]] || !base64[b[1]]) 629 break; 630 n = base64num[*b++] << 18; 631 n |= base64num[*b++] << 12; 632 *out++ = n >> 16; total++; 633 l -= 2; 634 635 if (l > 0) { 636 if (*b == '=') 637 break; 638 if (!base64[*b]) 639 break; 640 n |= base64num[*b++] << 6; 641 *out++ = (n >> 8) & 0xFF; total++; 642 --l; 643 } 644 if (l > 0) { 645 if (*b == '=') 646 break; 647 if (!base64[*b]) 648 break; 649 n |= base64num[*b++]; 650 *out++ = n & 0xFF; total++; 651 --l; 652 } 653 } 654 if (l && *b != '=') { 655 archive_set_error(&self->archive->archive, 656 ARCHIVE_ERRNO_MISC, 657 "Insufficient compressed data"); 658 return (ARCHIVE_FATAL); 659 } 660 break; 661 } 662 } 663 finish: 664 if (ravail < avail_in) 665 used -= avail_in - ravail; 666 __archive_read_filter_consume(self->upstream, used); 667 668 *buff = uudecode->out_buff; 669 uudecode->total += total; 670 return (total); 671 } 672 673 static int 674 uudecode_filter_close(struct archive_read_filter *self) 675 { 676 struct uudecode *uudecode; 677 678 uudecode = (struct uudecode *)self->data; 679 free(uudecode->in_buff); 680 free(uudecode->out_buff); 681 free(uudecode); 682 683 return (ARCHIVE_OK); 684 } 685 686