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