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 newsize = uudecode->in_allocated << 1; 385 ptr = malloc(newsize); 386 if (ptr == NULL || 387 newsize < uudecode->in_allocated) { 388 free(ptr); 389 archive_set_error(&self->archive->archive, 390 ENOMEM, 391 "Can't allocate data for uudecode"); 392 return (ARCHIVE_FATAL); 393 } 394 if (uudecode->in_cnt) 395 memmove(ptr, uudecode->in_buff, 396 uudecode->in_cnt); 397 free(uudecode->in_buff); 398 uudecode->in_buff = ptr; 399 uudecode->in_allocated = newsize; 400 } 401 return (ARCHIVE_OK); 402} 403 404static ssize_t 405uudecode_filter_read(struct archive_read_filter *self, const void **buff) 406{ 407 struct uudecode *uudecode; 408 const unsigned char *b, *d; 409 unsigned char *out; 410 ssize_t avail_in, ravail; 411 ssize_t used; 412 ssize_t total; 413 ssize_t len, llen, nl; 414 415 uudecode = (struct uudecode *)self->data; 416 417read_more: 418 d = __archive_read_filter_ahead(self->upstream, 1, &avail_in); 419 if (d == NULL && avail_in < 0) 420 return (ARCHIVE_FATAL); 421 /* Quiet a code analyzer; make sure avail_in must be zero 422 * when d is NULL. */ 423 if (d == NULL) 424 avail_in = 0; 425 used = 0; 426 total = 0; 427 out = uudecode->out_buff; 428 ravail = avail_in; 429 if (uudecode->in_cnt) { 430 /* 431 * If there is remaining data which is saved by 432 * previous calling, use it first. 433 */ 434 if (ensure_in_buff_size(self, uudecode, 435 avail_in + uudecode->in_cnt) != ARCHIVE_OK) 436 return (ARCHIVE_FATAL); 437 memcpy(uudecode->in_buff + uudecode->in_cnt, 438 d, avail_in); 439 d = uudecode->in_buff; 440 avail_in += uudecode->in_cnt; 441 uudecode->in_cnt = 0; 442 } 443 for (;used < avail_in; d += llen, used += llen) { 444 int l, body; 445 446 b = d; 447 len = get_line(b, avail_in - used, &nl); 448 if (len < 0) { 449 /* Non-ascii character is found. */ 450 archive_set_error(&self->archive->archive, 451 ARCHIVE_ERRNO_MISC, 452 "Insufficient compressed data"); 453 return (ARCHIVE_FATAL); 454 } 455 llen = len; 456 if (nl == 0) { 457 /* 458 * Save remaining data which does not contain 459 * NL('\n','\r'). 460 */ 461 if (ensure_in_buff_size(self, uudecode, len) 462 != ARCHIVE_OK) 463 return (ARCHIVE_FATAL); 464 if (uudecode->in_buff != b) 465 memmove(uudecode->in_buff, b, len); 466 uudecode->in_cnt = len; 467 if (total == 0) { 468 /* Do not return 0; it means end-of-file. 469 * We should try to read bytes more. */ 470 __archive_read_filter_consume( 471 self->upstream, ravail); 472 goto read_more; 473 } 474 break; 475 } 476 if (total + len * 2 > OUT_BUFF_SIZE) 477 break; 478 switch (uudecode->state) { 479 default: 480 case ST_FIND_HEAD: 481 if (len - nl > 13 && memcmp(b, "begin ", 6) == 0) 482 l = 6; 483 else if (len - nl > 18 && 484 memcmp(b, "begin-base64 ", 13) == 0) 485 l = 13; 486 else 487 l = 0; 488 if (l != 0 && b[l] >= '0' && b[l] <= '7' && 489 b[l+1] >= '0' && b[l+1] <= '7' && 490 b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { 491 if (l == 6) 492 uudecode->state = ST_READ_UU; 493 else 494 uudecode->state = ST_READ_BASE64; 495 } 496 break; 497 case ST_READ_UU: 498 body = len - nl; 499 if (!uuchar[*b] || body <= 0) { 500 archive_set_error(&self->archive->archive, 501 ARCHIVE_ERRNO_MISC, 502 "Insufficient compressed data"); 503 return (ARCHIVE_FATAL); 504 } 505 /* Get length of undecoded bytes of curent line. */ 506 l = UUDECODE(*b++); 507 body--; 508 if (l > body) { 509 archive_set_error(&self->archive->archive, 510 ARCHIVE_ERRNO_MISC, 511 "Insufficient compressed data"); 512 return (ARCHIVE_FATAL); 513 } 514 if (l == 0) { 515 uudecode->state = ST_UUEND; 516 break; 517 } 518 while (l > 0) { 519 int n = 0; 520 521 if (l > 0) { 522 if (!uuchar[b[0]] || !uuchar[b[1]]) 523 break; 524 n = UUDECODE(*b++) << 18; 525 n |= UUDECODE(*b++) << 12; 526 *out++ = n >> 16; total++; 527 --l; 528 } 529 if (l > 0) { 530 if (!uuchar[b[0]]) 531 break; 532 n |= UUDECODE(*b++) << 6; 533 *out++ = (n >> 8) & 0xFF; total++; 534 --l; 535 } 536 if (l > 0) { 537 if (!uuchar[b[0]]) 538 break; 539 n |= UUDECODE(*b++); 540 *out++ = n & 0xFF; total++; 541 --l; 542 } 543 } 544 if (l) { 545 archive_set_error(&self->archive->archive, 546 ARCHIVE_ERRNO_MISC, 547 "Insufficient compressed data"); 548 return (ARCHIVE_FATAL); 549 } 550 break; 551 case ST_UUEND: 552 if (len - nl == 3 && memcmp(b, "end ", 3) == 0) 553 uudecode->state = ST_FIND_HEAD; 554 else { 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_READ_BASE64: 562 l = len - nl; 563 if (l >= 3 && b[0] == '=' && b[1] == '=' && 564 b[2] == '=') { 565 uudecode->state = ST_FIND_HEAD; 566 break; 567 } 568 while (l > 0) { 569 int n = 0; 570 571 if (l > 0) { 572 if (!base64[b[0]] || !base64[b[1]]) 573 break; 574 n = base64num[*b++] << 18; 575 n |= base64num[*b++] << 12; 576 *out++ = n >> 16; total++; 577 l -= 2; 578 } 579 if (l > 0) { 580 if (*b == '=') 581 break; 582 if (!base64[*b]) 583 break; 584 n |= base64num[*b++] << 6; 585 *out++ = (n >> 8) & 0xFF; total++; 586 --l; 587 } 588 if (l > 0) { 589 if (*b == '=') 590 break; 591 if (!base64[*b]) 592 break; 593 n |= base64num[*b++]; 594 *out++ = n & 0xFF; total++; 595 --l; 596 } 597 } 598 if (l && *b != '=') { 599 archive_set_error(&self->archive->archive, 600 ARCHIVE_ERRNO_MISC, 601 "Insufficient compressed data"); 602 return (ARCHIVE_FATAL); 603 } 604 break; 605 } 606 } 607 608 __archive_read_filter_consume(self->upstream, ravail); 609 610 *buff = uudecode->out_buff; 611 uudecode->total += total; 612 return (total); 613} 614 615static int 616uudecode_filter_close(struct archive_read_filter *self) 617{ 618 struct uudecode *uudecode; 619 620 uudecode = (struct uudecode *)self->data; 621 free(uudecode->in_buff); 622 free(uudecode->out_buff); 623 free(uudecode); 624 625 return (ARCHIVE_OK); 626} 627 628