blob: 1734ed41964c805bd9a17c59287645567b71b14d [file] [log] [blame]
Glenn L McGrath7f9de022003-11-06 03:17:23 +00001/*
2 * GPLv2
3 * Copyright 2003, Glenn McGrath <bug1@optushome.com.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 *
Glenn L McGrath7f9de022003-11-06 03:17:23 +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>
Eric Andersen999bf722000-07-09 06:59:58 +000027#include <getopt.h>
Eric Andersened3ef502001-01-27 08:24:39 +000028#include <string.h>
29#include <stdlib.h>
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000030
Glenn L McGrath7f9de022003-11-06 03:17:23 +000031#include "libbb.h"
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000032
Glenn L McGrath7f9de022003-11-06 03:17:23 +000033static int read_stduu(FILE *src_stream, FILE *dst_stream)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000034{
Glenn L McGrath7f9de022003-11-06 03:17:23 +000035 char *line;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000036
Glenn L McGrath7f9de022003-11-06 03:17:23 +000037 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
38 int length;
39 char *line_ptr = line;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000040
Glenn L McGrath7f9de022003-11-06 03:17:23 +000041 if (strcmp(line, "end") == 0) {
42 return(EXIT_SUCCESS);
43 }
44 length = ((*line_ptr - 0x20) & 0x3f)* 4 / 3;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000045
Glenn L McGrath7f9de022003-11-06 03:17:23 +000046 if (length <= 0) {
47 /* Ignore the "`\n" line, why is it even in the encode file ? */
48 continue;
49 }
50 if (length > 60) {
51 bb_error_msg_and_die("Line too long");
52 }
53
54 line_ptr++;
55 /* Tolerate an overly long line to acomadate a possible exta '`' */
56 if (strlen(line_ptr) < length) {
57 bb_error_msg_and_die("Short file");
58 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000059
Glenn L McGrath7f9de022003-11-06 03:17:23 +000060 while (length > 0) {
61 /* Merge four 6 bit chars to three 8 bit chars */
62 fputc(((line_ptr[0] - 0x20) & 077) << 2 | ((line_ptr[1] - 0x20) & 077) >> 4, dst_stream);
63 line_ptr++;
64 length--;
65 if (length == 0) {
66 break;
67 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000068
Glenn L McGrath7f9de022003-11-06 03:17:23 +000069 fputc(((line_ptr[0] - 0x20) & 077) << 4 | ((line_ptr[1] - 0x20) & 077) >> 2, dst_stream);
70 line_ptr++;
71 length--;
72 if (length == 0) {
73 break;
74 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000075
Glenn L McGrath7f9de022003-11-06 03:17:23 +000076 fputc(((line_ptr[0] - 0x20) & 077) << 6 | ((line_ptr[1] - 0x20) & 077), dst_stream);
77 line_ptr += 2;
78 length -= 2;
79 }
80 free(line);
81 }
82 bb_error_msg_and_die("Short file");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000083}
84
Glenn L McGrath7f9de022003-11-06 03:17:23 +000085static int read_base64(FILE *src_stream, FILE *dst_stream)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000086{
Glenn L McGrath7f9de022003-11-06 03:17:23 +000087 const char *base64_table =
88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n";
89 char term_count = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000090
Glenn L McGrath7f9de022003-11-06 03:17:23 +000091 while (1) {
92 char translated[4];
93 int count = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000094
Glenn L McGrath7f9de022003-11-06 03:17:23 +000095 while (count < 4) {
96 char *table_ptr;
97 char ch;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000098
Glenn L McGrath7f9de022003-11-06 03:17:23 +000099 /* Get next _valid_ character */
100 do {
101 ch = fgetc(src_stream);
102 if (ch == EOF) {
103 bb_error_msg_and_die("Short file");
104 }
105 } while ((table_ptr = strchr(base64_table, ch)) == NULL);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000106
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000107 /* Convert encoded charcter to decimal */
108 ch = table_ptr - base64_table;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000109
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000110 if (*table_ptr == '=') {
111 if (term_count == 0) {
112 translated[count] = 0;
113 break;
114 }
115 term_count++;
116 }
117 else if (*table_ptr == '\n') {
118 /* Check for terminating line */
119 if (term_count == 5) {
120 return(EXIT_SUCCESS);
121 }
122 term_count = 1;
123 continue;
124 } else {
125 translated[count] = ch;
126 count++;
127 term_count = 0;
128 }
129 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000130
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000131 /* Merge 6 bit chars to 8 bit */
132 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
133 if (count > 2) {
134 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
135 }
136 if (count > 3) {
137 fputc(translated[2] << 6 | translated[3], dst_stream);
138 }
139 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000140}
141
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000142extern int uudecode_main(int argc, char **argv)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000143{
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000144 int (*decode_fn_ptr) (FILE * src, FILE * dst);
145 FILE *src_stream;
146 char *outname = NULL;
147 char *line;
148 int opt;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000149
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000150 opt = bb_getopt_ulflags(argc, argv, "o:", &outname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000151
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000152 if (optind == argc) {
153 src_stream = stdin;
154 } else if (optind + 1 == argc) {
155 src_stream = bb_xfopen(argv[optind], "r");
156 } else {
157 bb_show_usage();
158 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000159
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000160 /* Search for the start of the encoding */
161 while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
162 char *line_ptr = NULL;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000163
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000164 if (line == NULL) {
165 break;
166 } else if (strncmp(line, "begin-base64 ", 13) == 0) {
167 line_ptr = line + 13;
168 decode_fn_ptr = read_base64;
169 } else if (strncmp(line, "begin ", 6) == 0) {
170 line_ptr = line + 6;
171 decode_fn_ptr = read_stduu;
172 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000173
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000174 if (line_ptr) {
175 FILE *dst_stream;
176 int mode;
177 int ret;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000178
Glenn L McGrath7f9de022003-11-06 03:17:23 +0000179 mode = strtoul(line_ptr, NULL, 8);
180 if (outname == NULL) {
181 outname = strchr(line_ptr, ' ');
182 if ((outname == NULL) || (*outname == '\0')) {
183 break;
184 }
185 outname++;
186 }
187 if (strcmp(outname, "-") == 0) {
188 dst_stream = stdout;
189 } else {
190 dst_stream = bb_xfopen(outname, "w");
191 chmod(outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO));
192 }
193 free(line);
194 ret = decode_fn_ptr(src_stream, dst_stream);
195 bb_fclose_nonstdin(src_stream);
196 return(ret);
197 }
198 free(line);
199 }
200 bb_error_msg_and_die("No `begin' line");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000201}