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/
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 */
34 std::string::const_iterator begin
, end
;
36 base64_input(const std::string
&input
)
37 : begin(input
.begin()), end(input
.end()) {}
44 return (int)((unsigned int)(unsigned char) *begin
++);
49 /* OCHAR -- Output an encoded character, inserting line breaks
54 std::back_insert_iterator
<std::string
> insert
;
55 int linelength
; /* Length of encoded output line */
58 base64_output(std::string
&output
)
59 : insert(back_inserter(output
)),
63 void operator()(int c
)
65 if (linelength
>= LINELEN
) {
70 *insert
++ = (unsigned char) c
;
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
++) {
85 dtable
[26 + i
] = 'a' + i
;
87 for (i
= 0; i
< 10; i
++) {
88 dtable
[52 + i
] = '0' + i
;
94 byte igroup
[3], ogroup
[4];
97 igroup
[0] = igroup
[1] = igroup
[2] = 0;
98 for (n
= 0; n
< 3; n
++) {
104 igroup
[n
] = (byte
) c
;
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. */
122 for (i
= 0; i
< 4; i
++) {
130 /* INSIG -- Return next significant input */
132 static int insig(base64_input
&inchar
)
136 /*CONSTANTCONDITION*/
139 if (c
== EOF
|| (c
> ' ')) {
146 /* DECODE -- Decode base64. */
148 static bool decode(base64_input
&inchar
, base64_output
&ochar
)
152 for (i
= 0; i
< 255; i
++) {
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*/
170 byte a
[4], b
[4], o
[3];
172 for (i
= 0; i
< 4; i
++) {
173 int c
= insig(inchar
);
176 // fprintf(stderr, "Input file incomplete.\n");
179 if (dtable
[c
] & 0x80) {
181 //fprintf(stderr, "Illegal character '%c' in input file.\n", c);
184 /* Ignoring errors: discard invalid character. */
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
++ )
203 // in-memory encode / decode API
204 bool base64_encode(const std::string
&in
, std::string
&out
)
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
)
215 base64_input
input(in
);
216 base64_output
output(out
);
217 return decode(input
, output
);
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
;
236 cerr
<< "Success" << endl
;