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