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