~sergei.glushchenko/+junk/page-scan-hack

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive/archive_read_support_compression_uu.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

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