Conscience Core
base.h
Go to the documentation of this file.
1 #ifndef JWT_CPP_BASE_H
2 #define JWT_CPP_BASE_H
3 
4 #include <algorithm>
5 #include <array>
6 #include <stdexcept>
7 #include <string>
8 #include <vector>
9 
10 #ifdef __has_cpp_attribute
11 #if __has_cpp_attribute(fallthrough)
12 #define JWT_FALLTHROUGH [[fallthrough]]
13 #endif
14 #endif
15 
16 #ifndef JWT_FALLTHROUGH
17 #define JWT_FALLTHROUGH
18 #endif
19 
20 namespace jwt {
24  namespace alphabet {
31  struct base64 {
32  static const std::array<char, 64>& data() {
33  static constexpr std::array<char, 64> data{
34  {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
35  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
36  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
37  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
38  return data;
39  }
40  static const std::string& fill() {
41  static std::string fill{"="};
42  return fill;
43  }
44  };
54  struct base64url {
55  static const std::array<char, 64>& data() {
56  static constexpr std::array<char, 64> data{
57  {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
58  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
59  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
60  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
61  return data;
62  }
63  static const std::string& fill() {
64  static std::string fill{"%3d"};
65  return fill;
66  }
67  };
68  namespace helper {
76  static const std::array<char, 64>& data() {
77  static constexpr std::array<char, 64> data{
78  {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
79  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
80  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
81  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
82  return data;
83  }
84  static const std::initializer_list<std::string>& fill() {
85  static std::initializer_list<std::string> fill{"%3D", "%3d"};
86  return fill;
87  }
88  };
89  } // namespace helper
90 
91  inline uint32_t index(const std::array<char, 64>& alphabet, char symbol) {
92  auto itr = std::find_if(alphabet.cbegin(), alphabet.cend(), [symbol](char c) { return c == symbol; });
93  if (itr == alphabet.cend()) { throw std::runtime_error("Invalid input: not within alphabet"); }
94 
95  return std::distance(alphabet.cbegin(), itr);
96  }
97  } // namespace alphabet
98 
102  namespace base {
103 
104  namespace details {
105  struct padding {
106  size_t count = 0;
107  size_t length = 0;
108 
109  padding() = default;
110  padding(size_t count, size_t length) : count(count), length(length) {}
111 
112  padding operator+(const padding& p) { return padding(count + p.count, length + p.length); }
113 
114  friend bool operator==(const padding& lhs, const padding& rhs) {
115  return lhs.count == rhs.count && lhs.length == rhs.length;
116  }
117  };
118 
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;
122  // Does the end of the input exactly match the fill pattern?
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);
126  }
127  }
128 
129  return {};
130  }
131 
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();
135  std::string res;
136 
137  // clear incomplete bytes
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++]);
143 
144  uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
145 
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];
150  }
151 
152  if (fast_size == size) return res;
153 
154  size_t mod = size % 3;
155 
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;
159 
160  uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
161 
162  switch (mod) {
163  case 1:
164  res += alphabet[(triple >> 3 * 6) & 0x3F];
165  res += alphabet[(triple >> 2 * 6) & 0x3F];
166  res += fill;
167  res += fill;
168  break;
169  case 2:
170  res += alphabet[(triple >> 3 * 6) & 0x3F];
171  res += alphabet[(triple >> 2 * 6) & 0x3F];
172  res += alphabet[(triple >> 1 * 6) & 0x3F];
173  res += fill;
174  break;
175  default: break;
176  }
177 
178  return res;
179  }
180 
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");
185 
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");
188 
189  size_t out_size = size / 4 * 3;
190  std::string res;
191  res.reserve(out_size);
192 
193  auto get_sextet = [&](size_t offset) { return alphabet::index(alphabet, base[offset]); };
194 
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++);
201 
202  uint32_t triple =
203  (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
204 
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);
208  }
209 
210  if (pad.count == 0) return res;
211 
212  uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
213 
214  switch (pad.count) {
215  case 1:
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);
219  break;
220  case 2: res += static_cast<char>((triple >> 2 * 8) & 0xFFU); break;
221  default: break;
222  }
223 
224  return res;
225  }
226 
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});
230  }
231 
232  inline std::string pad(const std::string& base, const std::string& fill) {
233  std::string padding;
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;
238  default: break;
239  }
240 
241  return base + padding;
242  }
243 
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);
247  }
248  } // namespace details
249 
250  template<typename T>
251  std::string encode(const std::string& bin) {
252  return details::encode(bin, T::data(), T::fill());
253  }
254  template<typename T>
255  std::string decode(const std::string& base) {
256  return details::decode(base, T::data(), T::fill());
257  }
258  template<typename T>
259  std::string pad(const std::string& base) {
260  return details::pad(base, T::fill());
261  }
262  template<typename T>
263  std::string trim(const std::string& base) {
264  return details::trim(base, T::fill());
265  }
266  } // namespace base
267 } // namespace jwt
268 
269 #endif
jwt::alphabet::base64url::data
static const std::array< char, 64 > & data()
Definition: base.h:55
jwt::base::details::padding::length
size_t length
Definition: base.h:107
jwt::base::details::padding
Definition: base.h:105
jwt::base::pad
std::string pad(const std::string &base)
Definition: base.h:259
jwt::base::details::trim
std::string trim(const std::string &base, const std::string &fill)
Definition: base.h:244
jwt::base::details::encode
std::string encode(const std::string &bin, const std::array< char, 64 > &alphabet, const std::string &fill)
Definition: base.h:132
jwt::base::details::padding::padding
padding()=default
jwt::alphabet::base64url::fill
static const std::string & fill()
Definition: base.h:63
jwt::base::trim
std::string trim(const std::string &base)
Definition: base.h:263
jwt::alphabet::helper::base64url_percent_encoding
A General purpose base64url alphabet respecting the URI Case Normalization
Definition: base.h:75
jwt::base::details::padding::operator+
padding operator+(const padding &p)
Definition: base.h:112
jwt
JSON Web Token.
Definition: base.h:20
jwt::base::details::pad
std::string pad(const std::string &base, const std::string &fill)
Definition: base.h:232
jwt::alphabet::index
uint32_t index(const std::array< char, 64 > &alphabet, char symbol)
Definition: base.h:91
jwt::base::details::padding::padding
padding(size_t count, size_t length)
Definition: base.h:110
jwt::alphabet::base64url
valid list of character when working with Base64URL
Definition: base.h:54
jwt::base::details::count_padding
padding count_padding(const std::string &base, const std::vector< std::string > &fills)
Definition: base.h:119
jwt::base::details::padding::count
size_t count
Definition: base.h:106
jwt::alphabet::base64::fill
static const std::string & fill()
Definition: base.h:40
jwt::base::details::padding::operator==
friend bool operator==(const padding &lhs, const padding &rhs)
Definition: base.h:114
jwt::alphabet::base64
valid list of character when working with Base64
Definition: base.h:31
JWT_FALLTHROUGH
#define JWT_FALLTHROUGH
Definition: base.h:17
jwt::alphabet::base64::data
static const std::array< char, 64 > & data()
Definition: base.h:32
c
double c
Definition: HybridAStar.cpp:84
jwt::base::encode
std::string encode(const std::string &bin)
Definition: base.h:251
jwt::alphabet::helper::base64url_percent_encoding::fill
static const std::initializer_list< std::string > & fill()
Definition: base.h:84
jwt::base::details::decode
std::string decode(const std::string &base, const std::array< char, 64 > &alphabet, const std::vector< std::string > &fill)
Definition: base.h:181
jwt::base::decode
std::string decode(const std::string &base)
Definition: base.h:255
jwt::alphabet::helper::base64url_percent_encoding::data
static const std::array< char, 64 > & data()
Definition: base.h:76
i
int i
Definition: HybridAStar.cpp:191