10 [[nodiscard]]
static constexpr
char encode(uint8_t c)
12 constexpr
const char*
const base64_chars =
13 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
14 "abcdefghijklmnopqrstuvwxyz"
17 return base64_chars[c];
20 [[nodiscard]]
static constexpr uint8_t decode(uint8_t c)
22 if (
'A' <= c && c <=
'Z') {
24 }
else if (
'a' <= c && c <=
'z') {
26 }
else if (
'0' <= c && c <=
'9') {
28 }
else if (c ==
'+') {
30 }
else if (c ==
'/') {
37 std::string encode(
const uint8_t* input,
size_t inSize)
39 constexpr
int CHUNKS = 19;
40 constexpr
int IN_CHUNKS = 3 * CHUNKS;
41 constexpr
int OUT_CHUNKS = 4 * CHUNKS;
43 auto outSize = ((inSize + (IN_CHUNKS - 1)) / IN_CHUNKS) * (OUT_CHUNKS + 1);
44 std::string ret(outSize, 0);
48 if (out) ret[out++] =
'\n';
49 auto n2 = std::min<size_t>(IN_CHUNKS, inSize);
50 auto n = unsigned(n2);
51 for (; n >= 3; n -= 3) {
52 ret[out++] = encode( (input[0] & 0xfc) >> 2);
53 ret[out++] = encode(((input[0] & 0x03) << 4) +
54 ((input[1] & 0xf0) >> 4));
55 ret[out++] = encode(((input[1] & 0x0f) << 2) +
56 ((input[2] & 0xc0) >> 6));
57 ret[out++] = encode( (input[2] & 0x3f) >> 0);
61 uint8_t buf3[3] = { 0, 0, 0 };
66 buf4[0] = (buf3[0] & 0xfc) >> 2;
67 buf4[1] = ((buf3[0] & 0x03) << 4) +
68 ((buf3[1] & 0xf0) >> 4);
69 buf4[2] = ((buf3[1] & 0x0f) << 2) +
70 ((buf3[2] & 0xc0) >> 6);
71 buf4[3] = (buf3[2] & 0x3f) >> 0;
72 for (
auto j :
xrange(n + 1)) {
73 ret[out++] = encode(buf4[j]);
82 assert(outSize >= out);
87 std::pair<MemBuffer<uint8_t>,
size_t> decode(std::string_view input)
89 auto outSize = (input.size() * 3 + 3) / 4;
95 for (
auto c : input) {
96 uint8_t d = decode(c);
97 if (d == uint8_t(-1))
continue;
101 ret[out++] = char(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
102 ret[out++] = char(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
103 ret[out++] = char(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
107 for (
auto j :
xrange(i, 4u)) {
111 buf3[0] = ((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4);
112 buf3[1] = ((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2);
113 buf3[2] = ((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0);
114 for (
auto j :
xrange(i - 1)) {
115 ret[out++] = buf3[j];
119 assert(outSize >= out);
121 return {std::move(ret), out};
129 for (
auto c : input) {
130 uint8_t d = decode(c);
131 if (d == uint8_t(-1))
continue;
135 if ((out + 3) > outSize) [[unlikely]]
return false;
136 output[out++] = char(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
137 output[out++] = char(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
138 output[out++] = char(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
142 for (
auto j :
xrange(i, 4u)) {
146 buf3[0] = ((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4);
147 buf3[1] = ((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2);
148 buf3[2] = ((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0);
149 for (
auto j :
xrange(i - 1)) {
150 if (out == outSize) [[unlikely]]
return false;
151 output[out++] = buf3[j];
155 return out == outSize;
This class manages the lifetime of a block of memory.
void resize(size_t size)
Grow or shrink the memory block.
bool decode_inplace(std::string_view input, uint8_t *output, size_t outSize)
constexpr auto xrange(T e)