LeviLamina
Loading...
Searching...
No Matches
Base64Utils.h
1#pragma once
2
3#include <string_view>
4
5#include "ll/api/base/StdInt.h"
6
7namespace ll::inline utils::base64_utils {
8namespace detail {
9constexpr uchar encodeLookup(uchar c) {
10 return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
11 "abcdefghijklmnopqrstuvwxyz"
12 "0123456789+/"[c];
13}
14constexpr uchar decodeLookup(uchar c) {
15 if (c >= 'A' && c <= 'Z') return c - 'A';
16 if (c >= 'a' && c <= 'z') return c - 71;
17 if (c >= '0' && c <= '9') return c + 4;
18 if (c == '+') return 62;
19 if (c == '/') return 63;
20 return 64;
21}
22} // namespace detail
23
24constexpr size_t getEncodeLength(size_t len) { return (len + 2 - ((len + 2) % 3)) / 3 * 4; }
25
26constexpr size_t getEncodeLength(std::string_view str) { return getEncodeLength(str.length()); }
27
28constexpr size_t getDecodeLength(std::string_view in) {
29 uchar count = 0;
30 size_t input_size = in.size();
31 for (auto it = in.rbegin(); it != in.rend() && *it == '='; ++it) {
32 ++count;
33 }
34 input_size -= count; // remove padding size
35 count = 0; // reset padding counter
36 while (input_size % 4) { // redo padding
37 input_size++;
38 count++;
39 }
40 return ((6 * input_size) / 8) - count;
41}
42
43constexpr std::string encode(std::string_view str) {
44 std::string result;
45 result.reserve(getEncodeLength(str));
46 int32_t i = 0;
47 int32_t j = -6;
48 for (auto& c : str) {
49 i = (i << 8) + static_cast<uint8_t>(c);
50 j += 8;
51 while (j >= 0) {
52 result += detail::encodeLookup((i >> j) & 0x3F);
53 j -= 6;
54 }
55 }
56 if (j > -6) {
57 result += detail::encodeLookup(((i << 8) >> (j + 8)) & 0x3F);
58 }
59 while (result.size() % 4) {
60 result.push_back('=');
61 }
62 return result;
63}
64
65constexpr std::string decode(std::string_view str) {
66 size_t input_size = str.size();
67 size_t output_size = getDecodeLength(str);
68 std::string out;
69 out.resize(output_size);
70 for (size_t i = 0, j = 0; i < input_size;) {
71 uint32_t c1 = (i > input_size || str[i] == '=') ? 0 & i++ : detail::decodeLookup(str[i++]);
72 uint32_t c2 = (i > input_size || str[i] == '=') ? 0 & i++ : detail::decodeLookup(str[i++]);
73 uint32_t c3 = (i > input_size || str[i] == '=') ? 0 & i++ : detail::decodeLookup(str[i++]);
74 uint32_t c4 = (i > input_size || str[i] == '=') ? 0 & i++ : detail::decodeLookup(str[i++]);
75
76 uint32_t data = (c1 << 3 * 6) + (c2 << 2 * 6) + (c3 << 1 * 6) + (c4 << 0 * 6);
77
78 if (j < output_size) out[j++] = static_cast<char>((data >> 2 * 8) & 0xFF);
79 if (j < output_size) out[j++] = static_cast<char>((data >> 1 * 8) & 0xFF);
80 if (j < output_size) out[j++] = static_cast<char>((data >> 0 * 8) & 0xFF);
81 }
82 return out;
83}
84} // namespace ll::inline utils::base64_utils