Files
wxWidgets/src/common/base64.cpp
Vadim Zeitlin 07890fbeb5 Never overflow the output buffer in wxBase64Decode().
Don't write extra NUL bytes obtained by decoding the padding at the end of
input into the output buffer as there may be not enough place in it for them.
And in any case the buffer is not (always) NUL-terminated as no NUL bytes are
obtained in absence of padding, so it's better to never terminate it for
consistency.

Closes #11101.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61753 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2009-08-23 22:25:12 +00:00

242 lines
7.3 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"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#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, wxT("NULL input buffer") );
const unsigned char *src = 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, wxT("NULL input buffer") );
unsigned char *dst = 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[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 = 1;
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 = 1;
}
break;
default:
if ( end )
{
// nothing is allowed after the end so provoke error return
n = -1;
srcLen = 1;
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;
// be careful to not overwrite the output buffer with NUL pad
// bytes
if ( padLen != 2 )
{
*dst++ = in[1] << 4 | in[2] >> 2;
if ( !padLen )
*dst++ = in[2] << 6 | in[3];
}
}
n = 0;
}
}
if ( n )
{
if ( posErr )
{
// notice that the error was on a previous position as we did one
// extra "p++" in the loop line after it
*posErr = p - src - 1;
}
return wxCONV_FAILED;
}
return decLen;
}
wxMemoryBuffer wxBase64Decode(const char *src,
size_t srcLen,
wxBase64DecodeMode mode,
size_t *posErr)
{
wxMemoryBuffer buf;
wxCHECK_MSG( src, buf, wxT("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