--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: src/common/base64.cpp
+// Purpose: implementation of BASE64 encoding/decoding functions
+// Author: Charles Reimers, Vadim Zeitlin
+// Created: 2007-06-18
+// RCS-ID: $Id$
+// Licence: wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#include "wx/wxprec.h"
+
+#if wxUSE_BASE64
+
+#include "wx/base64.h"
+
+size_t
+wxBase64Encode(char *dst, size_t dstLen, const void *src_, size_t srcLen)
+{
+ wxCHECK_MSG( src_, wxCONV_FAILED, _T("NULL input buffer") );
+
+ const unsigned char *src = wx_static_cast(const unsigned char *, src_);
+
+ static const char b64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+ size_t encLen = 0;
+
+ // encode blocks of 3 bytes into 4 base64 characters
+ for ( ; srcLen >= 3; srcLen -= 3, src += 3 )
+ {
+ encLen += 4;
+ if ( dst )
+ {
+ if ( encLen > dstLen )
+ return wxCONV_FAILED;
+
+ *dst++ = b64[src[0] >> 2];
+ *dst++ = b64[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)];
+ *dst++ = b64[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)];
+ *dst++ = b64[src[2] & 0x3f];
+ }
+ }
+
+ // finish with the remaining characters
+ if ( srcLen )
+ {
+ encLen += 4;
+ if ( dst )
+ {
+ if ( encLen > dstLen )
+ return wxCONV_FAILED;
+
+ // we have definitely one and maybe two bytes remaining
+ unsigned char next = srcLen == 2 ? src[1] : 0;
+ *dst++ = b64[src[0] >> 2];
+ *dst++ = b64[((src[0] & 0x03) << 4) | ((next & 0xf0) >> 4)];
+ *dst++ = srcLen == 2 ? b64[((next & 0x0f) << 2)] : '=';
+ *dst = '=';
+ }
+ }
+
+ return encLen;
+}
+
+size_t
+wxBase64Decode(void *dst_, size_t dstLen,
+ const char *src, size_t srcLen,
+ wxBase64DecodeMode mode,
+ size_t *posErr)
+{
+ wxCHECK_MSG( src, wxCONV_FAILED, _T("NULL input buffer") );
+
+ unsigned char *dst = wx_static_cast(unsigned char *, dst_);
+
+ size_t decLen = 0;
+
+ if ( srcLen == wxNO_LEN )
+ srcLen = strlen(src);
+
+ // this table contains the values, in base 64, of all valid characters and
+ // special values WSP or INV for white space and invalid characters
+ // respectively as well as a special PAD value for '='
+ enum
+ {
+ WSP = 200,
+ INV,
+ PAD
+ };
+
+ static const char decode[256] =
+ {
+ WSP,INV,INV,INV,INV,INV,INV,INV,INV,WSP,WSP,INV,WSP,WSP,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ WSP,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,076,INV,INV,INV,077,
+ 064,065,066,067,070,071,072,073,074,075,INV,INV,INV,PAD,INV,INV,
+ INV,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016,
+ 017,020,021,022,023,024,025,026,027,030,031,INV,INV,INV,INV,INV,
+ INV,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050,
+ 051,052,053,054,055,056,057,060,061,062,063,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
+ };
+
+ // we decode input by groups of 4 characters but things are complicated by
+ // the fact that there can be whitespace and other junk in it too so keep
+ // record of where exactly we're inside the current quartet in this var
+ int n = 0;
+ unsigned char in[4]; // current quartet
+ bool end = false; // set when we find padding
+ size_t padLen = 0; // length lost to padding
+ const char *p;
+ for ( p = src; srcLen; p++, srcLen-- )
+ {
+ const char c = decode[(int)*p]; // cast just to suppress warnings
+ switch ( c )
+ {
+ case WSP:
+ if ( mode == wxBase64DecodeMode_SkipWS )
+ continue;
+ // fall through
+
+ case INV:
+ if ( mode == wxBase64DecodeMode_Relaxed )
+ continue;
+
+ // force the loop to stop and an error to be returned
+ n = -1;
+ srcLen = 0;
+ break;
+
+ case PAD:
+ // set the flag telling us that we're past the end now
+ end = true;
+
+ // there can be either a single '=' at the end of a quartet or
+ // "==" in positions 2 and 3
+ if ( n == 3 )
+ {
+ padLen = 1;
+ in[n++] = '\0';
+ }
+ else if ( (n == 2) && (--srcLen && *++p == '=') )
+ {
+ padLen = 2;
+ in[n++] = '\0';
+ in[n++] = '\0';
+ }
+ else // invalid padding
+ {
+ // force the loop terminate with an error
+ n = -1;
+ srcLen = 0;
+ }
+ break;
+
+ default:
+ if ( end )
+ {
+ // nothing is allowed after the end so provoke error return
+ n = -1;
+ srcLen = 0;
+ break;
+ }
+
+ in[n++] = c;
+ }
+
+ if ( n == 4 )
+ {
+ // got entire block, decode
+ decLen += 3 - padLen;
+ if ( dst )
+ {
+ if ( decLen > dstLen )
+ return wxCONV_FAILED;
+
+ // undo the bit shifting done during encoding
+ *dst++ = in[0] << 2 | in[1] >> 4;
+ *dst++ = in[1] << 4 | in[2] >> 2;
+ *dst++ = in[2] << 6 | in[3];
+ }
+
+ n = 0;
+ }
+ }
+
+ if ( n )
+ {
+ if ( posErr )
+ *posErr = p - src;
+
+ return wxCONV_FAILED;
+ }
+
+ return decLen;
+}
+
+wxMemoryBuffer wxBase64Decode(const char *src,
+ size_t srcLen,
+ wxBase64DecodeMode mode,
+ size_t *posErr)
+{
+ wxMemoryBuffer buf;
+ wxCHECK_MSG( src, buf, _T("NULL input buffer") );
+
+ if ( srcLen == wxNO_LEN )
+ srcLen = strlen(src);
+
+ size_t len = wxBase64DecodedSize(srcLen);
+ len = wxBase64Decode(buf.GetWriteBuf(len), len, src, srcLen, mode, posErr);
+ if ( len == wxCONV_FAILED )
+ len = 0;
+
+ buf.SetDataLen(len);
+
+ return buf;
+}
+
+#endif // wxUSE_BASE64