69 [[nodiscard]]
static std::string
encode(std::span<const std::uint8_t> data);
77 [[nodiscard]]
static std::string
encode(std::string_view text);
91 [[nodiscard]]
static std::optional<std::vector<std::uint8_t>>
decode(std::string_view input);
101 [[nodiscard]]
static std::optional<std::string>
decode_to_string(std::string_view input);
116 [[nodiscard]]
static std::optional<std::uint8_t> decode_char(
char c)
noexcept;
123 static constexpr std::string_view ENCODE_LOOKUP =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
126 static constexpr char PADDING_CAR =
'=';
137 result.reserve(((data.size() + 2) / 3) * 4);
139 for (std::size_t i = 0; i < data.size(); i += 3)
141 const std::uint32_t b0 = data[i];
142 const std::uint32_t b1 = (i + 1 < data.size()) ? data[i + 1] : 0u;
143 const std::uint32_t b2 = (i + 2 < data.size()) ? data[i + 2] : 0u;
145 const std::uint32_t triple = (b0 << 16) | (b1 << 8) | b2;
147 result += ENCODE_LOOKUP[(triple >> 18) & 0x3F];
148 result += ENCODE_LOOKUP[(triple >> 12) & 0x3F];
149 result += (i + 1 < data.size()) ? ENCODE_LOOKUP[(triple >> 6) & 0x3F] : PADDING_CAR;
150 result += (i + 2 < data.size()) ? ENCODE_LOOKUP[(triple >> 0) & 0x3F] : PADDING_CAR;
163inline std::optional<std::vector<std::uint8_t>>
Base64::decode(
const std::string_view input)
165 if (input.size() % 4 != 0)
169 return std::vector<std::uint8_t>{};
173 for (std::size_t i = 0; i < input.size() - 4; ++i)
175 if (input[i] == PADDING_CAR)
179 const std::string_view last = input.substr(input.size() - 4);
183 if (last[2] == PADDING_CAR && last[3] != PADDING_CAR)
186 std::vector<std::uint8_t> result;
187 result.reserve((input.size() / 4) * 3);
189 for (std::size_t i = 0; i < input.size(); i += 4)
191 const auto v0 = decode_char(input[i]);
192 const auto v1 = decode_char(input[i + 1]);
193 const auto v2 = input[i + 2] == PADDING_CAR ? std::optional<std::uint8_t>{ 0 } : decode_char(input[i + 2]);
194 const auto v3 = input[i + 3] == PADDING_CAR ? std::optional<std::uint8_t>{ 0 } : decode_char(input[i + 3]);
196 if (!v0 || !v1 || !v2 || !v3)
199 const std::uint32_t triple =
200 (
static_cast<std::uint32_t
>(*v0) << 18) |
201 (
static_cast<std::uint32_t
>(*v1) << 12) |
202 (
static_cast<std::uint32_t
>(*v2) << 6) |
203 (
static_cast<std::uint32_t
>(*v3));
205 result.push_back(
static_cast<std::uint8_t
>((triple >> 16) & 0xFF));
206 if (input[i + 2] != PADDING_CAR)
207 result.push_back(
static_cast<std::uint8_t
>((triple >> 8) & 0xFF));
208 if (input[i + 3] != PADDING_CAR)
209 result.push_back(
static_cast<std::uint8_t
>((triple >> 0) & 0xFF));