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