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