]> git.ipfire.org Git - thirdparty/libarchive.git/blame - libarchive/archive_read_support_filter_uu.c
uudecode filter: fix memory allocation and name length calculation
[thirdparty/libarchive.git] / libarchive / archive_read_support_filter_uu.c
CommitLineData
ecf376dd 1/*-
a1f785ea 2 * Copyright (c) 2009-2011 Michihiro NAKAJIMA
ecf376dd
MN
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"
77fc5b1e 27__FBSDID("$FreeBSD$");
ecf376dd
MN
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"
8f558b2a 40#include "archive_entry.h"
ecf376dd
MN
41#include "archive_private.h"
42#include "archive_read_private.h"
43
d09d4556
TK
44/* Maximum lookahead during bid phase */
45#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
8b30c206 46
ecf376dd
MN
47struct uudecode {
48 int64_t total;
49 unsigned char *in_buff;
50#define IN_BUFF_SIZE (1024)
51 int in_cnt;
52 size_t in_allocated;
53 unsigned char *out_buff;
54#define OUT_BUFF_SIZE (64 * 1024)
55 int state;
56#define ST_FIND_HEAD 0
57#define ST_READ_UU 1
58#define ST_UUEND 2
59#define ST_READ_BASE64 3
664ea71d 60#define ST_IGNORE 4
8f558b2a
MM
61 mode_t mode;
62 int mode_set;
63 char *name;
ecf376dd
MN
64};
65
66static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
67 struct archive_read_filter *filter);
68static int uudecode_bidder_init(struct archive_read_filter *);
69
8f558b2a
MM
70static int uudecode_read_header(struct archive_read_filter *,
71 struct archive_entry *entry);
ecf376dd
MN
72static ssize_t uudecode_filter_read(struct archive_read_filter *,
73 const void **);
74static int uudecode_filter_close(struct archive_read_filter *);
75
7a80c8df
TK
76#if ARCHIVE_VERSION_NUMBER < 4000000
77/* Deprecated; remove in libarchive 4.0 */
a58aaa4f 78int
7a80c8df 79archive_read_support_compression_uu(struct archive *a)
a58aaa4f 80{
cf2a3031 81 return archive_read_support_filter_uu(a);
a58aaa4f 82}
7a80c8df 83#endif
a58aaa4f 84
64b82ac5
EV
85static const struct archive_read_filter_bidder_vtable
86uudecode_bidder_vtable = {
87 .bid = uudecode_bidder_bid,
88 .init = uudecode_bidder_init,
89};
90
ecf376dd 91int
7a80c8df 92archive_read_support_filter_uu(struct archive *_a)
ecf376dd
MN
93{
94 struct archive_read *a = (struct archive_read *)_a;
ecf376dd 95
5b5f6b59
EV
96 return __archive_read_register_bidder(a, NULL, "uu",
97 &uudecode_bidder_vtable);
ecf376dd
MN
98}
99
100static 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
119static 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
138static 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
157static 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
176static ssize_t
177get_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
c00dfcb2
MN
210static ssize_t
211bid_get_line(struct archive_read_filter *filter,
8b30c206
TK
212 const unsigned char **b, ssize_t *avail, ssize_t *ravail,
213 ssize_t *nl, size_t* nbytes_read)
c00dfcb2
MN
214{
215 ssize_t len;
216 int quit;
217
218 quit = 0;
0057a121
MN
219 if (*avail == 0) {
220 *nl = 0;
221 len = 0;
222 } else
223 len = get_line(*b, *avail, nl);
2d3cd81c 224
c00dfcb2
MN
225 /*
226 * Read bytes more while it does not reach the end of line.
227 */
2d3cd81c
MN
228 while (*nl == 0 && len == *avail && !quit &&
229 *nbytes_read < UUENCODE_BID_MAX_READ) {
c00dfcb2 230 ssize_t diff = *ravail - *avail;
2d3cd81c
MN
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;
c00dfcb2 238
2d3cd81c 239 *b = __archive_read_filter_ahead(filter, nbytes_req, avail);
c00dfcb2
MN
240 if (*b == NULL) {
241 if (*ravail >= *avail)
242 return (0);
2d3cd81c 243 /* Reading bytes reaches the end of a stream. */
c00dfcb2
MN
244 *b = __archive_read_filter_ahead(filter, *avail, avail);
245 quit = 1;
246 }
8b30c206 247 *nbytes_read = *avail;
c00dfcb2
MN
248 *ravail = *avail;
249 *b += diff;
250 *avail -= diff;
a8061438 251 tested = len;/* Skip some bytes we already determined. */
2d3cd81c
MN
252 len = get_line(*b + tested, *avail - tested, nl);
253 if (len >= 0)
254 len += tested;
c00dfcb2
MN
255 }
256 return (len);
257}
258
ecf376dd
MN
259#define UUDECODE(c) (((c) - 0x20) & 0x3f)
260
261static int
262uudecode_bidder_bid(struct archive_read_filter_bidder *self,
263 struct archive_read_filter *filter)
264{
265 const unsigned char *b;
c00dfcb2 266 ssize_t avail, ravail;
ecf376dd
MN
267 ssize_t len, nl;
268 int l;
269 int firstline;
8b30c206 270 size_t nbytes_read;
ecf376dd
MN
271
272 (void)self; /* UNUSED */
273
274 b = __archive_read_filter_ahead(filter, 1, &avail);
275 if (b == NULL)
276 return (0);
277
ecf376dd 278 firstline = 20;
c00dfcb2 279 ravail = avail;
8b30c206 280 nbytes_read = avail;
0057a121 281 for (;;) {
8b30c206 282 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
cceb8f2d 283 if (len < 0 || nl == 0)
8b30c206 284 return (0); /* No match found. */
4c04f230 285 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
ecf376dd 286 l = 6;
4c04f230 287 else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
ecf376dd
MN
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
ecf376dd
MN
297 b += len;
298 avail -= len;
299 if (l)
300 break;
301 firstline = 0;
8b30c206 302
d09d4556 303 /* Do not read more than UUENCODE_BID_MAX_READ bytes */
8b30c206
TK
304 if (nbytes_read >= UUENCODE_BID_MAX_READ)
305 return (0);
ecf376dd
MN
306 }
307 if (!avail)
308 return (0);
8b30c206 309 len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
ecf376dd
MN
310 if (len < 0 || nl == 0)
311 return (0);/* There are non-ascii characters. */
312 avail -= len;
313
314 if (l == 6) {
53d73345 315 /* "begin " */
ecf376dd
MN
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);
4fab664f
JS
323 if (l > len - nl)
324 return (0); /* Line too short. */
325 while (l) {
326 if (!uuchar[*b++])
327 return (0);
328 --len;
329 --l;
ecf376dd 330 }
ecf376dd
MN
331 if (len-nl == 1 &&
332 (uuchar[*b] || /* Check sum. */
333 (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
334 ++b;
335 --len;
336 }
337 b += nl;
338 if (avail && uuchar[*b])
339 return (firstline+30);
53d73345
MM
340 } else if (l == 13) {
341 /* "begin-base64 " */
ecf376dd
MN
342 while (len-nl > 0) {
343 if (!base64[*b++])
344 return (0);
345 --len;
346 }
347 b += nl;
0f01d202 348
ecf376dd
MN
349 if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
350 return (firstline+40);
351 if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
352 return (firstline+40);
353 if (avail > 0 && base64[*b])
354 return (firstline+30);
355 }
356
357 return (0);
358}
359
4b7558e1
EV
360static const struct archive_read_filter_vtable
361uudecode_reader_vtable = {
362 .read = uudecode_filter_read,
363 .close = uudecode_filter_close,
8f558b2a 364 .read_header = uudecode_read_header
4b7558e1
EV
365};
366
ecf376dd
MN
367static int
368uudecode_bidder_init(struct archive_read_filter *self)
369{
370 struct uudecode *uudecode;
371 void *out_buff;
372 void *in_buff;
373
ade42e29 374 self->code = ARCHIVE_FILTER_UU;
ecf376dd 375 self->name = "uu";
ecf376dd
MN
376
377 uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
378 out_buff = malloc(OUT_BUFF_SIZE);
379 in_buff = malloc(IN_BUFF_SIZE);
380 if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
381 archive_set_error(&self->archive->archive, ENOMEM,
382 "Can't allocate data for uudecode");
383 free(uudecode);
384 free(out_buff);
385 free(in_buff);
386 return (ARCHIVE_FATAL);
387 }
388
389 self->data = uudecode;
390 uudecode->in_buff = in_buff;
391 uudecode->in_cnt = 0;
392 uudecode->in_allocated = IN_BUFF_SIZE;
393 uudecode->out_buff = out_buff;
394 uudecode->state = ST_FIND_HEAD;
8f558b2a
MM
395 uudecode->mode_set = 0;
396 uudecode->name = NULL;
4b7558e1 397 self->vtable = &uudecode_reader_vtable;
ecf376dd
MN
398
399 return (ARCHIVE_OK);
400}
401
402static int
403ensure_in_buff_size(struct archive_read_filter *self,
404 struct uudecode *uudecode, size_t size)
405{
406
407 if (size > uudecode->in_allocated) {
408 unsigned char *ptr;
409 size_t newsize;
410
a1f785ea
MN
411 /*
412 * Calculate a new buffer size for in_buff.
413 * Increase its value until it has enough size we need.
414 */
415 newsize = uudecode->in_allocated;
416 do {
417 if (newsize < IN_BUFF_SIZE*32)
418 newsize <<= 1;
419 else
420 newsize += IN_BUFF_SIZE;
421 } while (size > newsize);
422 /* Allocate the new buffer. */
ecf376dd 423 ptr = malloc(newsize);
a1f785ea 424 if (ptr == NULL) {
ecf376dd
MN
425 free(ptr);
426 archive_set_error(&self->archive->archive,
427 ENOMEM,
428 "Can't allocate data for uudecode");
429 return (ARCHIVE_FATAL);
430 }
a1f785ea 431 /* Move the remaining data in in_buff into the new buffer. */
ecf376dd 432 if (uudecode->in_cnt)
a1f785ea
MN
433 memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
434 /* Replace in_buff with the new buffer. */
ecf376dd
MN
435 free(uudecode->in_buff);
436 uudecode->in_buff = ptr;
437 uudecode->in_allocated = newsize;
438 }
439 return (ARCHIVE_OK);
440}
441
8f558b2a
MM
442static int
443uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry)
444{
445
446 struct uudecode *uudecode;
447 uudecode = (struct uudecode *)self->data;
448
449 if (uudecode->mode_set != 0)
450 archive_entry_set_mode(entry, S_IFREG | uudecode->mode);
451
452 if (uudecode->name != NULL)
453 archive_entry_set_pathname(entry, uudecode->name);
454
455 return (ARCHIVE_OK);
456}
457
ecf376dd
MN
458static ssize_t
459uudecode_filter_read(struct archive_read_filter *self, const void **buff)
460{
461 struct uudecode *uudecode;
462 const unsigned char *b, *d;
463 unsigned char *out;
c00dfcb2 464 ssize_t avail_in, ravail;
ecf376dd
MN
465 ssize_t used;
466 ssize_t total;
8f558b2a 467 ssize_t len, llen, nl, namelen;
ecf376dd
MN
468
469 uudecode = (struct uudecode *)self->data;
470
c00dfcb2 471read_more:
ecf376dd
MN
472 d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
473 if (d == NULL && avail_in < 0)
474 return (ARCHIVE_FATAL);
e4d7323c
MN
475 /* Quiet a code analyzer; make sure avail_in must be zero
476 * when d is NULL. */
477 if (d == NULL)
478 avail_in = 0;
ecf376dd
MN
479 used = 0;
480 total = 0;
481 out = uudecode->out_buff;
c00dfcb2 482 ravail = avail_in;
664ea71d
MN
483 if (uudecode->state == ST_IGNORE) {
484 used = avail_in;
485 goto finish;
486 }
c00dfcb2
MN
487 if (uudecode->in_cnt) {
488 /*
489 * If there is remaining data which is saved by
490 * previous calling, use it first.
491 */
492 if (ensure_in_buff_size(self, uudecode,
493 avail_in + uudecode->in_cnt) != ARCHIVE_OK)
494 return (ARCHIVE_FATAL);
495 memcpy(uudecode->in_buff + uudecode->in_cnt,
496 d, avail_in);
497 d = uudecode->in_buff;
498 avail_in += uudecode->in_cnt;
499 uudecode->in_cnt = 0;
500 }
ecf376dd 501 for (;used < avail_in; d += llen, used += llen) {
4f54591d 502 int64_t l, body;
ecf376dd
MN
503
504 b = d;
505 len = get_line(b, avail_in - used, &nl);
506 if (len < 0) {
507 /* Non-ascii character is found. */
664ea71d
MN
508 if (uudecode->state == ST_FIND_HEAD &&
509 (uudecode->total > 0 || total > 0)) {
510 uudecode->state = ST_IGNORE;
511 used = avail_in;
512 goto finish;
513 }
ecf376dd
MN
514 archive_set_error(&self->archive->archive,
515 ARCHIVE_ERRNO_MISC,
516 "Insufficient compressed data");
517 return (ARCHIVE_FATAL);
518 }
519 llen = len;
4b590128 520 if ((nl == 0) && (uudecode->state != ST_UUEND)) {
7c2ffc20
MM
521 if (total == 0 && ravail <= 0) {
522 /* There is nothing more to read, fail */
523 archive_set_error(&self->archive->archive,
524 ARCHIVE_ERRNO_FILE_FORMAT,
525 "Missing format data");
526 return (ARCHIVE_FATAL);
527 }
ecf376dd
MN
528 /*
529 * Save remaining data which does not contain
530 * NL('\n','\r').
531 */
532 if (ensure_in_buff_size(self, uudecode, len)
533 != ARCHIVE_OK)
534 return (ARCHIVE_FATAL);
c00dfcb2
MN
535 if (uudecode->in_buff != b)
536 memmove(uudecode->in_buff, b, len);
4f54591d 537 uudecode->in_cnt = (int)len;
c00dfcb2
MN
538 if (total == 0) {
539 /* Do not return 0; it means end-of-file.
540 * We should try to read bytes more. */
541 __archive_read_filter_consume(
542 self->upstream, ravail);
543 goto read_more;
544 }
2b79319f 545 used += len;
ecf376dd
MN
546 break;
547 }
ecf376dd
MN
548 switch (uudecode->state) {
549 default:
550 case ST_FIND_HEAD:
42ecca9d
MN
551 /* Do not read more than UUENCODE_BID_MAX_READ bytes */
552 if (total + len >= UUENCODE_BID_MAX_READ) {
553 archive_set_error(&self->archive->archive,
554 ARCHIVE_ERRNO_FILE_FORMAT,
555 "Invalid format data");
556 return (ARCHIVE_FATAL);
557 }
b338a121 558 if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
ecf376dd 559 l = 6;
b338a121 560 else if (len - nl >= 18 &&
ecf376dd
MN
561 memcmp(b, "begin-base64 ", 13) == 0)
562 l = 13;
563 else
564 l = 0;
565 if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
566 b[l+1] >= '0' && b[l+1] <= '7' &&
567 b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
568 if (l == 6)
569 uudecode->state = ST_READ_UU;
570 else
571 uudecode->state = ST_READ_BASE64;
8f558b2a
MM
572 uudecode->mode = (mode_t)(
573 ((int)(b[l] - '0') * 64) +
574 ((int)(b[l+1] - '0') * 8) +
575 (int)(b[l+2] - '0'));
576 uudecode->mode_set = 1;
bce04175 577 namelen = len - nl - 4 - l;
8f558b2a 578 if (namelen > 1) {
bce04175 579 uudecode->name = malloc(namelen + 1);
8f558b2a
MM
580 strncpy(uudecode->name,
581 (const char *)(b + l + 4),
582 namelen);
583 uudecode->name[namelen] = '\0';
584 }
ecf376dd
MN
585 }
586 break;
587 case ST_READ_UU:
42ecca9d 588 if (total + len * 2 > OUT_BUFF_SIZE)
d2a08aef 589 goto finish;
ecf376dd
MN
590 body = len - nl;
591 if (!uuchar[*b] || body <= 0) {
592 archive_set_error(&self->archive->archive,
593 ARCHIVE_ERRNO_MISC,
594 "Insufficient compressed data");
595 return (ARCHIVE_FATAL);
596 }
17feb73f 597 /* Get length of undecoded bytes of current line. */
ecf376dd
MN
598 l = UUDECODE(*b++);
599 body--;
600 if (l > body) {
601 archive_set_error(&self->archive->archive,
602 ARCHIVE_ERRNO_MISC,
603 "Insufficient compressed data");
604 return (ARCHIVE_FATAL);
605 }
606 if (l == 0) {
607 uudecode->state = ST_UUEND;
608 break;
609 }
610 while (l > 0) {
611 int n = 0;
612
77d0d190
MM
613 if (!uuchar[b[0]] || !uuchar[b[1]])
614 break;
615 n = UUDECODE(*b++) << 18;
616 n |= UUDECODE(*b++) << 12;
617 *out++ = n >> 16; total++;
618 --l;
619
ecf376dd
MN
620 if (l > 0) {
621 if (!uuchar[b[0]])
622 break;
623 n |= UUDECODE(*b++) << 6;
624 *out++ = (n >> 8) & 0xFF; total++;
625 --l;
626 }
627 if (l > 0) {
628 if (!uuchar[b[0]])
629 break;
630 n |= UUDECODE(*b++);
631 *out++ = n & 0xFF; total++;
632 --l;
633 }
634 }
635 if (l) {
636 archive_set_error(&self->archive->archive,
637 ARCHIVE_ERRNO_MISC,
638 "Insufficient compressed data");
639 return (ARCHIVE_FATAL);
640 }
641 break;
642 case ST_UUEND:
643 if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
644 uudecode->state = ST_FIND_HEAD;
645 else {
646 archive_set_error(&self->archive->archive,
647 ARCHIVE_ERRNO_MISC,
648 "Insufficient compressed data");
649 return (ARCHIVE_FATAL);
650 }
651 break;
652 case ST_READ_BASE64:
42ecca9d 653 if (total + len * 2 > OUT_BUFF_SIZE)
d2a08aef 654 goto finish;
ecf376dd
MN
655 l = len - nl;
656 if (l >= 3 && b[0] == '=' && b[1] == '=' &&
657 b[2] == '=') {
658 uudecode->state = ST_FIND_HEAD;
659 break;
660 }
661 while (l > 0) {
662 int n = 0;
663
77d0d190
MM
664 if (!base64[b[0]] || !base64[b[1]])
665 break;
666 n = base64num[*b++] << 18;
667 n |= base64num[*b++] << 12;
668 *out++ = n >> 16; total++;
669 l -= 2;
670
ecf376dd
MN
671 if (l > 0) {
672 if (*b == '=')
673 break;
674 if (!base64[*b])
675 break;
676 n |= base64num[*b++] << 6;
677 *out++ = (n >> 8) & 0xFF; total++;
678 --l;
679 }
680 if (l > 0) {
681 if (*b == '=')
682 break;
683 if (!base64[*b])
684 break;
685 n |= base64num[*b++];
686 *out++ = n & 0xFF; total++;
687 --l;
688 }
689 }
690 if (l && *b != '=') {
691 archive_set_error(&self->archive->archive,
692 ARCHIVE_ERRNO_MISC,
693 "Insufficient compressed data");
694 return (ARCHIVE_FATAL);
695 }
696 break;
697 }
698 }
d2a08aef
MN
699finish:
700 if (ravail < avail_in)
701 used -= avail_in - ravail;
702 __archive_read_filter_consume(self->upstream, used);
ecf376dd
MN
703
704 *buff = uudecode->out_buff;
705 uudecode->total += total;
706 return (total);
707}
708
709static int
710uudecode_filter_close(struct archive_read_filter *self)
711{
712 struct uudecode *uudecode;
713
714 uudecode = (struct uudecode *)self->data;
715 free(uudecode->in_buff);
716 free(uudecode->out_buff);
8f558b2a 717 free(uudecode->name);
ecf376dd
MN
718 free(uudecode);
719
720 return (ARCHIVE_OK);
721}
722