summaryrefslogtreecommitdiff
path: root/busybox/coreutils/uudecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/coreutils/uudecode.c')
-rw-r--r--busybox/coreutils/uudecode.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/busybox/coreutils/uudecode.c b/busybox/coreutils/uudecode.c
new file mode 100644
index 0000000..57d4e83
--- /dev/null
+++ b/busybox/coreutils/uudecode.c
@@ -0,0 +1,201 @@
+/*
+ * GPLv2
+ * Copyright 2003, Glenn McGrath <bug1@iinet.net.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Based on specification from
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
+ *
+ * Bugs: the spec doesnt mention anything about "`\n`\n" prior to the "end" line
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+static int read_stduu(FILE *src_stream, FILE *dst_stream)
+{
+ char *line;
+
+ while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
+ int length;
+ char *line_ptr = line;
+
+ if (strcmp(line, "end") == 0) {
+ return(EXIT_SUCCESS);
+ }
+ length = ((*line_ptr - 0x20) & 0x3f)* 4 / 3;
+
+ if (length <= 0) {
+ /* Ignore the "`\n" line, why is it even in the encode file ? */
+ continue;
+ }
+ if (length > 60) {
+ bb_error_msg_and_die("Line too long");
+ }
+
+ line_ptr++;
+ /* Tolerate an overly long line to acomadate a possible exta '`' */
+ if (strlen(line_ptr) < length) {
+ bb_error_msg_and_die("Short file");
+ }
+
+ while (length > 0) {
+ /* Merge four 6 bit chars to three 8 bit chars */
+ fputc(((line_ptr[0] - 0x20) & 077) << 2 | ((line_ptr[1] - 0x20) & 077) >> 4, dst_stream);
+ line_ptr++;
+ length--;
+ if (length == 0) {
+ break;
+ }
+
+ fputc(((line_ptr[0] - 0x20) & 077) << 4 | ((line_ptr[1] - 0x20) & 077) >> 2, dst_stream);
+ line_ptr++;
+ length--;
+ if (length == 0) {
+ break;
+ }
+
+ fputc(((line_ptr[0] - 0x20) & 077) << 6 | ((line_ptr[1] - 0x20) & 077), dst_stream);
+ line_ptr += 2;
+ length -= 2;
+ }
+ free(line);
+ }
+ bb_error_msg_and_die("Short file");
+}
+
+static int read_base64(FILE *src_stream, FILE *dst_stream)
+{
+ const char *base64_table =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n";
+ char term_count = 0;
+
+ while (1) {
+ char translated[4];
+ int count = 0;
+
+ while (count < 4) {
+ char *table_ptr;
+ char ch;
+
+ /* Get next _valid_ character */
+ do {
+ ch = fgetc(src_stream);
+ if (ch == EOF) {
+ bb_error_msg_and_die("Short file");
+ }
+ } while ((table_ptr = strchr(base64_table, ch)) == NULL);
+
+ /* Convert encoded charcter to decimal */
+ ch = table_ptr - base64_table;
+
+ if (*table_ptr == '=') {
+ if (term_count == 0) {
+ translated[count] = 0;
+ break;
+ }
+ term_count++;
+ }
+ else if (*table_ptr == '\n') {
+ /* Check for terminating line */
+ if (term_count == 5) {
+ return(EXIT_SUCCESS);
+ }
+ term_count = 1;
+ continue;
+ } else {
+ translated[count] = ch;
+ count++;
+ term_count = 0;
+ }
+ }
+
+ /* Merge 6 bit chars to 8 bit */
+ fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
+ if (count > 2) {
+ fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
+ }
+ if (count > 3) {
+ fputc(translated[2] << 6 | translated[3], dst_stream);
+ }
+ }
+}
+
+extern int uudecode_main(int argc, char **argv)
+{
+ int (*decode_fn_ptr) (FILE * src, FILE * dst);
+ FILE *src_stream;
+ char *outname = NULL;
+ char *line;
+ int opt;
+
+ opt = bb_getopt_ulflags(argc, argv, "o:", &outname);
+
+ if (optind == argc) {
+ src_stream = stdin;
+ } else if (optind + 1 == argc) {
+ src_stream = bb_xfopen(argv[optind], "r");
+ } else {
+ bb_show_usage();
+ }
+
+ /* Search for the start of the encoding */
+ while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
+ char *line_ptr = NULL;
+
+ if (line == NULL) {
+ break;
+ } else if (strncmp(line, "begin-base64 ", 13) == 0) {
+ line_ptr = line + 13;
+ decode_fn_ptr = read_base64;
+ } else if (strncmp(line, "begin ", 6) == 0) {
+ line_ptr = line + 6;
+ decode_fn_ptr = read_stduu;
+ }
+
+ if (line_ptr) {
+ FILE *dst_stream;
+ int mode;
+ int ret;
+
+ mode = strtoul(line_ptr, NULL, 8);
+ if (outname == NULL) {
+ outname = strchr(line_ptr, ' ');
+ if ((outname == NULL) || (*outname == '\0')) {
+ break;
+ }
+ outname++;
+ }
+ if (strcmp(outname, "-") == 0) {
+ dst_stream = stdout;
+ } else {
+ dst_stream = bb_xfopen(outname, "w");
+ chmod(outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ }
+ free(line);
+ ret = decode_fn_ptr(src_stream, dst_stream);
+ bb_fclose_nonstdin(src_stream);
+ return(ret);
+ }
+ free(line);
+ }
+ bb_error_msg_and_die("No `begin' line");
+}