maint: added example command in release.sh
[barry.git] / src / base64.cc
blob3d3ccfd7069a8ae7bef79a3a27c4553748ac5aaa
1 /*
2 * Encode or decode file as MIME base64 (RFC 1341)
3 * Public domain by John Walker, August 11 1997
4 * http://www.fourmilab.ch/
5 * Modified slightly for the Citadel/UX system, June 1999
7 * Taken from the Citadel/UX GPL source tree, at version 6.01
8 * Modified into a C++ API by Chris Frey for Net Direct Inc., November 2005
9 * http://www.netdirect.ca/
13 #include "base64.h"
14 #include <string>
15 #include <iterator>
16 #include <stdio.h>
18 #define TRUE 1
19 #define FALSE 0
21 #define LINELEN 72 /* Encoded line length (max 76) */
23 typedef unsigned char byte; /* Byte type */
25 static byte dtable[256]; /* Encode / decode table */
26 //static char eol[] = "\r\n"; /* End of line sequence */
27 static int errcheck = TRUE; /* Check decode input for errors ? */
30 /* INCHAR -- Return next character from input */
32 class base64_input
34 std::string::const_iterator begin, end;
35 public:
36 base64_input(const std::string &input)
37 : begin(input.begin()), end(input.end()) {}
39 int operator()()
41 if (begin == end) {
42 return EOF;
44 return (int)((unsigned int)(unsigned char) *begin++);
49 /* OCHAR -- Output an encoded character, inserting line breaks
50 where required. */
52 class base64_output
54 std::back_insert_iterator<std::string> insert;
55 int linelength; /* Length of encoded output line */
57 public:
58 base64_output(std::string &output)
59 : insert(back_inserter(output)),
60 linelength(0)
63 void operator()(int c)
65 if (linelength >= LINELEN) {
66 *insert++ = '\n';
67 *insert++ = ' ';
68 linelength = 0;
70 *insert++ = (unsigned char) c;
71 linelength++;
75 /* ENCODE -- Encode binary file into base64. */
77 static bool encode(base64_input &inchar, base64_output &ochar)
79 int i, hiteof = FALSE;
81 /* Fill dtable with character encodings. */
83 for (i = 0; i < 26; i++) {
84 dtable[i] = 'A' + i;
85 dtable[26 + i] = 'a' + i;
87 for (i = 0; i < 10; i++) {
88 dtable[52 + i] = '0' + i;
90 dtable[62] = '+';
91 dtable[63] = '/';
93 while (!hiteof) {
94 byte igroup[3], ogroup[4];
95 int c, n;
97 igroup[0] = igroup[1] = igroup[2] = 0;
98 for (n = 0; n < 3; n++) {
99 c = inchar();
100 if (c == EOF) {
101 hiteof = TRUE;
102 break;
104 igroup[n] = (byte) c;
106 if (n > 0) {
107 ogroup[0] = dtable[igroup[0] >> 2];
108 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
109 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
110 ogroup[3] = dtable[igroup[2] & 0x3F];
112 /* Replace characters in output stream with "=" pad
113 characters if fewer than three characters were
114 read from the end of the input stream. */
116 if (n < 3) {
117 ogroup[3] = '=';
118 if (n < 2) {
119 ogroup[2] = '=';
122 for (i = 0; i < 4; i++) {
123 ochar(ogroup[i]);
127 return true;
130 /* INSIG -- Return next significant input */
132 static int insig(base64_input &inchar)
134 int c;
136 /*CONSTANTCONDITION*/
137 while (TRUE) {
138 c = inchar();
139 if (c == EOF || (c > ' ')) {
140 return c;
143 /*NOTREACHED*/
146 /* DECODE -- Decode base64. */
148 static bool decode(base64_input &inchar, base64_output &ochar)
150 int i;
152 for (i = 0; i < 255; i++) {
153 dtable[i] = 0x80;
155 for (i = 'A'; i <= 'Z'; i++) {
156 dtable[i] = 0 + (i - 'A');
158 for (i = 'a'; i <= 'z'; i++) {
159 dtable[i] = 26 + (i - 'a');
161 for (i = '0'; i <= '9'; i++) {
162 dtable[i] = 52 + (i - '0');
164 dtable[(int)'+'] = 62;
165 dtable[(int)'/'] = 63;
166 dtable[(int)'='] = 0;
168 /*CONSTANTCONDITION*/
169 while (TRUE) {
170 byte a[4], b[4], o[3];
172 for (i = 0; i < 4; i++) {
173 int c = insig(inchar);
175 if (c == EOF) {
176 // fprintf(stderr, "Input file incomplete.\n");
177 return false;
179 if (dtable[c] & 0x80) {
180 if (errcheck) {
181 //fprintf(stderr, "Illegal character '%c' in input file.\n", c);
182 return false;
184 /* Ignoring errors: discard invalid character. */
185 i--;
186 continue;
188 a[i] = (byte) c;
189 b[i] = (byte) dtable[c];
191 o[0] = (b[0] << 2) | (b[1] >> 4);
192 o[1] = (b[1] << 4) | (b[2] >> 2);
193 o[2] = (b[2] << 6) | b[3];
194 i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
195 for (int w = 0; w < i; w++ )
196 ochar(o[w]);
197 if (i < 3) {
198 return true;
203 // in-memory encode / decode API
204 bool base64_encode(const std::string &in, std::string &out)
206 out.clear();
207 base64_input input(in);
208 base64_output output(out);
209 return encode(input, output);
212 bool base64_decode(const std::string &in, std::string &out)
214 out.clear();
215 base64_input input(in);
216 base64_output output(out);
217 return decode(input, output);
221 #ifdef __TEST_MODE__
223 #include <iostream>
224 using namespace std;
226 /* Main program */
228 int main()
230 string test = "This is a test.", encoded, decoded;
231 base64_encode(test, encoded);
232 base64_decode(encoded, decoded);
233 if( test != decoded )
234 cerr << "Test failed" << endl;
235 else
236 cerr << "Success" << endl;
239 #endif