base 64 编解码


1. base64的编码都是按字符串长度,以每3个8bit的字符为一组,


2. 然后针对每组。首先获取每一个字符的ASCII编码。


3. 然后将ASCII编码转换成8bit的二进制,得到一组3*8=24bit的字节


4. 然后再将这24bit划分为4个6bit的字节,并在每一个6bit的字节前面都填两个高位0。得到4个8bit的字节


5. 然后将这4个8bit的字节转换成10进制。对比Base64编码表 (下表)。得到相应编码后的字符。


watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHVoZWF6eA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">


实现:

//////////////////////////////////////////////////////////////////////
//
// base64 Encoding/Decoding:
// Encoding: String2Base64: unsigned char * to base64;
// Decoding: Base642TString: base64 to unsigned char * .
//
// xuhh
// Dec 11, 2014
//
////////////////////////////////////////////////////////////////////// #if !defined(_MIME_CODING_H)
#define _MIME_CODING_H #if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 #include <utility>
#include <string>
#include <list>
using namespace std; #if !defined(ASSERT)
#if defined(_DEBUG)
#include <assert.h>
#define ASSERT(exp) assert(exp)
#else
#define ASSERT(exp) ((void)0)
#endif
#endif #if defined(_DEBUG) && !defined(DEBUG_NEW)
#define DEBUG_NEW new
#endif // maximum length of an encoded line (RFC 2045)
#define MAX_MIME_LINE_LEN 76
#define MAX_ENCODEDWORD_LEN 75 //////////////////////////////////////////////////////////////////////
// string to base64 extern unsigned char * String2Base64(const char* str); //////////////////////////////////////////////////////////////////////
// base64 to string extern unsigned char * Base642TString(const char* str); //////////////////////////////////////////////////////////////////////
// CMimeEnvironment - global environment to manage encoding/decoding class CMimeCodeBase; #define DECLARE_MIMECODER(class_name) \
public: static CMimeCodeBase* CreateObject() { return new class_name; } //////////////////////////////////////////////////////////////////////
// CMimeCodeBase class CMimeCodeBase
{
public:
CMimeCodeBase() :
m_pbInput(NULL),
m_nInputSize(0),
m_bIsEncoding(false) {} public:
void SetInput(const char* pbInput, int nInputSize, bool bEncoding)
{
m_pbInput = (const unsigned char*) pbInput;
m_nInputSize = nInputSize;
m_bIsEncoding = bEncoding;
}
int GetOutputLength() const
{
return m_bIsEncoding ? GetEncodeLength() : GetDecodeLength();
}
int GetOutput(unsigned char* pbOutput, int nMaxSize)
{
return m_bIsEncoding ? Encode(pbOutput, nMaxSize) : Decode(pbOutput, nMaxSize);
} protected:
// overrides
virtual int GetEncodeLength() const { return m_nInputSize; }
virtual int GetDecodeLength() const { return m_nInputSize; }
virtual int Encode(unsigned char* pbOutput, int nMaxSize) const
{
int nSize = min(nMaxSize, m_nInputSize);
::memcpy(pbOutput, m_pbInput, nSize);
return nSize;
}
virtual int Decode(unsigned char* pbOutput, int nMaxSize)
{
return CMimeCodeBase::Encode(pbOutput, nMaxSize);
} protected:
const unsigned char* m_pbInput;
int m_nInputSize;
bool m_bIsEncoding;
}; //////////////////////////////////////////////////////////////////////
// CMimeCodeBase64 - for base64 encoding mechanism class CMimeCodeBase64 : public CMimeCodeBase
{
public:
CMimeCodeBase64() :
m_bAddLineBreak(true) {} public:
DECLARE_MIMECODER(CMimeCodeBase64)
void AddLineBreak(bool bAdd=true) { m_bAddLineBreak = bAdd; } protected:
virtual int GetEncodeLength() const;
virtual int GetDecodeLength() const;
virtual int Encode(unsigned char* pbOutput, int nMaxSize) const;
virtual int Decode(unsigned char* pbOutput, int nMaxSize); private:
bool m_bAddLineBreak; private:
static inline int DecodeBase64Char(unsigned int nCode)
{
if (nCode >= 'A' && nCode <= 'Z')
return nCode - 'A';
if (nCode >= 'a' && nCode <= 'z')
return nCode - 'a' + 26;
if (nCode >= '0' && nCode <= '9')
return nCode - '0' + 52;
if (nCode == '+')
return 62;
if (nCode == '/')
return 63;
return 64;
}
}; #endif // !defined(_MIME_CODING_H)


实现文件:



//////////////////////////////////////////////////////////////////////
//
// base64 Encoding/Decoding:
// Encoding: String2Base64: unsigned char * to base64;
// Decoding: Base642TString: base64 to unsigned char * .
//
// xuhh
// Dec 11, 2014
//
//////////////////////////////////////////////////////////////////////
#include "MimeCode.h" #ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif //////////////////////////////////////////////////////////////////////////
// string to base64
unsigned char* String2Base64(const char * szStr)
{
CMimeCodeBase64 base64;
base64.SetInput(szStr, strlen(szStr), true);
int nLen = base64.GetOutputLength()+1;
unsigned char* pOutput = new unsigned char[nLen];
nLen = base64.GetOutput(pOutput, nLen);
pOutput[nLen] = 0;
return pOutput;
} //////////////////////////////////////////////////////////////////////////
// base64 to string unsigned char * Base642TString(const char* str)
{
CMimeCodeBase64 base64;
base64.SetInput(str, strlen(str), false);
int len = base64.GetOutputLength()+1;
unsigned char* pOutput = new unsigned char[len];
len = base64.GetOutput(pOutput, len);
pOutput[len] = 0;
return pOutput;
} //////////////////////////////////////////////////////////////////////
// CMimeCodeBase64 int CMimeCodeBase64::GetEncodeLength() const
{
int nLength = (m_nInputSize + 2) / 3 * 4;
if (m_bAddLineBreak)
nLength += (nLength / MAX_MIME_LINE_LEN + 1) * 2;
return nLength;
} int CMimeCodeBase64::GetDecodeLength() const
{
return m_nInputSize * 3 / 4 + 2;
} int CMimeCodeBase64::Encode(unsigned char* pbOutput, int nMaxSize) const
{
static const char* s_Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; unsigned char* pbOutStart = pbOutput;
unsigned char* pbOutEnd = pbOutput + nMaxSize;
int nFrom, nLineLen = 0;
unsigned char chHigh4bits = 0; for (nFrom=0; nFrom<m_nInputSize; nFrom++)
{
if (pbOutput >= pbOutEnd)
break; unsigned char ch = m_pbInput[nFrom];
switch (nFrom % 3)
{
case 0:
*pbOutput++ = s_Base64Table[ch >> 2];
chHigh4bits = (ch << 4) & 0x30;
break; case 1:
*pbOutput++ = s_Base64Table[chHigh4bits | (ch >> 4)];
chHigh4bits = (ch << 2) & 0x3c;
break; default:
*pbOutput++ = s_Base64Table[chHigh4bits | (ch >> 6)];
if (pbOutput < pbOutEnd)
{
*pbOutput++ = s_Base64Table[ch & 0x3f];
nLineLen++;
}
} nLineLen++;
if (m_bAddLineBreak && nLineLen >= MAX_MIME_LINE_LEN && pbOutput+2 <= pbOutEnd)
{
*pbOutput++ = '\r';
*pbOutput++ = '\n';
nLineLen = 0;
}
} if (nFrom % 3 != 0 && pbOutput < pbOutEnd) // 不足三位。= 补足
{
*pbOutput++ = s_Base64Table[chHigh4bits];
int nPad = 4 - (nFrom % 3) - 1;
if (pbOutput+nPad <= pbOutEnd)
{
::memset(pbOutput, '=', nPad);
pbOutput += nPad;
}
}
if (m_bAddLineBreak && nLineLen != 0 && pbOutput+2 <= pbOutEnd)
{
*pbOutput++ = '\r';
*pbOutput++ = '\n';
}
return (int)(pbOutput - pbOutStart);
} int CMimeCodeBase64::Decode(unsigned char* pbOutput, int nMaxSize)
{
const unsigned char* pbData = m_pbInput;
const unsigned char* pbEnd = m_pbInput + m_nInputSize;
unsigned char* pbOutStart = pbOutput;
unsigned char* pbOutEnd = pbOutput + nMaxSize; int nFrom = 0;
unsigned char chHighBits = 0; while (pbData < pbEnd)
{
if (pbOutput >= pbOutEnd)
break; unsigned char ch = *pbData++;
if (ch == '\r' || ch == '\n')
continue;
ch = (unsigned char) DecodeBase64Char(ch);
if (ch >= 64) // invalid encoding, or trailing pad '='
break; switch ((nFrom++) % 4)
{
case 0:
chHighBits = ch << 2;
break; case 1:
*pbOutput++ = chHighBits | (ch >> 4);
chHighBits = ch << 4;
break; case 2:
*pbOutput++ = chHighBits | (ch >> 2);
chHighBits = ch << 6;
break; default:
*pbOutput++ = chHighBits | ch;
}
} return (int)(pbOutput - pbOutStart);
}

04-22 15:21