xref: /third_party/toybox/toys/posix/uudecode.c (revision 0f66f451)
1/* uudecode.c - uudecode / base64 decode
2 *
3 * Copyright 2013 Erich Plondke <toybox@erich.wreck.org>
4 *
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html
6
7USE_UUDECODE(NEWTOY(uudecode, ">1o:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
8
9config UUDECODE
10  bool "uudecode"
11  default y
12  help
13    usage: uudecode [-o OUTFILE] [INFILE]
14
15    Decode file from stdin (or INFILE).
16
17    -o	Write to OUTFILE instead of filename in header
18*/
19
20#define FOR_uudecode
21#include "toys.h"
22
23GLOBALS(
24  char *o;
25)
26
27void uudecode_main(void)
28{
29  FILE *ifp = stdin;
30  int ofd, idx = 0, m QUIET, n;
31  size_t allocated_length;
32  char *line = 0, mode[16],
33       *class[] = {"begin%*[ ]%15s%*[ ]%n", "begin-base64%*[ ]%15s%*[ ]%n"};
34
35  if (toys.optc) ifp = xfopen(*toys.optargs, "r");
36
37  while (!idx) {
38    if ((n = getline(&line, &allocated_length, ifp)) == -1)
39      error_exit("no begin line");
40    if (!n) continue;
41    line[n-1] = 0;
42    for (m=0; m < 2; m++) {
43      sscanf(line, class[m], mode, &idx);
44      if (idx) break;
45    }
46  }
47
48  if (TT.o && !strcmp(TT.o, "-")) ofd = 1;
49  else ofd = xcreate(TT.o ? TT.o : line+idx, O_WRONLY|O_CREAT|O_TRUNC,
50    string_to_mode(mode, 0777^toys.old_umask));
51
52  for (;;) {
53    char *in, *out;
54    int olen;
55
56    if (m == 2 || (n = getline(&line, &allocated_length, ifp)) == -1) break;
57    if (n) line[n-1] = 0;
58    if (!strcmp(line, m ? "====" : "end")) {
59      m = 2;
60      continue;
61    }
62
63    olen = 0;
64    in = out = line;
65    if (!m) olen = (*(in++) - 32) & 0x3f;
66
67    for (;;) {
68      int i = 0, x = 0, len = 4;
69      char c = 0;
70
71      if (!m) {
72        if (olen < 1) break;
73        if (olen < 3) len = olen + 1;
74      }
75
76      while (i < len) {
77        if (!(c = *(in++))) goto line_done;
78
79        if (m) {
80          if (c == '=') {
81            len--;
82            continue;
83          } else if (len != 4) break;
84
85          if (c >= 'A' && c <= 'Z') c -= 'A';
86          else if (c >= 'a' && c <= 'z') c += 26 - 'a';
87          else if (c >= '0' && c <= '9') c += 52 - '0';
88          else if (c == '+') c = 62;
89          else if (c == '/') c = 63;
90          else continue;
91        } else c = (c - 32) & 0x3f;
92
93        x |= c << (6*(3-i));
94
95        if (i && i < len) {
96          *(out++) = (x>>(8*(3-i))) & 0xff;
97          olen--;
98        }
99        i++;
100      }
101
102      if (i && i!=len) error_exit("bad %s", line);
103    }
104line_done:
105    xwrite(ofd, line, out-line);
106  }
107
108  if (CFG_TOYBOX_FREE) {
109    if (ifp != stdin) fclose(ifp);
110    close(ofd);
111    free(line);
112  }
113}
114