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/
20 #define LINELEN 72 /* Encoded line length (max 76) */
22 typedef unsigned char byte
; /* Byte type */
24 static byte dtable
[256]; /* Encode / decode table */
25 //static char eol[] = "\r\n"; /* End of line sequence */
26 static int errcheck
= TRUE
; /* Check decode input for errors ? */
29 /* INCHAR -- Return next character from input */
33 std::string::const_iterator begin
, end
;
35 base64_input(const std::string
&input
)
36 : begin(input
.begin()), end(input
.end()) {}
48 /* OCHAR -- Output an encoded character, inserting line breaks
53 std::back_insert_iterator
<std::string
> insert
;
54 int linelength
; /* Length of encoded output line */
57 base64_output(std::string
&output
)
58 : insert(back_inserter(output
)),
62 void operator()(int c
)
64 if (linelength
>= LINELEN
) {
69 *insert
++ = (unsigned char) c
;
74 /* ENCODE -- Encode binary file into base64. */
76 static bool encode(base64_input
&inchar
, base64_output
&ochar
)
78 int i
, hiteof
= FALSE
;
80 /* Fill dtable with character encodings. */
82 for (i
= 0; i
< 26; i
++) {
84 dtable
[26 + i
] = 'a' + i
;
86 for (i
= 0; i
< 10; i
++) {
87 dtable
[52 + i
] = '0' + i
;
93 byte igroup
[3], ogroup
[4];
96 igroup
[0] = igroup
[1] = igroup
[2] = 0;
97 for (n
= 0; n
< 3; n
++) {
103 igroup
[n
] = (byte
) c
;
106 ogroup
[0] = dtable
[igroup
[0] >> 2];
107 ogroup
[1] = dtable
[((igroup
[0] & 3) << 4) | (igroup
[1] >> 4)];
108 ogroup
[2] = dtable
[((igroup
[1] & 0xF) << 2) | (igroup
[2] >> 6)];
109 ogroup
[3] = dtable
[igroup
[2] & 0x3F];
111 /* Replace characters in output stream with "=" pad
112 characters if fewer than three characters were
113 read from the end of the input stream. */
121 for (i
= 0; i
< 4; i
++) {
129 /* INSIG -- Return next significant input */
131 static int insig(base64_input
&inchar
)
135 /*CONSTANTCONDITION*/
138 if (c
== EOF
|| (c
> ' ')) {
145 /* DECODE -- Decode base64. */
147 static bool decode(base64_input
&inchar
, base64_output
&ochar
)
151 for (i
= 0; i
< 255; i
++) {
154 for (i
= 'A'; i
<= 'Z'; i
++) {
155 dtable
[i
] = 0 + (i
- 'A');
157 for (i
= 'a'; i
<= 'z'; i
++) {
158 dtable
[i
] = 26 + (i
- 'a');
160 for (i
= '0'; i
<= '9'; i
++) {
161 dtable
[i
] = 52 + (i
- '0');
163 dtable
[(int)'+'] = 62;
164 dtable
[(int)'/'] = 63;
165 dtable
[(int)'='] = 0;
167 /*CONSTANTCONDITION*/
169 byte a
[4], b
[4], o
[3];
171 for (i
= 0; i
< 4; i
++) {
172 int c
= insig(inchar
);
175 // fprintf(stderr, "Input file incomplete.\n");
178 if (dtable
[c
] & 0x80) {
180 //fprintf(stderr, "Illegal character '%c' in input file.\n", c);
183 /* Ignoring errors: discard invalid character. */
188 b
[i
] = (byte
) dtable
[c
];
190 o
[0] = (b
[0] << 2) | (b
[1] >> 4);
191 o
[1] = (b
[1] << 4) | (b
[2] >> 2);
192 o
[2] = (b
[2] << 6) | b
[3];
193 i
= a
[2] == '=' ? 1 : (a
[3] == '=' ? 2 : 3);
194 for (int w
= 0; w
< i
; w
++ )
202 // in-memory encode / decode API
203 bool base64_encode(const std::string
&in
, std::string
&out
)
206 base64_input
input(in
);
207 base64_output
output(out
);
208 return encode(input
, output
);
211 bool base64_decode(const std::string
&in
, std::string
&out
)
214 base64_input
input(in
);
215 base64_output
output(out
);
216 return decode(input
, output
);
229 string test
= "This is a test.", encoded
, decoded
;
230 base64_encode(test
, encoded
);
231 base64_decode(encoded
, decoded
);
232 if( test
!= decoded
)
233 cerr
<< "Test failed" << endl
;
235 cerr
<< "Success" << endl
;