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
archive_read_support_compression_uu(struct archive * a)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
archive_read_support_filter_uu(struct archive * _a)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
get_line(const unsigned char * b,ssize_t avail,ssize_t * nlsize)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
bid_get_line(struct archive_read_filter * filter,const unsigned char ** b,ssize_t * avail,ssize_t * ravail,ssize_t * nl,size_t * nbytes_read)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
uudecode_bidder_bid(struct archive_read_filter_bidder * self,struct archive_read_filter * filter)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
uudecode_bidder_init(struct archive_read_filter * self)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
ensure_in_buff_size(struct archive_read_filter * self,struct uudecode * uudecode,size_t size)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
uudecode_filter_read(struct archive_read_filter * self,const void ** buff)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
uudecode_filter_close(struct archive_read_filter * self)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