blob: 5823afd903d07fd9fc2d4d51aa49ba65c3015c9c [file] [log] [blame]
Glenn L McGrath7f9de022003-11-06 03:17:23 +00001/*
2 * GPLv2
Glenn L McGrathc6992fe2004-04-25 05:11:19 +00003 * Copyright 2003, Glenn McGrath <bug1@iinet.net.au>
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00004 *
Glenn L McGrath7f9de022003-11-06 03:17:23 +00005 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation; either version 2 of the License.
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00008 *
Glenn L McGrath7f9de022003-11-06 03:17:23 +00009 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000013 *
Glenn L McGrath7f9de022003-11-06 03:17:23 +000014 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Eric Andersen4e573f42000-11-14 23:29:24 +000017 *
Glenn L McGrath7f9de022003-11-06 03:17:23 +000018 * Based on specification from
19 * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
Eric Andersen4e573f42000-11-14 23:29:24 +000020 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +000021 * Bugs: the spec doesnt mention anything about "`\n`\n" prior to the "end" line
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000022 */
23
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000024
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000025#include <stdio.h>
26#include <errno.h>
Rob Landleyb7128c62005-09-11 01:05:30 +000027#include <getopt.h> /* optind */
Eric Andersened3ef502001-01-27 08:24:39 +000028#include <string.h>
29#include <stdlib.h>
"Vladimir N. Oleynik"ba248202005-10-06 15:18:09 +000030#include "busybox.h"
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000031
Glenn L McGrath7f9de022003-11-06 03:17:23 +000032static int read_stduu(FILE *src_stream, FILE *dst_stream)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000033{
Glenn L McGrath7f9de022003-11-06 03:17:23 +000034 char *line;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000035
Glenn L McGrath7f9de022003-11-06 03:17:23 +000036 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
37 int length;
38 char *line_ptr = line;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000039
Glenn L McGrath7f9de022003-11-06 03:17:23 +000040 if (strcmp(line, "end") == 0) {
41 return(EXIT_SUCCESS);
42 }
43 length = ((*line_ptr - 0x20) & 0x3f)* 4 / 3;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000044
Glenn L McGrath7f9de022003-11-06 03:17:23 +000045 if (length <= 0) {
46 /* Ignore the "`\n" line, why is it even in the encode file ? */
47 continue;
48 }
49 if (length > 60) {
50 bb_error_msg_and_die("Line too long");
51 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +000052
Glenn L McGrath7f9de022003-11-06 03:17:23 +000053 line_ptr++;
54 /* Tolerate an overly long line to acomadate a possible exta '`' */
"Vladimir N. Oleynik"87be3162006-01-31 14:25:52 +000055 if (strlen(line_ptr) < (size_t)length) {
Glenn L McGrath7f9de022003-11-06 03:17:23 +000056 bb_error_msg_and_die("Short file");
57 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000058
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000059 while (length > 0) {
Glenn L McGrath7f9de022003-11-06 03:17:23 +000060 /* Merge four 6 bit chars to three 8 bit chars */
"Vladimir N. Oleynik"87be3162006-01-31 14:25:52 +000061 fputc(((line_ptr[0] - 0x20) & 077) << 2 | ((line_ptr[1] - 0x20) & 077) >> 4, dst_stream);
Glenn L McGrath7f9de022003-11-06 03:17:23 +000062 line_ptr++;
63 length--;
64 if (length == 0) {
65 break;
66 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000067
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000068 fputc(((line_ptr[0] - 0x20) & 077) << 4 | ((line_ptr[1] - 0x20) & 077) >> 2, dst_stream);
Glenn L McGrath7f9de022003-11-06 03:17:23 +000069 line_ptr++;
70 length--;
71 if (length == 0) {
72 break;
73 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000074
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000075 fputc(((line_ptr[0] - 0x20) & 077) << 6 | ((line_ptr[1] - 0x20) & 077), dst_stream);
Glenn L McGrath7f9de022003-11-06 03:17:23 +000076 line_ptr += 2;
77 length -= 2;
78 }
79 free(line);
80 }
81 bb_error_msg_and_die("Short file");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000082}
83
Glenn L McGrath7f9de022003-11-06 03:17:23 +000084static int read_base64(FILE *src_stream, FILE *dst_stream)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000085{
"Vladimir N. Oleynik"87be3162006-01-31 14:25:52 +000086 static const char base64_table[] =
Glenn L McGrath7f9de022003-11-06 03:17:23 +000087 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n";
88 char term_count = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000089
Glenn L McGrath7f9de022003-11-06 03:17:23 +000090 while (1) {
91 char translated[4];
92 int count = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000093
Glenn L McGrath7f9de022003-11-06 03:17:23 +000094 while (count < 4) {
95 char *table_ptr;
Eric Andersen5e678872006-01-30 19:48:23 +000096 int ch;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000097
Glenn L McGrath7f9de022003-11-06 03:17:23 +000098 /* Get next _valid_ character */
99 do {
100 ch = fgetc(src_stream);
101 if (ch == EOF) {
102 bb_error_msg_and_die("Short file");
103 }
104 } while ((table_ptr = strchr(base64_table, ch)) == NULL);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000105
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000106 /* Convert encoded charcter to decimal */
107 ch = table_ptr - base64_table;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000108
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000109 if (*table_ptr == '=') {
110 if (term_count == 0) {
111 translated[count] = 0;
112 break;
113 }
114 term_count++;
115 }
116 else if (*table_ptr == '\n') {
117 /* Check for terminating line */
118 if (term_count == 5) {
119 return(EXIT_SUCCESS);
120 }
121 term_count = 1;
122 continue;
123 } else {
124 translated[count] = ch;
125 count++;
126 term_count = 0;
127 }
128 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000129
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000130 /* Merge 6 bit chars to 8 bit */
131 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
132 if (count > 2) {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000133 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000134 }
135 if (count > 3) {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000136 fputc(translated[2] << 6 | translated[3], dst_stream);
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000137 }
138 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000139}
140
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000141extern int uudecode_main(int argc, char **argv)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000142{
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000143 int (*decode_fn_ptr) (FILE * src, FILE * dst);
144 FILE *src_stream;
145 char *outname = NULL;
146 char *line;
147 int opt;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000148
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000149 opt = bb_getopt_ulflags(argc, argv, "o:", &outname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000150
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000151 if (optind == argc) {
152 src_stream = stdin;
153 } else if (optind + 1 == argc) {
154 src_stream = bb_xfopen(argv[optind], "r");
155 } else {
156 bb_show_usage();
157 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000158
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000159 /* Search for the start of the encoding */
160 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
161 char *line_ptr = NULL;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000162
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000163 if (line == NULL) {
164 break;
165 } else if (strncmp(line, "begin-base64 ", 13) == 0) {
166 line_ptr = line + 13;
167 decode_fn_ptr = read_base64;
168 } else if (strncmp(line, "begin ", 6) == 0) {
169 line_ptr = line + 6;
170 decode_fn_ptr = read_stduu;
171 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000172
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000173 if (line_ptr) {
174 FILE *dst_stream;
175 int mode;
176 int ret;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000177
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000178 mode = strtoul(line_ptr, NULL, 8);
179 if (outname == NULL) {
180 outname = strchr(line_ptr, ' ');
181 if ((outname == NULL) || (*outname == '\0')) {
182 break;
183 }
184 outname++;
185 }
186 if (strcmp(outname, "-") == 0) {
187 dst_stream = stdout;
188 } else {
189 dst_stream = bb_xfopen(outname, "w");
190 chmod(outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO));
191 }
192 free(line);
193 ret = decode_fn_ptr(src_stream, dst_stream);
194 bb_fclose_nonstdin(src_stream);
195 return(ret);
196 }
197 free(line);
198 }
199 bb_error_msg_and_die("No `begin' line");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000200}