编码方案
- Base encoding 编码规格书 RFC3548
- 把二进制数据转化为可打印字符集数据称为base encoding
- 编码后的数据方便用于存储和网络传输
Base64
- 把8bit数据用6bit进行编码,即把0 ~ 的字符集合A映射到0 ~ 的字符集合B内
- 字符集合B的选择有2种:
- 标准集合:A~Z && a ~ z && 0 ~ 9 && + /
- 用于path和url的编码:A~Z && a ~ z && 0 ~ 9 && - _
因为path和url中不能出现’/’,所以用 ‘-’ , ‘_’ 来替代’+’ , ‘/’
编码流程
- 按照bit流进行编码,24(6和8的最小公倍数)bit为一组.
- 有以下几种填充情况:
- input的长度(单位bit)是24的倍数,正常编码不需要填充
- input 多8bit,需要填充16bit 0,使用了填充的前4bit的0后,剩余的12bit使用2个’='表示
- input 多16bit,需要填充8bit 0,使用填充的前2bit的0后,剩余的6bit使用1个‘=’表示
- 经过Base64编码后的数据膨胀约33.3%
- encoding
const std::string Base64::base64_chars_{"ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz0123456789+/"};
std::string Base64::encode(const std::string &to_encode_string){
if(to_encode_string.empty()){
return {};
}
std::string ret{""};
int i = 0,j = 0;
const unsigned char * bytes_to_encode = reinterpret_cast<const unsigned char*>(to_encode_string.c_str());
unsigned int in_len = to_encode_string.size();
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;
}
}
//i为len%3
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);
for (j = 0; (j < i + 1); j++)
ret += base64_chars_[char_array_4[j]];
//空余几个
while((i++ < 3))
ret += '=';
}
return ret;
}
- decoding
if(encoded_string.empty()){
return {};
}
int in_len = encoded_string.size();
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-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[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 = 0; j < i; 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);
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
Base32
- 把0 ~ 数据集合A映射到 0 ~ 的数据集合B上
- 数据集合B:A~Z && 2 ~ 7
- 有以下几种填充情况:
- input的长度(bit)是40的整数倍,不需要填充
- 多出来8bit,需要填充32bit的0,使用了填充的前2个bit,剩下的30bit需要用6个‘=’替代
- 多出来16bit,需要填充24bit的0,使用了填充的前4个bit,剩下的20bit需要用4个‘=’替代
- 多出来24bit,需要填充16bit的0,使用了填充的前1个bit,剩下的15bit需要用3个‘=’替代
- 多出来32bit,需要填充8bit的0,使用了填充的前3个bit,剩下的5bit需要用1个‘=’替代
Base16
- 把0 ~ 数据集合A映射到 0 ~ 的数据集合B上
- 数据集合B:0~9 && A ~F
- 也就是HEX编码
- 每个字节都编码为2个字节
- 不存在填充情况
class Base16{
const static std::string base16_chars;
static bool check(unsigned char it){
if(isdigit(it) || (it >= 'A' && it <= 'F')) return true;
return false;
}
static unsigned char toDecode(unsigned char i){
return base16_chars[i];
}
static unsigned char fromDecode(unsigned char it){
if(it > 'F' || it < '0') throw InvalidParam("invalid input");
if(it >= 'A') return it -'A' + 10;
if(it <= '9') return it - '0';
throw InvalidParam("invalid input");
}
public:
class InvalidParam:public std::exception{
std::string msg_;
public:
InvalidParam(const std::string& m):msg_(m){}
const char* what() const noexcept override{
return msg_.c_str();
}
};
static std::string encode(const std::string& in);
static std::string decode(const std::string& in);
};
const std::string Base16::base16_chars{"0123456789ABCDEF"};
std::string Base16::encode(const std::string& in){
int size = in.size();
std::string res(2*size,0);
int j = 0;
for(int i = 0;i < size;++i){
unsigned char it = in[i];
res[j++] = toDecode(it>>4);
res[j++] = toDecode(it&0x0f);
}
return res;
}
std::string Base16::decode(const std::string&in){
int size = in.size();
if(size %2 != 0) throw InvalidParam("invalid input");;
std::string res(size/2,0);
int j = 0;
for(int i = 0;i < size;++i){
if(!check(in[i]) || !check(in[i+1])){
throw InvalidParam("invalid input");
}
res[j++] = fromDecode(in[i])*16+fromDecode(in[i+1]);
i++;
}
return res;
}