annotate toys/pending/uudecode.c @ 828:1fdaba9a7124

uuencode/decode tests and tweaks from Erich Plondke.
author Rob Landley <rob@landley.net>
date Fri, 22 Mar 2013 00:26:12 -0500
parents 0429050a224b
children 1c61f2827bf8
rev   line source
rob@823 1 /* uudecode.c - uudecode / base64 decode
rob@823 2 *
rob@823 3 * Copyright 2013 Erich Plondke <toybox@erich.wreck.org>
rob@823 4 *
rob@823 5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html
rob@823 6
rob@823 7 USE_UUENCODE(NEWTOY(uudecode, ">2o:", TOYFLAG_USR|TOYFLAG_BIN))
rob@823 8
rob@823 9 config UUDECODE
rob@823 10 bool "uudecode"
rob@823 11 default n
rob@823 12 help
rob@823 13 usage: uudecode [-o outfile] [file]
rob@823 14
rob@823 15 Uudecode or base64-decode stdin or [file], sending output to outfile or
rob@823 16 filename specified by input.
rob@823 17 */
rob@823 18
rob@823 19 #define FOR_uudecode
rob@823 20 #include "toys.h"
rob@823 21
rob@823 22 GLOBALS(
rob@823 23 char *o;
rob@823 24 )
rob@823 25
rob@823 26 /*
rob@823 27 * Turn a character back into a value.
rob@823 28 * The smallest valid character is 0x2B ('+')
rob@823 29 * The biggest valid character is 0x7A ('z')
rob@823 30 * We can make a table of 16*5 entries to cover 0x2B - 0x7A
rob@823 31 */
rob@823 32
rob@823 33 static inline int startswith(const char *a, const char *b)
rob@823 34 {
rob@823 35 return (0==strncmp(a,b,strlen(b)));
rob@823 36 }
rob@823 37
rob@823 38 static inline signed char uudecode_b64_1byte(char in)
rob@823 39 {
rob@823 40 char ret;
rob@823 41 static const signed char table[16*5] = {
rob@823 42 /* '+' (0x2B) is 62, '/'(0x2F) is 63, rest invalid */
rob@823 43 62, -1, -1, -1, 63,
rob@823 44 /* '0'-'9' are values 52-61, rest of 0x3A - 0x3F is invalid, = is special... */
rob@823 45 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
rob@823 46 /* '@' is invalid, 'A'-'Z' are values 0-25, 0x5b - 0x5F are invalid */
rob@823 47 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
rob@823 48 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
rob@823 49 /* '`' is invalid, 'a'-'z' are values 26-51, 0x7B - 0x7F are invalid */
rob@823 50 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
rob@823 51 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
rob@823 52 };
rob@823 53 in &= 0x7f;
rob@823 54 if (in < '+') return -1;
rob@823 55 if (in > 'z') return -1;
rob@823 56 in -= '+';
rob@823 57 ret = table[in];
rob@823 58 return ret;
rob@823 59 };
rob@823 60
rob@823 61
rob@823 62 /* Returns length put in out */
rob@823 63 static int uudecode_b64_4bytes(char *out, const char *in)
rob@823 64 {
rob@823 65 unsigned int i,x=0;
rob@823 66 signed char b0,b1,b2,b3;
rob@823 67 int len = 3;
rob@823 68 b0 = uudecode_b64_1byte(in[0]);
rob@823 69 b1 = uudecode_b64_1byte(in[1]);
rob@823 70 b2 = uudecode_b64_1byte(in[2]);
rob@823 71 b3 = uudecode_b64_1byte(in[3]);
rob@823 72 if ((b1 < 0) || (b0 < 0)) return 0;
rob@823 73 if (b3 < 0) len--;
rob@823 74 if (b2 < 0) len--;
rob@823 75 x = ((b0 & 0x3f)<<18) | ((b1 & 0x3f)<<12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f);
rob@823 76 for (i = 0; i < len; i++) {
rob@823 77 *out++ = (x>>(8*(2-i))) & 0x0ff;
rob@823 78 }
rob@823 79 return len;
rob@823 80 }
rob@823 81
rob@823 82 static void uudecode_b64_line(int ofd, const char *in, int ilen)
rob@823 83 {
rob@823 84 int olen;
rob@823 85 char out[4];
rob@823 86 while (ilen >= 4) {
rob@823 87 olen = uudecode_b64_4bytes(out,in);
rob@823 88 xwrite(ofd,out,olen);
rob@823 89 in += 4;
rob@823 90 ilen -= 4;
rob@823 91 };
rob@823 92 }
rob@823 93
rob@823 94 static void uudecode_b64(int ifd, int ofd)
rob@823 95 {
rob@823 96 int len;
rob@823 97 char *line;
rob@823 98 while ((line = get_line(ifd)) != NULL) {
rob@823 99 if (startswith(line,"====")) return;
rob@823 100 if ((len = strlen(line)) < 4) continue; // skip empty lines
rob@823 101 uudecode_b64_line(ofd,line,len);
rob@823 102 free(line);
rob@823 103 }
rob@823 104 }
rob@823 105
rob@823 106
rob@823 107 static void uudecode_uu_4bytes(char *out, const char *in, int len)
rob@823 108 {
rob@823 109 unsigned int i,x=0;
rob@823 110 for (i = 0; i < 4; i++) {
rob@823 111 x |= ((in[i] - 32) & 0x03f) << (6*(3-i));
rob@823 112 }
rob@823 113 if (len > 3) len = 3;
rob@823 114 for (i = 0; i < len; i++) {
rob@823 115 *out++ = x >> (8*(2-i));
rob@823 116 }
rob@823 117 }
rob@823 118
rob@823 119 static void uudecode_uu_line(int ofd, const char *in)
rob@823 120 {
rob@823 121 int olen = in[0] - 32;
rob@823 122 char buf[4];
rob@823 123 in++;
rob@823 124 while (olen > 0) {
rob@823 125 uudecode_uu_4bytes(buf,in,olen);
rob@823 126 xwrite(ofd,buf,olen < 3 ? olen : 3);
rob@823 127 olen -= 3;
rob@823 128 in += 4;
rob@823 129 }
rob@823 130 }
rob@823 131
rob@823 132 static void uudecode_uu(int ifd, int ofd)
rob@823 133 {
rob@823 134 char *line = NULL;
rob@823 135 while ((line = get_line(ifd)) != NULL) {
rob@823 136 if (line[0] == '`') break;
rob@823 137 if (startswith(line,"end")) break;
rob@823 138 if (strlen(line) < 1) break;
rob@823 139 uudecode_uu_line(ofd,line);
rob@823 140 free(line);
rob@823 141 }
rob@823 142 }
rob@823 143
rob@823 144 void uudecode_main(void)
rob@823 145 {
rob@823 146 char *out_filename = NULL;
rob@823 147 int ifd = 0; /* STDIN */
rob@823 148 int ofd = 1; /* STDOUT */
rob@823 149 char *line;
rob@823 150 char *p,*p2;
rob@823 151 void (*decoder)(int ifd, int ofd) = NULL;
rob@823 152 long mode = 0744;
rob@823 153 if (toys.optc == 1) {
rob@823 154 ifd = xopen(toys.optargs[0],O_RDONLY); // dies if error
rob@823 155 }
rob@823 156 do {
rob@823 157 if ((line = get_line(ifd)) == NULL) perror_exit("empty file");
rob@823 158 } while (strlen(line) == 0); /* skip over empty lines */
rob@823 159 if (startswith(line,"begin ")) decoder = uudecode_uu;
rob@823 160 else if (startswith(line,"begin-base64 ")) decoder = uudecode_b64;
rob@823 161 else perror_exit("not a valid uu- or base64-encoded file");
rob@823 162 for (p = line; !isspace(*p); p++) /* skip first part */;
rob@823 163 for (; isspace(*p); p++) /* skip spaces */;
rob@823 164 mode = strtoul(p,&p2,8);
rob@823 165 p = p2 + 1; /* skip space */
rob@823 166 if (toys.optflags & FLAG_o) {
rob@823 167 out_filename = TT.o;
rob@823 168 } else {
rob@823 169 out_filename = p;
rob@823 170 }
rob@823 171 ofd = xcreate(out_filename,O_WRONLY|O_CREAT|O_TRUNC,mode);
rob@823 172 free(line);
rob@823 173 decoder(ifd,ofd);
rob@828 174 if (TOYBOX_CLEANUP) close(ofd);
rob@823 175 }