Coverage Report

Created: 2024-02-25 06:27

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