busybox/coreutils/uudecode.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Copyright 2003, Glenn McGrath
   4 *
   5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   6 *
   7 * Based on specification from
   8 * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
   9 *
  10 * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the
  11 * "end" line
  12 */
  13
  14//usage:#define uudecode_trivial_usage
  15//usage:       "[-o OUTFILE] [INFILE]"
  16//usage:#define uudecode_full_usage "\n\n"
  17//usage:       "Uudecode a file\n"
  18//usage:       "Finds OUTFILE in uuencoded source unless -o is given"
  19//usage:
  20//usage:#define uudecode_example_usage
  21//usage:       "$ uudecode -o busybox busybox.uu\n"
  22//usage:       "$ ls -l busybox\n"
  23//usage:       "-rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox\n"
  24
  25#include "libbb.h"
  26
  27#if ENABLE_UUDECODE
  28static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags UNUSED_PARAM)
  29{
  30        char *line;
  31
  32        while ((line = xmalloc_fgetline(src_stream)) != NULL) {
  33                int encoded_len, str_len;
  34                char *line_ptr, *dst;
  35
  36                if (strcmp(line, "end") == 0) {
  37                        return; /* the only non-error exit */
  38                }
  39
  40                line_ptr = line;
  41                while (*line_ptr) {
  42                        *line_ptr = (*line_ptr - 0x20) & 0x3f;
  43                        line_ptr++;
  44                }
  45                str_len = line_ptr - line;
  46
  47                encoded_len = line[0] * 4 / 3;
  48                /* Check that line is not too short. (we tolerate
  49                 * overly _long_ line to accomodate possible extra '`').
  50                 * Empty line case is also caught here. */
  51                if (str_len <= encoded_len) {
  52                        break; /* go to bb_error_msg_and_die("short file"); */
  53                }
  54                if (encoded_len <= 0) {
  55                        /* Ignore the "`\n" line, why is it even in the encode file ? */
  56                        free(line);
  57                        continue;
  58                }
  59                if (encoded_len > 60) {
  60                        bb_error_msg_and_die("line too long");
  61                }
  62
  63                dst = line;
  64                line_ptr = line + 1;
  65                do {
  66                        /* Merge four 6 bit chars to three 8 bit chars */
  67                        *dst++ = line_ptr[0] << 2 | line_ptr[1] >> 4;
  68                        encoded_len--;
  69                        if (encoded_len == 0) {
  70                                break;
  71                        }
  72
  73                        *dst++ = line_ptr[1] << 4 | line_ptr[2] >> 2;
  74                        encoded_len--;
  75                        if (encoded_len == 0) {
  76                                break;
  77                        }
  78
  79                        *dst++ = line_ptr[2] << 6 | line_ptr[3];
  80                        line_ptr += 4;
  81                        encoded_len -= 2;
  82                } while (encoded_len > 0);
  83                fwrite(line, 1, dst - line, dst_stream);
  84                free(line);
  85        }
  86        bb_error_msg_and_die("short file");
  87}
  88#endif
  89
  90#if ENABLE_UUDECODE
  91int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  92int uudecode_main(int argc UNUSED_PARAM, char **argv)
  93{
  94        FILE *src_stream;
  95        char *outname = NULL;
  96        char *line;
  97
  98        opt_complementary = "?1"; /* 1 argument max */
  99        getopt32(argv, "o:", &outname);
 100        argv += optind;
 101
 102        if (!argv[0])
 103                *--argv = (char*)"-";
 104        src_stream = xfopen_stdin(argv[0]);
 105
 106        /* Search for the start of the encoding */
 107        while ((line = xmalloc_fgetline(src_stream)) != NULL) {
 108                void FAST_FUNC (*decode_fn_ptr)(FILE *src, FILE *dst, int flags);
 109                char *line_ptr;
 110                FILE *dst_stream;
 111                int mode;
 112
 113                if (strncmp(line, "begin-base64 ", 13) == 0) {
 114                        line_ptr = line + 13;
 115                        decode_fn_ptr = read_base64;
 116                } else if (strncmp(line, "begin ", 6) == 0) {
 117                        line_ptr = line + 6;
 118                        decode_fn_ptr = read_stduu;
 119                } else {
 120                        free(line);
 121                        continue;
 122                }
 123
 124                /* begin line found. decode and exit */
 125                mode = bb_strtou(line_ptr, NULL, 8);
 126                if (outname == NULL) {
 127                        outname = strchr(line_ptr, ' ');
 128                        if (!outname)
 129                                break;
 130                        outname++;
 131                        if (!outname[0])
 132                                break;
 133                }
 134                dst_stream = stdout;
 135                if (NOT_LONE_DASH(outname)) {
 136                        dst_stream = xfopen_for_write(outname);
 137                        fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO));
 138                }
 139                free(line);
 140                decode_fn_ptr(src_stream, dst_stream, /*flags:*/ BASE64_FLAG_UU_STOP + BASE64_FLAG_NO_STOP_CHAR);
 141                /* fclose_if_not_stdin(src_stream); - redundant */
 142                return EXIT_SUCCESS;
 143        }
 144        bb_error_msg_and_die("no 'begin' line");
 145}
 146#endif
 147
 148//applet:IF_BASE64(APPLET(base64, BB_DIR_BIN, BB_SUID_DROP))
 149
 150//kbuild:lib-$(CONFIG_BASE64) += uudecode.o
 151
 152//config:config BASE64
 153//config:       bool "base64"
 154//config:       default y
 155//config:       help
 156//config:         Base64 encode and decode
 157
 158//usage:#define base64_trivial_usage
 159//usage:        "[-d] [FILE]"
 160//usage:#define base64_full_usage "\n\n"
 161//usage:       "Base64 encode or decode FILE to standard output"
 162//usage:     "\n        -d      Decode data"
 163////usage:     "\n      -w COL  Wrap lines at COL (default 76, 0 disables)"
 164////usage:     "\n      -i      When decoding, ignore non-alphabet characters"
 165
 166#if ENABLE_BASE64
 167int base64_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 168int base64_main(int argc UNUSED_PARAM, char **argv)
 169{
 170        FILE *src_stream;
 171        unsigned opts;
 172
 173        opt_complementary = "?1"; /* 1 argument max */
 174        opts = getopt32(argv, "d");
 175        argv += optind;
 176
 177        if (!argv[0])
 178                *--argv = (char*)"-";
 179        src_stream = xfopen_stdin(argv[0]);
 180        if (opts) {
 181                read_base64(src_stream, stdout, /*flags:*/ (char)EOF);
 182        } else {
 183                enum {
 184                        SRC_BUF_SIZE = 76/4*3,  /* This *MUST* be a multiple of 3 */
 185                        DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
 186                };
 187                char src_buf[SRC_BUF_SIZE];
 188                char dst_buf[DST_BUF_SIZE + 1];
 189                int src_fd = fileno(src_stream);
 190                while (1) {
 191                        size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE);
 192                        if (!size)
 193                                break;
 194                        if ((ssize_t)size < 0)
 195                                bb_perror_msg_and_die(bb_msg_read_error);
 196                        /* Encode the buffer we just read in */
 197                        bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
 198                        xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3));
 199                        bb_putchar('\n');
 200                        fflush(stdout);
 201                }
 202        }
 203
 204        fflush_stdout_and_exit(EXIT_SUCCESS);
 205}
 206#endif
 207
 208/* Test script.
 209Put this into an empty dir with busybox binary, an run.
 210
 211#!/bin/sh
 212test -x busybox || { echo "No ./busybox?"; exit; }
 213ln -sf busybox uudecode
 214ln -sf busybox uuencode
 215>A_null
 216echo -n A >A
 217echo -n AB >AB
 218echo -n ABC >ABC
 219echo -n ABCD >ABCD
 220echo -n ABCDE >ABCDE
 221echo -n ABCDEF >ABCDEF
 222cat busybox >A_bbox
 223for f in A*; do
 224    echo uuencode $f
 225    ./uuencode    $f <$f >u_$f
 226    ./uuencode -m $f <$f >m_$f
 227done
 228mkdir unpk_u unpk_m 2>/dev/null
 229for f in u_*; do
 230    ./uudecode <$f -o unpk_u/${f:2}
 231    diff -a ${f:2} unpk_u/${f:2} >/dev/null 2>&1
 232    echo uudecode $f: $?
 233done
 234for f in m_*; do
 235    ./uudecode <$f -o unpk_m/${f:2}
 236    diff -a ${f:2} unpk_m/${f:2} >/dev/null 2>&1
 237    echo uudecode $f: $?
 238done
 239*/
 240