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