看一下Base64的索引表,字符选用了"A-Z、a-z、0-9、+、/" 64个可打印字符。数值代表字符的索引,这个是标准Base64协议规定的,不能更改。64个字符用6个bit位就可以全部表示,一个字节有8个bit 位,剩下两个bit就浪费掉了,这样就不得不牺牲一部分空间了。这里需要弄明白的就是一个Base64字符是8个bit,但是有效部分只有右边的6个 bit,左边两个永远是0。
那么怎么用6个有效bit来表示传统字符的8个bit呢?8和6的最小公倍数 是24,也就是说3个传统字节可以由4个Base64字符来表示,保证有效位数是一样的,这样就多了1/3的字节数来弥补Base64只有6个有效bit 的不足。你也可以说用两个Base64字符也能表示一个传统字符,但是采用最小公倍数的方案其实是最减少浪费的。结合下边的图比较容易理解。Man是三个 字符,一共24个有效bit,只好用4个Base64字符来凑齐24个有效位。红框表示的是对应的Base64,6个有效位转化成相应的索引值再对应 Base64字符表,查出"Man"对应的Base64字符是"TWFU"。说到这里有个原则不知道你发现了没有,要转换成Base64的最小单位就是三个字节,对一个字符串来说每次都是三个字节三个字节的转换,对应的是Base64的四个字节。这个搞清楚了其实就差不多了。
1.Base64.h
#ifndef BASE64_H
#define BASE64_H
#include <string>
class CBase64
{
public:
CBase64();
~CBase64();
public:
//static CString Base64Encode(LPCTSTR lpszSrc);
//static CString Base64Decode(LPCTSTR lpszSrc);
//编码
static std::string CBase64::Base64Encode(char* lpszSrc);
//解码
static std::string CBase64::Base64Decode(char* lpszSrc);
private:
//base64字符
static const std::string base64_chars;
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
public:
//utf8格式
static int find_utf_8_bit_head(const unsigned char *src_content,int src_size );
//编码
static std::string base64_encode(const unsigned char* bytes_to_encode, unsigned int in_len);
//解码
static std::string base64_decode(const unsigned char* bytes_to_encode, unsigned int in_len);
};
#endif
Base64.cpp
#include "Base64.h"
const std::string CBase64::base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
int CBase64::find_utf_8_bit_head(const unsigned char *src_content,int src_size )
{
int i_ret = -1;
int byteNum = 0; //字符数
if( src_content )
{
for(int i = src_size-1; i >= 0; i--)
{
if( 0 == (src_content[i] >> 7 ) )
{
byteNum = 1;
i_ret = src_size - i;
break;
}
if( 0x06 == (src_content[i]>> 5) )
{
byteNum = 2;
i_ret = src_size - i;
break;
}
if( 0x0E == (src_content[i] >> 4) )
{
byteNum = 3;
i_ret = src_size - i;
break;
}
if( 0x1E == (src_content[i] >> 3) )
{
byteNum = 4;
i_ret = src_size - i;
break;
}
if( 0x3E == (src_content[i] >> 2) )
{
byteNum = 5;
i_ret = src_size - i;
break;
}
if( 0x7E == (src_content[i] >> 1) )
{
byteNum = 6;
i_ret = src_size - i;
break;
}
}
if( i_ret == byteNum ) i_ret = -1;
}
return i_ret;
}
std::string CBase64::base64_encode(const unsigned char* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
//CString CBase64::Base64Encode(LPCTSTR lpszSrc)
//{
// char* strSrc = new char[_tcslen(lpszSrc)+1];
// ZeroMemory(strSrc, _tcslen(lpszSrc)+1);
// strcpy(strSrc, (char*)(_bstr_t(lpszSrc)));
// std::string str = base64_encode((unsigned char*)strSrc, (int)strlen(strSrc));
// CString strDst = str.c_str();
// return strDst;
//}
std::string CBase64::Base64Encode(char* lpszSrc)
{
int str_len = strlen(lpszSrc);
int find_index = find_utf_8_bit_head((unsigned char*)lpszSrc, str_len);
if(find_index > -1)
{
memset(lpszSrc+(str_len-find_index), 0, find_index);
}
str_len = strlen(lpszSrc);
return base64_encode((unsigned char*)lpszSrc, str_len);
}
std::string CBase64::base64_decode(const unsigned char* bytes_to_encode, unsigned int in_len) {
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( bytes_to_encode[in_] != '=') /*&& is_base64(bytes_to_encode[in_])*/) {
char_array_4[i++] = bytes_to_encode[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
//CString CBase64::Base64Decode(LPCTSTR lpszSrc)
//{
// char* strSrc = new char[_tcslen(lpszSrc)+1];
// ZeroMemory(strSrc, _tcslen(lpszSrc)+1);
// strcpy(strSrc, (char*)(_bstr_t(lpszSrc)));
// std::string str = base64_decode((unsigned char*)strSrc, (int)strlen(strSrc));
// CString strDst = str.c_str();
// return strDst;
//}
std::string CBase64::Base64Decode(char* lpszSrc)
{
return base64_decode((unsigned char*)lpszSrc, (int)strlen(lpszSrc));
}