一、简介:
Base64:是网络上最常见的用于传输8Bit字节码的编码方式之一,是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
Base64 编码:包括小写字母a-z、大写字母A-Z、数字0-9、符号"+“、”/"一共64个字符的字符集,(任何符号都可以转换成这个字符集中的字符,这个转换过程就叫做base64编码。
Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
Base64被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了Base64的各种“变种”。为统一和规范化Base64的输出,Base62x被视为无符号化的改进版本。
二、编码规则
- 把3个字节变成4个字节( 3 x 8 = 4 x 6 = 24 , 把6Bit再添两位高位0,组成四个8Bit的字节 )
- 每76个字符加一个换行符
- 最后的结束符也要处理
原始base64编码 是使用原始Base64表的字符顺序的编码, 私有Base64编码 是使用了私有Base64表(改变了原始表字符顺序的编码)
例如:
转换前: 11111111, 11111111, 11111111
转换后: 00111111, 00111111, 00111111, 00111111
转换前: 10101101, 10111010, 01110110
转换后: 00101011, 00011011, 00101001, 00110110
转换后十进制: 43 27 41 54
转换后对应码表中的值: r b p 2
三、实现
1. 基于 C 实现 原始 Base64
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char * base64_encode(const unsigned char * data, size_t dataLen)
{
size_t i=0, j=0;
// 计算输出长度,编码长度需被 4 整除
size_t outputLen = 4 * (dataLen / 3);
if(dataLen %3 > 0)
{
outputLen += 4;
}
// 申请 堆上空间存储 输出编码
char * encodeData = (char *)malloc(outputLen);
if (NULL == encodeData)
{
return NULL;
}
for(i=0, j=0; i<dataLen; )
{
// 组合成 32 位
uint32_t triple = 0x0000;
// Base64 是将 3个8位 拆分为 4个8位
// 特殊情况之一:如果输入 !
// first = 0010 0001 dataLen = 1 ==> second = 0000 0000 third = 0000 0000
// triple = 0010 0001 0000 0000 0000 0000
// 0000 1000 | 0001 0000 | 0000 0000 | 0000 0000
uint8_t first = i < dataLen ? data[i++] : ~0xff;
uint8_t second = i < dataLen ? data[i++] : ~0xff;
uint8_t third = i < dataLen ? data[i++] : ~0xff;
triple = ((first <<16 ) + (second << 8) + (third));
// 位操作 获取 data
// 0x3f - 0011 1111
// 如果输入 ! triple = 0010 0001 0000 0000 0000 0000 => 00 1000 0100 0000 0000
encodeData[j++] = base64_chars[(triple >> (3 * 6)) & 0x3F];
encodeData[j++] = base64_chars[(triple >> (2 * 6)) & 0x3F];
encodeData[j++] = base64_chars[(triple >> (1 * 6)) & 0x3F];
encodeData[j++] = base64_chars[(triple >> (0 * 6)) & 0x3F];
}
for(size_t i=0; i<(3-dataLen%3); i++)
{
encodeData[outputLen -1 -i] = '=';
}
return encodeData;
}
2. 基于 C++ 实现 原始 Base64
// 原始Base64表
std::string kBase64CodeTable =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// std::string const& raw 原始数据
// std::string* out 编码后数据
int Base64Encode(std::string const& raw, std::string* out)
{
// 1.
// 获取字符串长度
int len = raw.size();
for (int i = 0; i < len; i += 3)
{
// 2.
// 循环遍历原始字符串,每次处理3个字符
// 组成第一个八位 0xFC - 1111 1100
out->push_back(kBase64CodeTable[(raw[i] & 0xFC)>>2]);
if (i+1 >= len)
{
// 原始数据只剩一个字符 01-> 0001 0000
// 0x03 - 0000 0011
out->push_back(kBase64CodeTable[(raw[i] & 0x03)<<4]);
break;
}
// 0x03 - 0000 0011 0xf0 - 1111 0000
out->push_back(kBase64CodeTable[(raw[i] & 0x03)<<4|(raw[i+1] & 0xF0)>>4]);
// 组成第三个八位
if (i+2 >= len)
{
// 原始数据 只剩两个字符
out->push_back(kBase64CodeTable[(raw[i+1] & 0x0F)<<2]);
break;
}
// 原始数据 足够三个字符
// 0x0f - 0000 1111 0xb0 - 1100 0000
out->push_back(kBase64CodeTable[(raw[i+1] & 0x0F)<<2 |(raw[i+2] & 0xC0)>>6]);
// 组成第四个八位
// 0x3f - 0011 1111
out->push_back(kBase64CodeTable[raw[i+2] & 0x3F]);
}
len = out->size();
if (len % 4 != 0)
{
out->append(std::string(4-len%4, '='));
}
return 0;
}