summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2003-11-06 03:17:23 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2003-11-06 03:17:23 +0000
commit7f9de02ca6a6d0fbe28e826c4a7cd8bf8b7deeef (patch)
tree9a4e938c3260eaf83ca3c9c87c66a6b53452ee43
parent5912acb6709e78c307f9c485b6e3f742a4b5eb1b (diff)
downloadbusybox-w32-7f9de02ca6a6d0fbe28e826c4a7cd8bf8b7deeef.tar.gz
busybox-w32-7f9de02ca6a6d0fbe28e826c4a7cd8bf8b7deeef.tar.bz2
busybox-w32-7f9de02ca6a6d0fbe28e826c4a7cd8bf8b7deeef.zip
Rewrite, 800+ bytes smaller and more robust.
-rw-r--r--coreutils/uudecode.c508
1 files changed, 178 insertions, 330 deletions
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 4f9270c18..1734ed419 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -1,353 +1,201 @@
1/* uudecode.c -- uudecode utility. 1/*
2 * Copyright (C) 1994, 1995 Free Software Foundation, Inc. 2 * GPLv2
3 * Copyright 2003, Glenn McGrath <bug1@optushome.com.au>
3 * 4 *
4 * This product is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License version 2 as published
6 * the Free Software Foundation; either version 2, or (at your option) 7 * by the Free Software Foundation; either version 2 of the License.
7 * any later version.
8 * 8 *
9 * This product is distributed in the hope that it will be useful, 9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU Library General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with this product; see the file COPYING. If not, write to 15 * along with this program; if not, write to the Free Software
16 * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 * 02111-1307, USA.
18 * 17 *
19 * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. 18 * Based on specification from
19 * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
20 * 20 *
21 * Original copyright notice is retained at the end of this file. 21 * Bugs: the spec doesnt mention anything about "`\n`\n" prior to the "end" line
22 */ 22 */
23 23
24 24
25
26#include <stdio.h> 25#include <stdio.h>
27#include <errno.h> 26#include <errno.h>
28#include <getopt.h> 27#include <getopt.h>
29#include <string.h> 28#include <string.h>
30#include <stdlib.h> 29#include <stdlib.h>
31#include "busybox.h"
32#include "pwd_.h"
33#include "grp_.h"
34
35/*struct passwd *getpwnam();*/
36 30
37/* Single character decode. */ 31#include "libbb.h"
38#define DEC(Char) (((Char) - ' ') & 077)
39 32
40static int read_stduu (const char *inname) 33static int read_stduu(FILE *src_stream, FILE *dst_stream)
41{ 34{
42 char buf[2 * BUFSIZ]; 35 char *line;
43 36
44 while (1) { 37 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
45 int n; 38 int length;
46 char *p; 39 char *line_ptr = line;
47 40
48 if (fgets (buf, sizeof(buf), stdin) == NULL) { 41 if (strcmp(line, "end") == 0) {
49 bb_error_msg("%s: Short file", inname); 42 return(EXIT_SUCCESS);
50 return FALSE; 43 }
51 } 44 length = ((*line_ptr - 0x20) & 0x3f)* 4 / 3;
52 p = buf; 45
53 46 if (length <= 0) {
54 /* N is used to avoid writing out all the characters at the end of 47 /* Ignore the "`\n" line, why is it even in the encode file ? */
55 the file. */ 48 continue;
56 n = DEC (*p); 49 }
57 if (n <= 0) 50 if (length > 60) {
58 break; 51 bb_error_msg_and_die("Line too long");
59 for (++p; n > 0; p += 4, n -= 3) { 52 }
60 char ch; 53
61 54 line_ptr++;
62 if (n >= 3) { 55 /* Tolerate an overly long line to acomadate a possible exta '`' */
63 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; 56 if (strlen(line_ptr) < length) {
64 putchar (ch); 57 bb_error_msg_and_die("Short file");
65 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; 58 }
66 putchar (ch); 59
67 ch = DEC (p[2]) << 6 | DEC (p[3]); 60 while (length > 0) {
68 putchar (ch); 61 /* Merge four 6 bit chars to three 8 bit chars */
69 } else { 62 fputc(((line_ptr[0] - 0x20) & 077) << 2 | ((line_ptr[1] - 0x20) & 077) >> 4, dst_stream);
70 if (n >= 1) { 63 line_ptr++;
71 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; 64 length--;
72 putchar (ch); 65 if (length == 0) {
73 } 66 break;
74 if (n >= 2) { 67 }
75 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; 68
76 putchar (ch); 69 fputc(((line_ptr[0] - 0x20) & 077) << 4 | ((line_ptr[1] - 0x20) & 077) >> 2, dst_stream);
77 } 70 line_ptr++;
78 } 71 length--;
79 } 72 if (length == 0) {
80 } 73 break;
81 74 }
82 if (fgets (buf, sizeof(buf), stdin) == NULL 75
83 || strcmp (buf, "end\n")) { 76 fputc(((line_ptr[0] - 0x20) & 077) << 6 | ((line_ptr[1] - 0x20) & 077), dst_stream);
84 bb_error_msg("%s: No `end' line", inname); 77 line_ptr += 2;
85 return FALSE; 78 length -= 2;
86 } 79 }
87 80 free(line);
88 return TRUE; 81 }
82 bb_error_msg_and_die("Short file");
89} 83}
90 84
91static int read_base64 (const char *inname) 85static int read_base64(FILE *src_stream, FILE *dst_stream)
92{ 86{
93 static const char b64_tab[256] = { 87 const char *base64_table =
94 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/ 88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n";
95 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/ 89 char term_count = 0;
96 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/ 90
97 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/ 91 while (1) {
98 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/ 92 char translated[4];
99 '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/ 93 int count = 0;
100 '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/ 94
101 '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/ 95 while (count < 4) {
102 '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/ 96 char *table_ptr;
103 '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/ 97 char ch;
104 '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/ 98
105 '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/ 99 /* Get next _valid_ character */
106 '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/ 100 do {
107 '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/ 101 ch = fgetc(src_stream);
108 '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/ 102 if (ch == EOF) {
109 '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/ 103 bb_error_msg_and_die("Short file");
110 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/ 104 }
111 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/ 105 } while ((table_ptr = strchr(base64_table, ch)) == NULL);
112 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/ 106
113 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/ 107 /* Convert encoded charcter to decimal */
114 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/ 108 ch = table_ptr - base64_table;
115 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/ 109
116 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/ 110 if (*table_ptr == '=') {
117 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/ 111 if (term_count == 0) {
118 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/ 112 translated[count] = 0;
119 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/ 113 break;
120 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/ 114 }
121 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/ 115 term_count++;
122 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/ 116 }
123 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/ 117 else if (*table_ptr == '\n') {
124 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/ 118 /* Check for terminating line */
125 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/ 119 if (term_count == 5) {
126 }; 120 return(EXIT_SUCCESS);
127 unsigned char buf[2 * BUFSIZ]; 121 }
128 122 term_count = 1;
129 while (1) { 123 continue;
130 int last_data = 0; 124 } else {
131 unsigned char *p; 125 translated[count] = ch;
132 126 count++;
133 if (fgets (buf, sizeof(buf), stdin) == NULL) { 127 term_count = 0;
134 bb_error_msg("%s: Short file", inname); 128 }
135 return FALSE; 129 }
136 } 130
137 p = buf; 131 /* Merge 6 bit chars to 8 bit */
138 132 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
139 if (memcmp (buf, "====", 4) == 0) 133 if (count > 2) {
140 break; 134 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
141 if (last_data != 0) { 135 }
142 bb_error_msg("%s: data following `=' padding character", inname); 136 if (count > 3) {
143 return FALSE; 137 fputc(translated[2] << 6 | translated[3], dst_stream);
144 } 138 }
145 139 }
146 /* The following implementation of the base64 decoding might look
147 a bit clumsy but I only try to follow the POSIX standard:
148 ``All line breaks or other characters not found in the table
149 [with base64 characters] shall be ignored by decoding
150 software.'' */
151 while (*p != '\n') {
152 char c1, c2, c3;
153
154 while ((b64_tab[*p] & '\100') != 0)
155 if (*p == '\n' || *p++ == '=')
156 break;
157 if (*p == '\n')
158 /* This leaves the loop. */
159 continue;
160 c1 = b64_tab[*p++];
161
162 while ((b64_tab[*p] & '\100') != 0)
163 if (*p == '\n' || *p++ == '=') {
164 bb_error_msg("%s: illegal line", inname);
165 return FALSE;
166 }
167 c2 = b64_tab[*p++];
168
169 while (b64_tab[*p] == '\177')
170 if (*p++ == '\n') {
171 bb_error_msg("%s: illegal line", inname);
172 return FALSE;
173 }
174 if (*p == '=') {
175 putchar (c1 << 2 | c2 >> 4);
176 last_data = 1;
177 break;
178 }
179 c3 = b64_tab[*p++];
180
181 while (b64_tab[*p] == '\177')
182 if (*p++ == '\n') {
183 bb_error_msg("%s: illegal line", inname);
184 return FALSE;
185 }
186 putchar (c1 << 2 | c2 >> 4);
187 putchar (c2 << 4 | c3 >> 2);
188 if (*p == '=') {
189 last_data = 1;
190 break;
191 }
192 else
193 putchar (c3 << 6 | b64_tab[*p++]);
194 }
195 }
196
197 return TRUE;
198} 140}
199 141
200static int decode (const char *inname, 142extern int uudecode_main(int argc, char **argv)
201 const char *forced_outname)
202{ 143{
203 struct passwd *pw; 144 int (*decode_fn_ptr) (FILE * src, FILE * dst);
204 register char *p; 145 FILE *src_stream;
205 int mode; 146 char *outname = NULL;
206 char buf[2 * BUFSIZ]; 147 char *line;
207 char *outname; 148 int opt;
208 int do_base64 = 0; 149
209 int res; 150 opt = bb_getopt_ulflags(argc, argv, "o:", &outname);
210 int dofre; 151
211 152 if (optind == argc) {
212 /* Search for header line. */ 153 src_stream = stdin;
213 154 } else if (optind + 1 == argc) {
214 while (1) { 155 src_stream = bb_xfopen(argv[optind], "r");
215 if (fgets (buf, sizeof (buf), stdin) == NULL) { 156 } else {
216 bb_error_msg("%s: No `begin' line", inname); 157 bb_show_usage();
217 return FALSE; 158 }
218 } 159
219 160 /* Search for the start of the encoding */
220 if (strncmp (buf, "begin", 5) == 0) { 161 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
221 if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) { 162 char *line_ptr = NULL;
222 do_base64 = 1; 163
223 break; 164 if (line == NULL) {
224 } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2) 165 break;
225 break; 166 } else if (strncmp(line, "begin-base64 ", 13) == 0) {
226 } 167 line_ptr = line + 13;
227 } 168 decode_fn_ptr = read_base64;
228 169 } else if (strncmp(line, "begin ", 6) == 0) {
229 /* If the output file name is given on the command line this rules. */ 170 line_ptr = line + 6;
230 dofre = FALSE; 171 decode_fn_ptr = read_stduu;
231 if (forced_outname != NULL) 172 }
232 outname = (char *) forced_outname; 173
233 else { 174 if (line_ptr) {
234 /* Handle ~user/file format. */ 175 FILE *dst_stream;
235 if (buf[0] != '~') 176 int mode;
236 outname = buf; 177 int ret;
237 else { 178
238 p = buf + 1; 179 mode = strtoul(line_ptr, NULL, 8);
239 while (*p != '/') 180 if (outname == NULL) {
240 ++p; 181 outname = strchr(line_ptr, ' ');
241 if (*p == '\0') { 182 if ((outname == NULL) || (*outname == '\0')) {
242 bb_error_msg("%s: Illegal ~user", inname); 183 break;
243 return FALSE; 184 }
244 } 185 outname++;
245 *p++ = '\0'; 186 }
246 pw = getpwnam (buf + 1); 187 if (strcmp(outname, "-") == 0) {
247 if (pw == NULL) { 188 dst_stream = stdout;
248 bb_error_msg("%s: No user `%s'", inname, buf + 1); 189 } else {
249 return FALSE; 190 dst_stream = bb_xfopen(outname, "w");
250 } 191 chmod(outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO));
251 outname = concat_path_file(pw->pw_dir, p); 192 }
252 dofre = TRUE; 193 free(line);
253 } 194 ret = decode_fn_ptr(src_stream, dst_stream);
254 } 195 bb_fclose_nonstdin(src_stream);
255 196 return(ret);
256 /* Create output file and set mode. */ 197 }
257 if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0 198 free(line);
258 && (freopen (outname, "w", stdout) == NULL 199 }
259 || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) 200 bb_error_msg_and_die("No `begin' line");
260 )) {
261 bb_perror_msg("%s", outname); /* */
262 if (dofre)
263 free(outname);
264 return FALSE;
265 }
266
267 /* We differenciate decoding standard UU encoding and base64. A
268 common function would only slow down the program. */
269
270 /* For each input line: */
271 if (do_base64)
272 res = read_base64 (inname);
273 else
274 res = read_stduu (inname);
275 if (dofre)
276 free(outname);
277 return res;
278} 201}
279
280int uudecode_main (int argc,
281 char **argv)
282{
283 int opt;
284 int exit_status;
285 const char *outname;
286 outname = NULL;
287
288 while ((opt = getopt(argc, argv, "o:")) != EOF) {
289 switch (opt) {
290 case 0:
291 break;
292
293 case 'o':
294 outname = optarg;
295 break;
296
297 default:
298 bb_show_usage();
299 }
300 }
301
302 if (optind == argc)
303 exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
304 else {
305 exit_status = EXIT_SUCCESS;
306 do {
307 if (freopen (argv[optind], "r", stdin) != NULL) {
308 if (decode (argv[optind], outname) != 0)
309 exit_status = FALSE;
310 } else {
311 bb_perror_msg("%s", argv[optind]);
312 exit_status = EXIT_FAILURE;
313 }
314 optind++;
315 }
316 while (optind < argc);
317 }
318 return(exit_status);
319}
320
321/* Copyright (c) 1983 Regents of the University of California.
322 * All rights reserved.
323 *
324 * Redistribution and use in source and binary forms, with or without
325 * modification, are permitted provided that the following conditions
326 * are met:
327 * 1. Redistributions of source code must retain the above copyright
328 * notice, this list of conditions and the following disclaimer.
329 * 2. Redistributions in binary form must reproduce the above copyright
330 * notice, this list of conditions and the following disclaimer in the
331 * documentation and/or other materials provided with the distribution.
332 *
333 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
334 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
335 *
336 * 4. Neither the name of the University nor the names of its contributors
337 * may be used to endorse or promote products derived from this software
338 * without specific prior written permission.
339 *
340 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
341 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
342 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
343 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
344 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
345 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
346 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
347 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
348 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
349 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
350 * SUCH DAMAGE.
351 */
352
353