diff options
Diffstat (limited to 'toys/pending/uudecode.c')
-rw-r--r-- | toys/pending/uudecode.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/toys/pending/uudecode.c b/toys/pending/uudecode.c new file mode 100644 index 00000000..71774ea2 --- /dev/null +++ b/toys/pending/uudecode.c @@ -0,0 +1,174 @@ +/* uudecode.c - uudecode / base64 decode + * + * Copyright 2013 Erich Plondke <toybox@erich.wreck.org> + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html + +USE_UUENCODE(NEWTOY(uudecode, ">2o:", TOYFLAG_USR|TOYFLAG_BIN)) + +config UUDECODE + bool "uudecode" + default n + help + usage: uudecode [-o outfile] [file] + + Uudecode or base64-decode stdin or [file], sending output to outfile or + filename specified by input. +*/ + +#define FOR_uudecode +#include "toys.h" + +GLOBALS( + char *o; +) + +/* + * Turn a character back into a value. + * The smallest valid character is 0x2B ('+') + * The biggest valid character is 0x7A ('z') + * We can make a table of 16*5 entries to cover 0x2B - 0x7A + */ + +static inline int startswith(const char *a, const char *b) +{ + return (0==strncmp(a,b,strlen(b))); +} + +static inline signed char uudecode_b64_1byte(char in) +{ + char ret; + static const signed char table[16*5] = { + /* '+' (0x2B) is 62, '/'(0x2F) is 63, rest invalid */ + 62, -1, -1, -1, 63, + /* '0'-'9' are values 52-61, rest of 0x3A - 0x3F is invalid, = is special... */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + /* '@' is invalid, 'A'-'Z' are values 0-25, 0x5b - 0x5F are invalid */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + /* '`' is invalid, 'a'-'z' are values 26-51, 0x7B - 0x7F are invalid */ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + in &= 0x7f; + if (in < '+') return -1; + if (in > 'z') return -1; + in -= '+'; + ret = table[in]; + return ret; +}; + + +/* Returns length put in out */ +static int uudecode_b64_4bytes(char *out, const char *in) +{ + unsigned int i,x=0; + signed char b0,b1,b2,b3; + int len = 3; + b0 = uudecode_b64_1byte(in[0]); + b1 = uudecode_b64_1byte(in[1]); + b2 = uudecode_b64_1byte(in[2]); + b3 = uudecode_b64_1byte(in[3]); + if ((b1 < 0) || (b0 < 0)) return 0; + if (b3 < 0) len--; + if (b2 < 0) len--; + x = ((b0 & 0x3f)<<18) | ((b1 & 0x3f)<<12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f); + for (i = 0; i < len; i++) { + *out++ = (x>>(8*(2-i))) & 0x0ff; + } + return len; +} + +static void uudecode_b64_line(int ofd, const char *in, int ilen) +{ + int olen; + char out[4]; + while (ilen >= 4) { + olen = uudecode_b64_4bytes(out,in); + xwrite(ofd,out,olen); + in += 4; + ilen -= 4; + }; +} + +static void uudecode_b64(int ifd, int ofd) +{ + int len; + char *line; + while ((line = get_line(ifd)) != NULL) { + if (startswith(line,"====")) return; + if ((len = strlen(line)) < 4) continue; // skip empty lines + uudecode_b64_line(ofd,line,len); + free(line); + } +} + + +static void uudecode_uu_4bytes(char *out, const char *in, int len) +{ + unsigned int i,x=0; + for (i = 0; i < 4; i++) { + x |= ((in[i] - 32) & 0x03f) << (6*(3-i)); + } + if (len > 3) len = 3; + for (i = 0; i < len; i++) { + *out++ = x >> (8*(2-i)); + } +} + +static void uudecode_uu_line(int ofd, const char *in) +{ + int olen = in[0] - 32; + char buf[4]; + in++; + while (olen > 0) { + uudecode_uu_4bytes(buf,in,olen); + xwrite(ofd,buf,olen < 3 ? olen : 3); + olen -= 3; + in += 4; + } +} + +static void uudecode_uu(int ifd, int ofd) +{ + char *line = NULL; + while ((line = get_line(ifd)) != NULL) { + if (line[0] == '`') break; + if (startswith(line,"end")) break; + if (strlen(line) < 1) break; + uudecode_uu_line(ofd,line); + free(line); + } +} + +void uudecode_main(void) +{ + char *out_filename = NULL; + int ifd = 0; /* STDIN */ + int ofd = 1; /* STDOUT */ + char *line; + char *p,*p2; + void (*decoder)(int ifd, int ofd) = NULL; + long mode = 0744; + if (toys.optc == 1) { + ifd = xopen(toys.optargs[0],O_RDONLY); // dies if error + } + do { + if ((line = get_line(ifd)) == NULL) perror_exit("empty file"); + } while (strlen(line) == 0); /* skip over empty lines */ + if (startswith(line,"begin ")) decoder = uudecode_uu; + else if (startswith(line,"begin-base64 ")) decoder = uudecode_b64; + else perror_exit("not a valid uu- or base64-encoded file"); + for (p = line; !isspace(*p); p++) /* skip first part */; + for (; isspace(*p); p++) /* skip spaces */; + mode = strtoul(p,&p2,8); + p = p2 + 1; /* skip space */ + if (toys.optflags & FLAG_o) { + out_filename = TT.o; + } else { + out_filename = p; + } + ofd = xcreate(out_filename,O_WRONLY|O_CREAT|O_TRUNC,mode); + free(line); + decoder(ifd,ofd); +} |