110 padding(
size_t count,
size_t length) : count(count), length(length) {}
112 padding operator+(
const padding& p) {
return padding(count + p.count, length + p.length); }
114 friend bool operator==(
const padding& lhs,
const padding& rhs) {
115 return lhs.count == rhs.count && lhs.length == rhs.length;
119 inline padding count_padding(
const std::string& base,
const std::vector<std::string>& fills) {
120 for (
const auto& fill : fills) {
121 if (base.size() < fill.size())
continue;
123 if (base.substr(base.size() - fill.size()) == fill) {
124 return padding{1, fill.length()} +
125 count_padding(base.substr(0, base.size() - fill.size()), fills);
132 inline std::string encode(
const std::string& bin,
const std::array<char, 64>& alphabet,
133 const std::string& fill) {
134 size_t size = bin.size();
138 size_t fast_size = size - size % 3;
139 for (
size_t i = 0; i < fast_size;) {
140 uint32_t octet_a =
static_cast<unsigned char>(bin[i++]);
141 uint32_t octet_b =
static_cast<unsigned char>(bin[i++]);
142 uint32_t octet_c =
static_cast<unsigned char>(bin[i++]);
144 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
146 res += alphabet[(triple >> 3 * 6) & 0x3F];
147 res += alphabet[(triple >> 2 * 6) & 0x3F];
148 res += alphabet[(triple >> 1 * 6) & 0x3F];
149 res += alphabet[(triple >> 0 * 6) & 0x3F];
152 if (fast_size == size)
return res;
154 size_t mod = size % 3;
156 uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
157 uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
158 uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
160 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
164 res += alphabet[(triple >> 3 * 6) & 0x3F];
165 res += alphabet[(triple >> 2 * 6) & 0x3F];
170 res += alphabet[(triple >> 3 * 6) & 0x3F];
171 res += alphabet[(triple >> 2 * 6) & 0x3F];
172 res += alphabet[(triple >> 1 * 6) & 0x3F];
181 inline std::string decode(
const std::string& base,
const std::array<char, 64>& alphabet,
182 const std::vector<std::string>& fill) {
183 const auto pad = count_padding(base, fill);
184 if (pad.count > 2)
throw std::runtime_error(
"Invalid input: too much fill");
186 const size_t size = base.size() - pad.length;
187 if ((size + pad.count) % 4 != 0)
throw std::runtime_error(
"Invalid input: incorrect total size");
189 size_t out_size = size / 4 * 3;
191 res.reserve(out_size);
193 auto get_sextet = [&](
size_t offset) {
return alphabet::index(alphabet, base[offset]); };
195 size_t fast_size = size - size % 4;
196 for (
size_t i = 0; i < fast_size;) {
197 uint32_t sextet_a = get_sextet(i++);
198 uint32_t sextet_b = get_sextet(i++);
199 uint32_t sextet_c = get_sextet(i++);
200 uint32_t sextet_d = get_sextet(i++);
203 (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
205 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
206 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
207 res +=
static_cast<char>((triple >> 0 * 8) & 0xFFU);
210 if (pad.count == 0)
return res;
212 uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
216 triple |= (get_sextet(fast_size + 2) << 1 * 6);
217 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
218 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
220 case 2: res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
break;
227 inline std::string decode(
const std::string& base,
const std::array<char, 64>& alphabet,
228 const std::string& fill) {
229 return decode(base, alphabet, std::vector<std::string>{fill});
232 inline std::string pad(
const std::string& base,
const std::string& fill) {
234 switch (base.size() % 4) {
235 case 1: padding += fill; JWT_FALLTHROUGH;
236 case 2: padding += fill; JWT_FALLTHROUGH;
237 case 3: padding += fill; JWT_FALLTHROUGH;
241 return base + padding;
244 inline std::string trim(
const std::string& base,
const std::string& fill) {
245 auto pos = base.find(fill);
246 return base.substr(0, pos);
261 std::string
encode(
const std::string& bin) {
262 return details::encode(bin, T::data(), T::fill());
275 std::string
decode(
const std::string& base) {
276 return details::decode(base, T::data(), T::fill());
289 std::string
pad(
const std::string& base) {
290 return details::pad(base, T::fill());
303 std::string
trim(
const std::string& base) {
304 return details::trim(base, T::fill());