Base64是MIME中常用的编码方式之一,也是一种数据加密方法。
使用Base64编码可以对任何二进制数据进行编码,经过编码后变成可打印字符。在Base64中的字符有:‘A’~‘Z’、‘a’~‘z’、‘0’~‘9’、‘+’、‘/’64个字符,由这64个字符构成Base64编码表。使用Base64编码时,对待编码字符串的二进制进行重组,每6个bit为一个单元,这样可以形成26 = 64个索引码。每个索引码对应Base64编码表中的一下字符。
Ø Base64编码算法
1 依次取出编码串的6个bit,得到一个索引码,查询Base64编码表,得到相应的Base64字符
2 对于不足3个或3的倍数个字符的字符串要做特殊处理
2.1 剩余一个字符(一个字节),前6个bit转换成Base64字符,剩余低2位要左边补0 ,凑成6bit,然后转换成Base64字符。最后要补上两个'='
2.2 剩余二个字符(二个字节),最后剩余4个bit,左边补0,凑成6bit,转换成Base64字符。最后要补上一个'='
Ø Base64的解码
Base64解码表是以64个Base64字符的值为索引值构造的一张表(Base64CharacterMap)。网上有的给解码表分配128个存储单元,也有的分配256个存储单元,其实128个 足够了(Base64最大字符的值为122)。如:‘A’的ASCII值为65,它在Base64编码表中的索引为0,那么Base64CharacterMap[65] = 0; 对于不存在的索引就定义一个标志位就行了。如Base64CharacterMap[0] = -1;
如果觉得构造解码表不好理解,可以写个函数来计算每个Base64字符在编码表的位置。如:
int GetBase64Index(const char p)
{
if (p >= 'A' && p <= 'Z')
{
return (p - 'A');
}
else if (p >= 'a' && p <= 'z')
{
return (p - 'a' + 'Z' - 'A' + 1);
}
else if (p >= '0' && p <= '9')
{
return (p - '0' + ('Z' - 'A' + 1) * 2);
}
else if (p == '+')
{
return 62;
}
else if (p == '/')
{
return 63;
}
else
{
return -1;
}
}
Ø 算法实现
² 方法一:
typedef unsigned char Byte;
const char Base64CharacterSet[] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '+', '/'
};
void Base64Encode(const Byte *pByte, int nByteLen, string &sResult)
{
int nLoop = nByteLen / 3;
int nRemain = nByteLen % 3;
int i = 0;
for (i=0; i < nLoop; ++i)
{
int nIndex1 = pByte[i*3] >> 2;
int nIndex2 = ((pByte[i*3] & 0x03) << 4) | ((pByte[i*3+1] & 0xF0) >> 4);
int nIndex3 = ((pByte[i*3+1] & 0x0F) << 2) | ((pByte[i*3+2] & 0xc0) >> 6);
int nIndex4 = (pByte[i*3+2] & 0x3F);
sResult += Base64CharacterSet[nIndex1];
sResult += Base64CharacterSet[nIndex2];
sResult += Base64CharacterSet[nIndex3];
sResult += Base64CharacterSet[nIndex4];
}
if (nRemain == 1)
{
int nIndex1 = pByte[i*3] >> 2;
int nIndex2 = (pByte[i*3] & 0x03);
sResult += Base64CharacterSet[nIndex1];
sResult += Base64CharacterSet[nIndex2];
sResult += "==";
}
else if (nRemain == 2)
{
int nIndex1 = pByte[i*3] >> 2;
int nIndex2 = ((pByte[i*3] & 0x03) << 4) | (pByte[i*3+1] >> 4);
int nIndex3 = (pByte[i*3+1] & 0x0F);
sResult += Base64CharacterSet[nIndex1];
sResult += Base64CharacterSet[nIndex2];
sResult += Base64CharacterSet[nIndex3];
sResult += "=";
}
else
{
sResult += "";
}
}
解码
void Base64Decode(const Byte *pSrc, int nLen, string &sDest)
{
for (int i=0; i < nLen; i += 4)
{
int nVal1 = GetBase64Index(pSrc[i]);
int nVal2 = GetBase64Index(pSrc[i+1]);
int nVal3 = GetBase64Index(pSrc[i+2]);
int nVal4 = GetBase64Index(pSrc[i+3]);
if (-1 != nVal3) //第三个字符不为'=',说明源字符串3*n+2
{
sDest += (nVal1 << 2) | (nVal2 >> 4);
if (-1 != nVal4) //第四个字符不为'=',说明源字符串3*n
{
sDest += (nVal2 << 4) | (nVal3 >> 2);
sDest += (nVal3 << 6) | nVal4;
}
else //3*n+2
{
sDest += (nVal2 << 4) | nVal3;
}
}
else //3*n+1
{
sDest += (nVal1 << 2) | nVal2;
}
}
}
² 方法二:
typedef unsigned long uint32;
union Base64Block
{
Byte bytes[4];
uint32 uBase64Block;
};
void Base64Encode(const Byte *pByte, int nByteLen, string &sResult)
{
Base64Block block;
uint32 uMask = 0x3F;
for (int i=0, nLeft = nByteLen; i < nByteLen; i+=3, nLeft -= 3)
{
block.bytes[2] = pByte[i];
if (nLeft > 1)
{
block.bytes[1] = pByte[i+1];
if (nLeft > 2)
{
block.bytes[0] = pByte[i];
}
else
{
block.bytes[0] = 0;
}
}
else
{
block.bytes[0] = 0;
block.bytes[1] = 0;
}
sResult += Base64CharacterSet[(block.uBase64Block >> 18) & uMask];
sResult += Base64CharacterSet[(block.uBase64Block >> 12 & uMask];
if (nLeft > 1)
{
sResult += Base64CharacterSet[(block.uBase64Block >> 6) & uMask];
if (nLeft > 2)
{
sResult += Base64CharacterSet[block.uBase64Block & uMask];
}
else
{
sResult += "=";
}
}
else
{
sResult += '==";
}
}
}
解码待续.