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