changeset 823:0429050a224b

uuencode and uudecode by Erich Plondke.
author Rob Landley <rob@landley.net>
date Mon, 18 Mar 2013 09:11:21 -0500
parents 84959a5529e8
children 0509ceff26cf
files toys/pending/uudecode.c toys/pending/uuencode.c
diffstat 2 files changed, 290 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/uudecode.c	Mon Mar 18 09:11:21 2013 -0500
@@ -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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/uuencode.c	Mon Mar 18 09:11:21 2013 -0500
@@ -0,0 +1,116 @@
+/* uuencode.c - uuencode / base64 encode
+ *
+ * Copyright 2013 Erich Plondke <toybox@erich.wreck.org>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uuencode.html
+
+USE_UUENCODE(NEWTOY(uuencode, "<1>2m", TOYFLAG_USR|TOYFLAG_BIN))
+
+config UUENCODE
+  bool "uuencode"
+  default n
+  help
+    usage: uuencode [-m] [file] encode-filename
+
+    Uuencode or (with -m option) base64-encode stdin or [file], 
+    with encode-filename in the output, which is sent to stdout.
+*/
+
+#define FOR_uuencode
+#include "toys.h"
+
+
+
+static void uuencode_b64_3bytes(char *out, const char *in, int bytes)
+{
+  static const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                             "abcdefghijklmnopqrstuvwxyz"
+                             "0123456789+/";
+  unsigned int i,x=0;
+  for (i = 0; i < bytes; i++) {
+    x |= (in[i] & 0x0ff) << (8*(2-i));
+  }
+  out[0] = table[(x>>(3*6)) & 0x3f];
+  out[1] = table[(x>>(2*6)) & 0x3f];
+  out[2] = table[(x>>(1*6)) & 0x3f];
+  out[3] = table[(x>>(0*6)) & 0x3f];
+  if (bytes <= 1) out[2] = '=';
+  if (bytes <= 2) out[3] = '=';
+}
+
+static void uuencode_b64_line(char *out, const char *in, int len)
+{
+  while (len > 0) {
+    uuencode_b64_3bytes(out,in,len < 3 ? len : 3);
+    xprintf("%c%c%c%c",out[0],out[1],out[2],out[3]);
+    in += 3;
+    len -= 3;
+  };
+  xprintf("\n");
+}
+
+static void uuencode_b64(int fd, const char *name)
+{
+  int len;
+  char *inbuf = toybuf;
+  char *outbuf = toybuf+64;
+  xprintf("begin-base64 744 %s\n",name);
+  do {
+    len = xread(fd,inbuf,48);
+    uuencode_b64_line(outbuf,inbuf,len);
+  } while (len > 0);
+  xprintf("====\n");
+}
+
+
+static void uuencode_uu_3bytes(char *out, const char *in)
+{
+  unsigned int i,x=0;
+  for (i = 0; i <= 2; i++) {
+    x |= (in[i] & 0x0ff) << (8*(2-i));
+  }
+  for (i = 0; i <= 3; i++) {
+    out[i] = 32 + ((x >> (6*(3-i))) & 0x3f);
+  }
+}
+
+static void uuencode_uu_line(char *out, const char *in, int len)
+{
+  int i;
+  if (len == 0) {
+    xprintf("`\n");
+    return;
+  }
+  xprintf("%c",len+32);
+  for (i = 0; i < len; i += 3) {
+    uuencode_uu_3bytes(out,in+i);
+    xprintf("%c%c%c%c",out[0],out[1],out[2],out[3]);
+  }
+  xprintf("\n");
+}
+
+static void uuencode_uu(int fd, const char *name)
+{
+  int len;
+  char *inbuf = toybuf;
+  char *outbuf = toybuf+64;
+  xprintf("begin 744 %s\n",name);
+  do {
+    len = xread(fd,inbuf,45);
+    uuencode_uu_line(outbuf,inbuf,len);
+  } while (len > 0);
+  xprintf("end\n");
+}
+
+void uuencode_main(void)
+{
+  char *encode_filename = toys.optargs[0];
+  int fd = 0; /* STDIN */
+
+  if (toys.optc == 2) {
+    fd = xopen(toys.optargs[0],O_RDONLY); // dies if error
+    encode_filename = toys.optargs[1];
+  }
+  if (toys.optflags & FLAG_m) uuencode_b64(fd,encode_filename);
+  else uuencode_uu(fd,encode_filename);
+}