]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libarchive/libarchive/archive_read_support_filter_uu.c
libarchive: import changes from upstream
[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 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
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
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
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
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
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
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
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
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