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