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?
8 USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
9 USE_BASE32(NEWTOY(base32, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
10 
11 config 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 
23 config 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 
GLOBALS(long w;unsigned total;unsigned n;unsigned align;)40 GLOBALS(
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 
47 static 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 
do_base(int fd,char * name)57 static 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 
base64_main(void)106 void base64_main(void)
107 {
108   TT.n = 6;
109   TT.align = 3;
110   base64_init(toybuf);
111   loopfiles(toys.optargs, do_base);
112 }
113 
base32_main(void)114 void 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