Base64
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法
代码实现(C++)
/*
base64.cpp and base64.h
base64 encoding and decoding with C++.
More information at
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
Version: 2.rc.04 (release candidate)
Copyright (C) 2004-2017, 2020 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
/**
* Base64编解码
* @file: Base64.cpp
* @author: rancheng <rc4work@163.com>
* @date: 2020-11-20
*/
#include "Base64.h"
namespace dev {
static std::string base64Encode(BytesConstRef bs, const char* charSet, char padCh) {
// 提前分配好内存
auto len = bs.size();
std::string ret((len + 2) / 3 * 4, ' ');
// 每3个字节转换为4个Base64字符,不足的后面补充填充字符
for (size_t i = 0, off = 0; i < len; i += 3) {
ret[off++] = charSet[(bs[i] & 0xfc) >> 2];
if (i + 1 < len) {
ret[off++] = charSet[((bs[i] & 0x03) << 4) + ((bs[i + 1] & 0xf0) >> 4)];
if (i + 2 < len) {
ret[off++] = charSet[((bs[i + 1] & 0x0f) << 2) + ((bs[i + 2] & 0xc0) >> 6)];
ret[off++] = charSet[bs[i + 2] & 0x3f];
} else {
ret[off++] = charSet[(bs[i + 1] & 0x0f) << 2];
ret[off++] = padCh;
}
} else {
ret[off++] = charSet[(bs[i] & 0x03) << 4];
ret[off++] = padCh;
ret[off++] = padCh;
}
}
return ret;
}
// 将字节数组转换为Base64编码的字符串(标准字符集)
std::string toBase64STD(BytesConstRef bs) {
// 字符集
static auto s_stdBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/";
// 填充字符
static char s_stdPadCh = '=';
return base64Encode(bs, s_stdBase64Chars, s_stdPadCh);
}
// 将字节数组转换为Base64编码的字符串(对url合法的字符集)
std::string toBase64URL(BytesConstRef bs) {
// 字符集
static auto s_urlBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_";
// 填充字符
static char s_urlPadCh = '=';
return base64Encode(bs, s_urlBase64Chars, s_urlPadCh);
}
// base64字符转换为对应的int值(标准字符集)
static int base64Ch2iSTD(int base64Ch) {
if (base64Ch >= 'A' && base64Ch <= 'Z') return base64Ch - 'A';
if (base64Ch >= 'a' && base64Ch <= 'z') return base64Ch - 'a' + ('Z' - 'A') + 1;
if (base64Ch >= '0' && base64Ch <= '9') return base64Ch - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
if (base64Ch == '+') return 62;
if (base64Ch == '/') return 63;
throw BadBase64Ch();
}
// base64字符转换为对应的int值(对url合法的字符集)
static int base64Ch2iURL(int base64Ch) {
if (base64Ch >= 'A' && base64Ch <= 'Z') return base64Ch - 'A';
if (base64Ch >= 'a' && base64Ch <= 'z') return base64Ch - 'a' + ('Z' - 'A') + 1;
if (base64Ch >= '0' && base64Ch <= '9') return base64Ch - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
if (base64Ch == '-') return 62;
if (base64Ch == '_') return 63;
throw BadBase64Ch();
}
using Base64Ch2i = int(*)(int);
Bytes base64Decode(const std::string& base64, Base64Ch2i base64Ch2i, char padCh) {
// 提前分配内存
auto len = base64.size();
Bytes ret((len + 3) / 4 * 3);
// 每4个Base64字符转换为3个字节
size_t off = 0;
for (size_t i = 0; i < len; i += 4) {
int one = base64Ch2i(base64[i]);
// C++11标准保证str[str.size()]为' '
int two = base64Ch2i(base64[i + 1]);
ret[off++] = (one << 2) + ((two & 0x30) >> 4);
if (base64[i + 2] != padCh) {
int three = base64Ch2i(base64[i + 2]);
ret[off++] = ((two & 0x0f) << 4) + ((three & 0x3c) >> 2);
if (base64[i + 3] != padCh) {
int four = base64Ch2i(base64[i + 3]);
ret[off++] = ((three & 0x03) << 6) + four;
}
}
}
ret.resize(off);
return ret;
}
/**
* 将Base64编码的字符串转换为字节数组
* @param base64 Base64编码的字符串(标准字符集)
* @return 对应的字节数组
* @throw 遇到非法Base64字符抛出BadBase64Ch异常
*/
Bytes fromBase64STD(const std::string& base64) {
// 填充字符
static char s_stdPadCh = '=';
return base64Decode(base64, base64Ch2iSTD, s_stdPadCh);
}
/**
* 将Base64编码的字符串转换为字节数组
* @param base64 Base64编码的字符串(对url合法的字符集)
* @return 对应的字节数组
* @throw 遇到非法Base64字符抛出BadBase64Ch异常
*/
Bytes fromBase64URL(const std::string& base64) {
// 填充字符
static char s_urlPadCh = '=';
return base64Decode(base64, base64Ch2iURL, s_urlPadCh);
}
} // namespace dev
在fromBase64
函数中有一个小技巧,那就是在C++11中保证str[str.size()]
返回字符' '。
URLSafe
Base64编码后的字符,常用来作为URL参数传递。但有些情况下,编码后可能出现字符+和/,在URL中就不能直接作为参数。
一般需要做URL Safe编码,就是把字符+和/分别变成-和_。