9cf58b6979
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47594 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
227 lines
6.9 KiB
C++
227 lines
6.9 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// 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 unsigned 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 unsigned char c = decode[wx_static_cast(unsigned char, *p)];
|
|
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
|