8 #ifdef __has_cpp_attribute
9 #if __has_cpp_attribute(fallthrough)
10 #define JWT_FALLTHROUGH [[fallthrough]]
14 #ifndef JWT_FALLTHROUGH
15 #define JWT_FALLTHROUGH
30 static const std::array<char, 64>&
data()
32 static constexpr std::array<char, 64>
data{
33 {
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
34 'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
35 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
36 'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/'}};
39 static const std::string&
fill()
41 static std::string
fill{
"="};
50 static const std::array<char, 64>&
data()
52 static constexpr std::array<char, 64>
data{
53 {
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
54 'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
55 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
56 'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'-',
'_'}};
59 static const std::string&
fill()
61 static std::string
fill{
"%3d"};
73 template <
typename T>
static std::string
encode(
const std::string& bin)
75 return encode(bin, T::data(), T::fill());
77 template <
typename T>
static std::string
decode(
const std::string&
base)
81 template <
typename T>
static std::string
pad(
const std::string&
base)
85 template <
typename T>
static std::string
trim(
const std::string&
base)
91 static std::string
encode(
const std::string& bin,
const std::array<char, 64>& alphabet,
92 const std::string& fill)
94 size_t size = bin.size();
98 size_t fast_size = size - size % 3;
99 for (
size_t i = 0; i < fast_size;)
101 uint32_t octet_a =
static_cast<unsigned char>(bin[i++]);
102 uint32_t octet_b =
static_cast<unsigned char>(bin[i++]);
103 uint32_t octet_c =
static_cast<unsigned char>(bin[i++]);
105 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
107 res += alphabet[(triple >> 3 * 6) & 0x3F];
108 res += alphabet[(triple >> 2 * 6) & 0x3F];
109 res += alphabet[(triple >> 1 * 6) & 0x3F];
110 res += alphabet[(triple >> 0 * 6) & 0x3F];
113 if (fast_size == size)
116 size_t mod = size % 3;
118 uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
119 uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
120 uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
122 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
127 res += alphabet[(triple >> 3 * 6) & 0x3F];
128 res += alphabet[(triple >> 2 * 6) & 0x3F];
133 res += alphabet[(triple >> 3 * 6) & 0x3F];
134 res += alphabet[(triple >> 2 * 6) & 0x3F];
135 res += alphabet[(triple >> 1 * 6) & 0x3F];
144 static std::string
decode(
const std::string& base,
const std::array<char, 64>& alphabet,
145 const std::string& fill)
147 size_t size = base.size();
150 while (size > fill.size())
152 if (base.substr(size - fill.size(), fill.size()) == fill)
157 throw std::runtime_error(
"Invalid input: too much fill");
163 if ((size + fill_cnt) % 4 != 0)
164 throw std::runtime_error(
"Invalid input: incorrect total size");
166 size_t out_size = size / 4 * 3;
168 res.reserve(out_size);
170 auto get_sextet = [&](
size_t offset)
172 for (
size_t i = 0; i < alphabet.size(); i++)
174 if (alphabet[i] == base[offset])
175 return static_cast<uint32_t
>(i);
177 throw std::runtime_error(
"Invalid input: not within alphabet");
180 size_t fast_size = size - size % 4;
181 for (
size_t i = 0; i < fast_size;)
183 uint32_t sextet_a = get_sextet(i++);
184 uint32_t sextet_b = get_sextet(i++);
185 uint32_t sextet_c = get_sextet(i++);
186 uint32_t sextet_d = get_sextet(i++);
188 uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) +
191 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
192 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
193 res +=
static_cast<char>((triple >> 0 * 8) & 0xFFU);
199 uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
204 triple |= (get_sextet(fast_size + 2) << 1 * 6);
205 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
206 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
208 case 2: res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
break;
215 static std::string
pad(
const std::string& base,
const std::string& fill)
218 switch (base.size() % 4)
226 return base + padding;
229 static std::string
trim(
const std::string& base,
const std::string& fill)
231 auto pos = base.find(fill);
232 return base.substr(0, pos);