xref: /third_party/toybox/toys/other/base64.c (revision 0f66f451)
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