Introduction
Introduction Statistics Contact Development Disclaimer Help
uudecode.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
uudecode.c (7090B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/stat.h>
3
4 #include <errno.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "util.h"
10
11 static int mflag = 0;
12 static int oflag = 0;
13
14 static FILE *
15 parsefile(const char *fname)
16 {
17 struct stat st;
18 int ret;
19
20 if (!strcmp(fname, "/dev/stdout") || !strcmp(fname, "-"))
21 return stdout;
22 ret = lstat(fname, &st);
23 /* if it is a new file, try to open it */
24 if (ret < 0 && errno == ENOENT)
25 goto tropen;
26 if (ret < 0) {
27 weprintf("lstat %s:", fname);
28 return NULL;
29 }
30 if (!S_ISREG(st.st_mode)) {
31 weprintf("for safety uudecode operates only on regular f…
32 return NULL;
33 }
34 tropen:
35 return fopen(fname, "w");
36 }
37
38 static void
39 parseheader(FILE *fp, const char *s, char **header, mode_t *mode, char *…
40 {
41 static char bufs[PATH_MAX + 18]; /* len header + mode + maxname …
42 char *p, *q;
43 size_t n;
44
45 if (!fgets(bufs, sizeof(bufs), fp))
46 if (ferror(fp))
47 eprintf("%s: read error:", s);
48 if (bufs[0] == '\0' || feof(fp))
49 eprintf("empty or nil header string\n");
50 if (!(p = strchr(bufs, '\n')))
51 eprintf("header string too long or non-newline terminate…
52 p = bufs;
53 if (!(q = strchr(p, ' ')))
54 eprintf("malformed mode string in header, expected ' '\n…
55 *header = bufs;
56 *q++ = '\0';
57 p = q;
58 /* now header should be null terminated, q points to mode */
59 if (!(q = strchr(p, ' ')))
60 eprintf("malformed mode string in header, expected ' '\n…
61 *q++ = '\0';
62 /* now mode should be null terminated, q points to fname */
63 *mode = parsemode(p, *mode, 0);
64 n = strlen(q);
65 while (n > 0 && (q[n - 1] == '\n' || q[n - 1] == '\r'))
66 q[--n] = '\0';
67 if (n > 0)
68 *fname = q;
69 else
70 eprintf("header string does not contain output file\n");
71 }
72
73 static const char b64dt[] = {
74 -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-…
75 -1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-…
76 52,53,54,55,56,57,58,59,60,61,-1,-1,-1, 0,-1,-1,-1, 0, 1, 2, 3, …
77 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-…
78 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,4…
79 49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-…
80 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-…
81 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-…
82 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-…
83 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-…
84 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
85 };
86
87 static void
88 uudecodeb64(FILE *fp, FILE *outfp)
89 {
90 char bufb[60], *pb;
91 char out[45], *po;
92 size_t n;
93 int b = 0, e, t = -1, l = 1;
94 unsigned char b24[3] = {0, 0, 0};
95
96 while ((n = fread(bufb, 1, sizeof(bufb), fp))) {
97 for (pb = bufb, po = out; pb < bufb + n; pb++) {
98 if (*pb == '\n') {
99 l++;
100 continue;
101 } else if (*pb == '=') {
102 switch (b) {
103 case 0:
104 /* expected '=' remaining
105 * including footer */
106 if (--t) {
107 fwrite(out, 1,
108 (po - out),
109 outfp);
110 return;
111 }
112 continue;
113 case 1:
114 eprintf("%d: unexpected \"=\""
115 "appeared\n", l);
116 case 2:
117 *po++ = b24[0];
118 b = 0;
119 t = 5; /* expect 5 '=' */
120 continue;
121 case 3:
122 *po++ = b24[0];
123 *po++ = b24[1];
124 b = 0;
125 t = 6; /* expect 6 '=' */
126 continue;
127 }
128 } else if ((e = b64dt[(int)*pb]) == -1)
129 eprintf("%d: invalid byte \"%c\"\n", l, …
130 else if (e == -2) /* whitespace */
131 continue;
132 else if (t > 0) /* state is parsing pad/footer */
133 eprintf("%d: invalid byte \"%c\""
134 " after padding\n",
135 l, *pb);
136 switch (b) { /* decode next base64 chr based on …
137 case 0: b24[0] |= e << 2; break;
138 case 1: b24[0] |= (e >> 4) & 0x3;
139 b24[1] |= (e & 0xf) << 4; break;
140 case 2: b24[1] |= (e >> 2) & 0xf;
141 b24[2] |= (e & 0x3) << 6; break;
142 case 3: b24[2] |= e; break;
143 }
144 if (++b == 4) { /* complete decoding an octet */
145 *po++ = b24[0];
146 *po++ = b24[1];
147 *po++ = b24[2];
148 b24[0] = b24[1] = b24[2] = 0;
149 b = 0;
150 }
151 }
152 fwrite(out, 1, (po - out), outfp);
153 }
154 eprintf("%d: invalid uudecode footer \"====\" not found\n", l);
155 }
156
157 static void
158 uudecode(FILE *fp, FILE *outfp)
159 {
160 char *bufb = NULL, *p;
161 size_t n = 0;
162 ssize_t len;
163 int ch, i;
164
165 #define DEC(c) (((c) - ' ') & 077) /* single character decode */
166 #define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
167 #define OUT_OF_RANGE(c) eprintf("character %c out of range: [%d-%d]\n", …
168
169 while ((len = getline(&bufb, &n, fp)) > 0) {
170 p = bufb;
171 /* trim newlines */
172 if (!len || bufb[len - 1] != '\n')
173 eprintf("no newline found, aborting\n");
174 bufb[len - 1] = '\0';
175
176 /* check for last line */
177 if ((i = DEC(*p)) <= 0)
178 break;
179 for (++p; i > 0; p += 4, i -= 3) {
180 if (i >= 3) {
181 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
182 IS_DEC(*(p + 2)) && IS_DEC(*(p + 3…
183 OUT_OF_RANGE(*p);
184
185 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
186 putc(ch, outfp);
187 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
188 putc(ch, outfp);
189 ch = DEC(p[2]) << 6 | DEC(p[3]);
190 putc(ch, outfp);
191 } else {
192 if (i >= 1) {
193 if (!(IS_DEC(*p) && IS_DEC(*(p +…
194 OUT_OF_RANGE(*p);
195
196 ch = DEC(p[0]) << 2 | DEC(p[1]) …
197 putc(ch, outfp);
198 }
199 if (i >= 2) {
200 if (!(IS_DEC(*(p + 1)) &&
201 IS_DEC(*(p + 2))))
202 OUT_OF_RANGE(*p);
203
204 ch = DEC(p[1]) << 4 | DEC(p[2]) …
205 putc(ch, outfp);
206 }
207 }
208 }
209 if (ferror(fp))
210 eprintf("read error:");
211 }
212 /* check for end or fail */
213 if ((len = getline(&bufb, &n, fp)) < 0)
214 eprintf("getline:");
215 if (len < 3 || strncmp(bufb, "end", 3) || bufb[3] != '\n')
216 eprintf("invalid uudecode footer \"end\" not found\n");
217 free(bufb);
218 }
219
220 static void
221 usage(void)
222 {
223 eprintf("usage: %s [-m] [-o output] [file]\n", argv0);
224 }
225
226 int
227 main(int argc, char *argv[])
228 {
229 FILE *fp = NULL, *nfp = NULL;
230 mode_t mode = 0;
231 int ret = 0;
232 char *fname, *header, *ifname, *ofname = NULL;
233 void (*d) (FILE *, FILE *) = NULL;
234
235 ARGBEGIN {
236 case 'm':
237 mflag = 1; /* accepted but unused (autodetect file type)…
238 break;
239 case 'o':
240 oflag = 1;
241 ofname = EARGF(usage());
242 break;
243 default:
244 usage();
245 } ARGEND
246
247 if (argc > 1)
248 usage();
249
250 if (!argc || !strcmp(argv[0], "-")) {
251 fp = stdin;
252 ifname = "<stdin>";
253 } else {
254 if (!(fp = fopen(argv[0], "r")))
255 eprintf("fopen %s:", argv[0]);
256 ifname = argv[0];
257 }
258
259 parseheader(fp, ifname, &header, &mode, &fname);
260
261 if (!strncmp(header, "begin", sizeof("begin")))
262 d = uudecode;
263 else if (!strncmp(header, "begin-base64", sizeof("begin-base64")…
264 d = uudecodeb64;
265 else
266 eprintf("unknown header %s:", header);
267
268 if (oflag)
269 fname = ofname;
270 if (!(nfp = parsefile(fname)))
271 eprintf("fopen %s:", fname);
272
273 d(fp, nfp);
274
275 if (nfp != stdout && chmod(fname, mode) < 0)
276 eprintf("chmod %s:", fname);
277
278 ret |= fshut(fp, (fp == stdin) ? "<stdin>" : argv[0]);
279 ret |= fshut(nfp, (nfp == stdout) ? "<stdout>" : fname);
280
281 return ret;
282 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.