1/* base64.c - Encode and decode base64 2 * 3 * Copyright 2014 Rob Landley <rob@landley.net> 4 * 5 * See https://tools.ietf.org/html/rfc4648 6 7// These optflags have to match. Todo: cleanup and collapse together? 8USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) 9USE_BASE32(NEWTOY(base32, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN)) 10 11config BASE64 12 bool "base64" 13 default y 14 help 15 usage: base64 [-di] [-w COLUMNS] [FILE...] 16 17 Encode or decode in base64. 18 19 -d Decode 20 -i Ignore non-alphabetic characters 21 -w Wrap output at COLUMNS (default 76 or 0 for no wrap) 22 23config BASE32 24 bool "base32" 25 default y 26 help 27 usage: base32 [-di] [-w COLUMNS] [FILE...] 28 29 Encode or decode in base32. 30 31 -d Decode 32 -i Ignore non-alphabetic characters 33 -w Wrap output at COLUMNS (default 76 or 0 for no wrap) 34*/ 35 36#define FOR_base64 37#define FORCE_FLAGS 38#include "toys.h" 39 40GLOBALS( 41 long w; 42 unsigned total; 43 unsigned n; // number of bits used in encoding. 5 for base32, 6 for base64 44 unsigned align; // number of bits to align to 45) 46 47static void wraputchar(int c, int *x) 48{ 49 putchar(c); 50 TT.total++; 51 if (TT.w && ++*x == TT.w) { 52 *x = 0; 53 xputc('\n'); 54 }; 55} 56 57static void do_base(int fd, char *name) 58{ 59 int out = 0, bits = 0, x = 0, i, len; 60 char *buf = toybuf+128; 61 62 TT.total = 0; 63 64 for (;;) { 65 // If no more data, flush buffer 66 if (!(len = xread(fd, buf, sizeof(toybuf)-128))) { 67 if (!FLAG(d)) { 68 if (bits) wraputchar(toybuf[out<<(TT.n-bits)], &x); 69 while (TT.total&TT.align) wraputchar('=', &x); 70 if (x) xputc('\n'); 71 } 72 73 return; 74 } 75 76 for (i=0; i<len; i++) { 77 if (FLAG(d)) { 78 if (buf[i] == '=') return; 79 80 if ((x = stridx(toybuf, buf[i])) != -1) { 81 out = (out<<TT.n) + x; 82 bits += TT.n; 83 if (bits >= 8) { 84 putchar(out >> (bits -= 8)); 85 out &= (1<<bits)-1; 86 if (ferror(stdout)) perror_exit(0); 87 } 88 89 continue; 90 } 91 if (buf[i] == '\n' || FLAG(i)) continue; 92 93 break; 94 } else { 95 out = (out<<8) + buf[i]; 96 bits += 8; 97 while (bits >= TT.n) { 98 wraputchar(toybuf[out >> (bits -= TT.n)], &x); 99 out &= (1<<bits)-1; 100 } 101 } 102 } 103 } 104} 105 106void base64_main(void) 107{ 108 TT.n = 6; 109 TT.align = 3; 110 base64_init(toybuf); 111 loopfiles(toys.optargs, do_base); 112} 113 114void base32_main(void) 115{ 116 int i; 117 118 TT.n = 5; 119 TT.align = 7; 120 for (i = 0; i<32; i++) toybuf[i] = i+(i<26 ? 'A' : 24); 121 loopfiles(toys.optargs, do_base); 122} 123