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编码表 (下表),得到对应编码后的字符。
实现:
//
//
// 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);
}