The rounded corners look really dumb at this size.
[wxWidgets.git] / src / common / base64.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/base64.cpp
3 // Purpose: implementation of BASE64 encoding/decoding functions
4 // Author: Charles Reimers, Vadim Zeitlin
5 // Created: 2007-06-18
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #include "wx/wxprec.h"
10
11 #ifdef __BORLANDC__
12 #pragma hdrstop
13 #endif
14
15 #if wxUSE_BASE64
16
17 #include "wx/base64.h"
18
19 size_t
20 wxBase64Encode(char *dst, size_t dstLen, const void *src_, size_t srcLen)
21 {
22 wxCHECK_MSG( src_, wxCONV_FAILED, wxT("NULL input buffer") );
23
24 const unsigned char *src = static_cast<const unsigned char *>(src_);
25
26 static const char b64[] =
27 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
28
29
30 size_t encLen = 0;
31
32 // encode blocks of 3 bytes into 4 base64 characters
33 for ( ; srcLen >= 3; srcLen -= 3, src += 3 )
34 {
35 encLen += 4;
36 if ( dst )
37 {
38 if ( encLen > dstLen )
39 return wxCONV_FAILED;
40
41 *dst++ = b64[src[0] >> 2];
42 *dst++ = b64[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)];
43 *dst++ = b64[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)];
44 *dst++ = b64[src[2] & 0x3f];
45 }
46 }
47
48 // finish with the remaining characters
49 if ( srcLen )
50 {
51 encLen += 4;
52 if ( dst )
53 {
54 if ( encLen > dstLen )
55 return wxCONV_FAILED;
56
57 // we have definitely one and maybe two bytes remaining
58 unsigned char next = srcLen == 2 ? src[1] : 0;
59 *dst++ = b64[src[0] >> 2];
60 *dst++ = b64[((src[0] & 0x03) << 4) | ((next & 0xf0) >> 4)];
61 *dst++ = srcLen == 2 ? b64[((next & 0x0f) << 2)] : '=';
62 *dst = '=';
63 }
64 }
65
66 return encLen;
67 }
68
69 size_t
70 wxBase64Decode(void *dst_, size_t dstLen,
71 const char *src, size_t srcLen,
72 wxBase64DecodeMode mode,
73 size_t *posErr)
74 {
75 wxCHECK_MSG( src, wxCONV_FAILED, wxT("NULL input buffer") );
76
77 unsigned char *dst = static_cast<unsigned char *>(dst_);
78
79 size_t decLen = 0;
80
81 if ( srcLen == wxNO_LEN )
82 srcLen = strlen(src);
83
84 // this table contains the values, in base 64, of all valid characters and
85 // special values WSP or INV for white space and invalid characters
86 // respectively as well as a special PAD value for '='
87 enum
88 {
89 WSP = 200,
90 INV,
91 PAD
92 };
93
94 static const unsigned char decode[256] =
95 {
96 WSP,INV,INV,INV,INV,INV,INV,INV,INV,WSP,WSP,INV,WSP,WSP,INV,INV,
97 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
98 WSP,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,076,INV,INV,INV,077,
99 064,065,066,067,070,071,072,073,074,075,INV,INV,INV,PAD,INV,INV,
100 INV,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016,
101 017,020,021,022,023,024,025,026,027,030,031,INV,INV,INV,INV,INV,
102 INV,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050,
103 051,052,053,054,055,056,057,060,061,062,063,INV,INV,INV,INV,INV,
104 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
105 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
106 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
107 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
108 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
109 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
110 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
111 INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
112 };
113
114 // we decode input by groups of 4 characters but things are complicated by
115 // the fact that there can be whitespace and other junk in it too so keep
116 // record of where exactly we're inside the current quartet in this var
117 int n = 0;
118 unsigned char in[4]; // current quartet
119 bool end = false; // set when we find padding
120 size_t padLen = 0; // length lost to padding
121 const char *p;
122 for ( p = src; srcLen; p++, srcLen-- )
123 {
124 const unsigned char c = decode[static_cast<unsigned char>(*p)];
125 switch ( c )
126 {
127 case WSP:
128 if ( mode == wxBase64DecodeMode_SkipWS )
129 continue;
130 // fall through
131
132 case INV:
133 if ( mode == wxBase64DecodeMode_Relaxed )
134 continue;
135
136 // force the loop to stop and an error to be returned
137 n = -1;
138 srcLen = 1;
139 break;
140
141 case PAD:
142 // set the flag telling us that we're past the end now
143 end = true;
144
145 // there can be either a single '=' at the end of a quartet or
146 // "==" in positions 2 and 3
147 if ( n == 3 )
148 {
149 padLen = 1;
150 in[n++] = '\0';
151 }
152 else if ( (n == 2) && (--srcLen && *++p == '=') )
153 {
154 padLen = 2;
155 in[n++] = '\0';
156 in[n++] = '\0';
157 }
158 else // invalid padding
159 {
160 // force the loop terminate with an error
161 n = -1;
162 srcLen = 1;
163 }
164 break;
165
166 default:
167 if ( end )
168 {
169 // nothing is allowed after the end so provoke error return
170 n = -1;
171 srcLen = 1;
172 break;
173 }
174
175 in[n++] = c;
176 }
177
178 if ( n == 4 )
179 {
180 // got entire block, decode
181 decLen += 3 - padLen;
182 if ( dst )
183 {
184 if ( decLen > dstLen )
185 return wxCONV_FAILED;
186
187 // undo the bit shifting done during encoding
188 *dst++ = in[0] << 2 | in[1] >> 4;
189
190 // be careful to not overwrite the output buffer with NUL pad
191 // bytes
192 if ( padLen != 2 )
193 {
194 *dst++ = in[1] << 4 | in[2] >> 2;
195 if ( !padLen )
196 *dst++ = in[2] << 6 | in[3];
197 }
198 }
199
200 n = 0;
201 }
202 }
203
204 if ( n )
205 {
206 if ( posErr )
207 {
208 // notice that the error was on a previous position as we did one
209 // extra "p++" in the loop line after it
210 *posErr = p - src - 1;
211 }
212
213 return wxCONV_FAILED;
214 }
215
216 return decLen;
217 }
218
219 wxMemoryBuffer wxBase64Decode(const char *src,
220 size_t srcLen,
221 wxBase64DecodeMode mode,
222 size_t *posErr)
223 {
224 wxMemoryBuffer buf;
225 wxCHECK_MSG( src, buf, wxT("NULL input buffer") );
226
227 if ( srcLen == wxNO_LEN )
228 srcLen = strlen(src);
229
230 size_t len = wxBase64DecodedSize(srcLen);
231 len = wxBase64Decode(buf.GetWriteBuf(len), len, src, srcLen, mode, posErr);
232 if ( len == wxCONV_FAILED )
233 len = 0;
234
235 buf.SetDataLen(len);
236
237 return buf;
238 }
239
240 #endif // wxUSE_BASE64