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