Line data Source code
1 : #ifndef THINGER_UTIL_BASE64_HPP
2 : #define THINGER_UTIL_BASE64_HPP
3 :
4 : #include <string>
5 : #include <cstdint>
6 : #include <array>
7 :
8 : namespace thinger::util {
9 :
10 : class base64 {
11 : private:
12 : static constexpr const char encode_table[] =
13 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
14 : "abcdefghijklmnopqrstuvwxyz"
15 : "0123456789+/";
16 :
17 14 : static const std::array<uint8_t, 256>& get_decode_table() {
18 : static const auto table = [] {
19 : std::array<uint8_t, 256> t{};
20 : t.fill(0xFF);
21 : for (uint8_t i = 0; i < 64; ++i) {
22 : t[static_cast<uint8_t>(encode_table[i])] = i;
23 : }
24 : return t;
25 : }();
26 14 : return table;
27 : }
28 :
29 : static bool is_base64(uint8_t c) {
30 : return get_decode_table()[c] != 0xFF;
31 : }
32 :
33 : public:
34 38 : static std::string encode(const std::string& input) {
35 38 : return encode(reinterpret_cast<const unsigned char*>(input.data()), input.size());
36 : }
37 :
38 114 : static std::string encode(const unsigned char* data, size_t len) {
39 114 : std::string result;
40 114 : result.reserve(((len + 2) / 3) * 4);
41 :
42 874 : for (size_t i = 0; i < len; i += 3) {
43 760 : uint32_t n = static_cast<uint32_t>(data[i]) << 16;
44 760 : if (i + 1 < len) n |= static_cast<uint32_t>(data[i + 1]) << 8;
45 760 : if (i + 2 < len) n |= static_cast<uint32_t>(data[i + 2]);
46 :
47 760 : result += encode_table[(n >> 18) & 0x3F];
48 760 : result += encode_table[(n >> 12) & 0x3F];
49 760 : result += (i + 1 < len) ? encode_table[(n >> 6) & 0x3F] : '=';
50 760 : result += (i + 2 < len) ? encode_table[n & 0x3F] : '=';
51 : }
52 :
53 114 : return result;
54 0 : }
55 :
56 14 : static std::string decode(const std::string& input) {
57 14 : const auto& table = get_decode_table();
58 14 : std::string result;
59 14 : result.reserve(input.size() * 3 / 4);
60 :
61 14 : uint32_t buf = 0;
62 14 : int bits = 0;
63 :
64 252 : for (char c : input) {
65 244 : if (c == '=' || c == '\0') break;
66 :
67 238 : uint8_t val = table[static_cast<uint8_t>(c)];
68 238 : if (val == 0xFF) continue;
69 :
70 238 : buf = (buf << 6) | val;
71 238 : bits += 6;
72 :
73 238 : if (bits >= 8) {
74 176 : bits -= 8;
75 176 : result += static_cast<char>((buf >> bits) & 0xFF);
76 : }
77 : }
78 :
79 14 : return result;
80 0 : }
81 : };
82 :
83 : } // namespace thinger::util
84 :
85 : #endif // THINGER_UTIL_BASE64_HPP
|