add util::base64_urlsafe_encode/decode
This commit is contained in:
parent
65ca46b2da
commit
4cdb1fbae2
@ -306,6 +306,12 @@ const char B64ABC[] =
|
||||
"0123456789"
|
||||
"+/";
|
||||
|
||||
const char URLSAFE_B64ABC[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"-_";
|
||||
|
||||
inline ubyte base64_decode_char(char c) {
|
||||
if (c >= 'A' && c <= 'Z') return c - 'A';
|
||||
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
||||
@ -315,16 +321,27 @@ inline ubyte base64_decode_char(char c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void base64_encode_(const ubyte* segment, char* output) {
|
||||
output[0] = B64ABC[(segment[0] & 0b11111100) >> 2];
|
||||
output[1] =
|
||||
B64ABC[((segment[0] & 0b11) << 4) | ((segment[1] & 0b11110000) >> 4)];
|
||||
output[2] =
|
||||
B64ABC[((segment[1] & 0b1111) << 2) | ((segment[2] & 0b11000000) >> 6)];
|
||||
output[3] = B64ABC[segment[2] & 0b111111];
|
||||
inline ubyte base64_urlsafe_decode_char(char c) {
|
||||
if (c >= 'A' && c <= 'Z') return c - 'A';
|
||||
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
||||
if (c >= '0' && c <= '9') return c - '0' + 52;
|
||||
if (c == '-') return 62;
|
||||
if (c == '_') return 63;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string util::base64_encode(const ubyte* data, size_t size) {
|
||||
template <const char* ABC>
|
||||
static void base64_encode_(const ubyte* segment, char* output) {
|
||||
output[0] = ABC[(segment[0] & 0b11111100) >> 2];
|
||||
output[1] =
|
||||
ABC[((segment[0] & 0b11) << 4) | ((segment[1] & 0b11110000) >> 4)];
|
||||
output[2] =
|
||||
ABC[((segment[1] & 0b1111) << 2) | ((segment[2] & 0b11000000) >> 6)];
|
||||
output[3] = ABC[segment[2] & 0b111111];
|
||||
}
|
||||
|
||||
template <const char* ABC>
|
||||
static std::string base64_encode_impl(const ubyte* data, size_t size) {
|
||||
std::stringstream ss;
|
||||
|
||||
size_t fullsegments = (size / 3) * 3;
|
||||
@ -332,7 +349,7 @@ std::string util::base64_encode(const ubyte* data, size_t size) {
|
||||
size_t i = 0;
|
||||
for (; i < fullsegments; i += 3) {
|
||||
char output[] = "====";
|
||||
base64_encode_(data + i, output);
|
||||
base64_encode_<ABC>(data + i, output);
|
||||
ss << output;
|
||||
}
|
||||
|
||||
@ -343,18 +360,27 @@ std::string util::base64_encode(const ubyte* data, size_t size) {
|
||||
size_t trailing = size - fullsegments;
|
||||
if (trailing) {
|
||||
char output[] = "====";
|
||||
output[0] = B64ABC[(ending[0] & 0b11111100) >> 2];
|
||||
output[0] = ABC[(ending[0] & 0b11111100) >> 2];
|
||||
output[1] =
|
||||
B64ABC[((ending[0] & 0b11) << 4) | ((ending[1] & 0b11110000) >> 4)];
|
||||
ABC[((ending[0] & 0b11) << 4) | ((ending[1] & 0b11110000) >> 4)];
|
||||
if (trailing > 1)
|
||||
output[2] = B64ABC
|
||||
[((ending[1] & 0b1111) << 2) | ((ending[2] & 0b11000000) >> 6)];
|
||||
if (trailing > 2) output[3] = B64ABC[ending[2] & 0b111111];
|
||||
output[2] =
|
||||
ABC[((ending[1] & 0b1111) << 2) |
|
||||
((ending[2] & 0b11000000) >> 6)];
|
||||
if (trailing > 2) output[3] = ABC[ending[2] & 0b111111];
|
||||
ss << output;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string util::base64_encode(const ubyte* data, size_t size) {
|
||||
return base64_encode_impl<B64ABC>(data, size);
|
||||
}
|
||||
|
||||
std::string util::base64_urlsafe_encode(const ubyte* data, size_t size) {
|
||||
return base64_encode_impl<URLSAFE_B64ABC>(data, size);
|
||||
}
|
||||
|
||||
std::string util::tohex(uint64_t value) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << value;
|
||||
@ -366,7 +392,8 @@ std::string util::mangleid(uint64_t value) {
|
||||
return tohex(value);
|
||||
}
|
||||
|
||||
util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
||||
template <ubyte(base64_decode_char)(char)>
|
||||
static util::Buffer<ubyte> base64_decode_impl(const char* str, size_t size) {
|
||||
util::Buffer<ubyte> bytes((size / 4) * 3);
|
||||
ubyte* dst = bytes.data();
|
||||
for (size_t i = 0; i < (size / 4) * 4;) {
|
||||
@ -387,18 +414,35 @@ util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
util::Buffer<ubyte> util::base64_urlsafe_decode(const char* str, size_t size) {
|
||||
return base64_decode_impl<base64_urlsafe_decode_char>(str, size);
|
||||
}
|
||||
|
||||
util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
||||
return base64_decode_impl<base64_decode_char>(str, size);
|
||||
}
|
||||
|
||||
util::Buffer<ubyte> util::base64_urlsafe_decode(std::string_view str) {
|
||||
return base64_urlsafe_decode(str.data(), str.size());
|
||||
}
|
||||
|
||||
util::Buffer<ubyte> util::base64_decode(std::string_view str) {
|
||||
return base64_decode(str.data(), str.size());
|
||||
}
|
||||
|
||||
int util::replaceAll(
|
||||
std::string& str, const std::string& from, const std::string& to
|
||||
template <typename CharT>
|
||||
static int replace_all(
|
||||
std::basic_string<CharT>& str,
|
||||
const std::basic_string<CharT>& from,
|
||||
const std::basic_string<CharT>& to
|
||||
) {
|
||||
int count = 0;
|
||||
size_t offset = 0;
|
||||
while (true) {
|
||||
size_t start_pos = str.find(from, offset);
|
||||
if (start_pos == std::string::npos) break;
|
||||
if (start_pos == std::basic_string<CharT>::npos) {
|
||||
break;
|
||||
}
|
||||
str.replace(start_pos, from.length(), to);
|
||||
offset = start_pos + to.length();
|
||||
count++;
|
||||
@ -406,6 +450,18 @@ int util::replaceAll(
|
||||
return count;
|
||||
}
|
||||
|
||||
int util::replaceAll(
|
||||
std::string& str, const std::string& from, const std::string& to
|
||||
) {
|
||||
return replace_all(str, from, to);
|
||||
}
|
||||
|
||||
int util::replaceAll(
|
||||
std::wstring& str, const std::wstring& from, const std::wstring& to
|
||||
) {
|
||||
return replace_all(str, from, to);
|
||||
}
|
||||
|
||||
// replace it with std::from_chars in the far far future
|
||||
double util::parse_double(const std::string& str) {
|
||||
std::istringstream ss(str);
|
||||
|
||||
@ -74,8 +74,12 @@ namespace util {
|
||||
std::wstring to_wstring(double x, int precision);
|
||||
|
||||
std::string base64_encode(const ubyte* data, size_t size);
|
||||
std::string base64_urlsafe_encode(const ubyte* data, size_t size);
|
||||
|
||||
util::Buffer<ubyte> base64_decode(const char* str, size_t size);
|
||||
util::Buffer<ubyte> base64_urlsafe_decode(const char* str, size_t size);
|
||||
util::Buffer<ubyte> base64_decode(std::string_view str);
|
||||
util::Buffer<ubyte> base64_urlsafe_decode(std::string_view str);
|
||||
|
||||
std::string tohex(uint64_t value);
|
||||
|
||||
@ -85,6 +89,10 @@ namespace util {
|
||||
std::string& str, const std::string& from, const std::string& to
|
||||
);
|
||||
|
||||
int replaceAll(
|
||||
std::wstring& str, const std::wstring& from, const std::wstring& to
|
||||
);
|
||||
|
||||
double parse_double(const std::string& str);
|
||||
double parse_double(const std::string& str, size_t offset, size_t len);
|
||||
|
||||
|
||||
@ -31,3 +31,19 @@ TEST(stringutil, base64) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(stringutil, base64_urlsafe) {
|
||||
srand(2019);
|
||||
for (size_t size = 0; size < 30; size++) {
|
||||
auto bytes = std::make_unique<ubyte[]>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
bytes[i] = rand();
|
||||
}
|
||||
auto base64 = util::base64_urlsafe_encode(bytes.get(), size);
|
||||
auto decoded = util::base64_urlsafe_decode(base64);
|
||||
ASSERT_EQ(size, decoded.size());
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ASSERT_EQ(bytes[i], decoded[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user