5
5
#include < array>
6
6
#include < stdexcept>
7
7
#include < string>
8
- #include < vector>
8
+
9
+ #include " string_types.h"
9
10
10
11
#ifdef __has_cpp_attribute
11
12
#if __has_cpp_attribute(fallthrough)
@@ -37,10 +38,7 @@ namespace jwt {
37
38
' w' , ' x' , ' y' , ' z' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' , ' +' , ' /' }};
38
39
return data;
39
40
}
40
- static const std::string& fill () {
41
- static std::string fill{" =" };
42
- return fill;
43
- }
41
+ static std::array<string_constant, 1 > fill () { return std::array<string_constant, 1 >{" =" }; }
44
42
};
45
43
/* *
46
44
* \brief valid list of character when working with [Base64URL](https://tools.ietf.org/html/rfc4648#section-5)
@@ -60,10 +58,7 @@ namespace jwt {
60
58
' w' , ' x' , ' y' , ' z' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' , ' -' , ' _' }};
61
59
return data;
62
60
}
63
- static const std::string& fill () {
64
- static std::string fill{" %3d" };
65
- return fill;
66
- }
61
+ static std::array<string_constant, 1 > fill () { return std::array<string_constant, 1 >{" %3d" }; }
67
62
};
68
63
namespace helper {
69
64
/* *
@@ -81,15 +76,15 @@ namespace jwt {
81
76
' w' , ' x' , ' y' , ' z' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' , ' -' , ' _' }};
82
77
return data;
83
78
}
84
- static const std::initializer_list<std::string>& fill () {
85
- static std::initializer_list<std::string> fill{" %3D" , " %3d" };
86
- return fill;
87
- }
79
+ static std::array<string_constant, 2 > fill () { return std::array<string_constant, 2 >{" %3D" , " %3d" }; }
88
80
};
89
81
} // namespace helper
90
82
91
83
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; });
84
+ if (symbol >= ' A' && symbol <= ' Z' ) { return static_cast <uint32_t >(symbol - ' A' ); }
85
+ if (symbol >= ' a' && symbol <= ' z' ) { return static_cast <uint32_t >(26 + symbol - ' a' ); }
86
+ if (symbol >= ' 0' && symbol <= ' 9' ) { return static_cast <uint32_t >(52 + symbol - ' 0' ); }
87
+ auto itr = std::find (std::next (alphabet.cbegin (), 62U ), alphabet.cend (), symbol);
93
88
if (itr == alphabet.cend ()) { throw std::runtime_error (" Invalid input: not within alphabet" ); }
94
89
95
90
return std::distance (alphabet.cbegin (), itr);
@@ -116,30 +111,31 @@ namespace jwt {
116
111
}
117
112
};
118
113
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 ;
114
+ template <class StrInputIt >
115
+ padding count_padding (string_view base, StrInputIt fillStart, StrInputIt fillEnd) {
116
+ for (StrInputIt fillIt = fillStart; fillIt != fillEnd; ++fillIt) {
117
+ int fillLen = static_cast <int >(fillIt->size ());
118
+ int deltaLen = static_cast <int >(base.size ()) - fillLen;
122
119
// 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 );
120
+ if (deltaLen >= 0 && base.substr (deltaLen) == *fillIt ) {
121
+ return padding{1 , static_cast < size_t >(fillLen )} +
122
+ count_padding (base.substr (0 , deltaLen), fillStart, fillEnd );
126
123
}
127
124
}
128
125
129
126
return {};
130
127
}
131
128
132
- inline std::string encode (const std::string& bin, const std::array<char , 64 >& alphabet,
133
- const std::string& fill) {
129
+ inline std::string encode (string_view bin, const std::array<char , 64 >& alphabet, string_view fill) {
134
130
size_t size = bin.size ();
135
131
std::string res;
136
132
137
133
// clear incomplete bytes
138
134
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++ ]);
135
+ for (size_t i = 0 ; i < fast_size; i += 3 ) {
136
+ uint32_t octet_a = static_cast <unsigned char >(bin[i]);
137
+ uint32_t octet_b = static_cast <unsigned char >(bin[i + 1 ]);
138
+ uint32_t octet_c = static_cast <unsigned char >(bin[i + 2 ]);
143
139
144
140
uint32_t triple = (octet_a << 0x10 ) + (octet_b << 0x08 ) + octet_c;
145
141
@@ -178,9 +174,10 @@ namespace jwt {
178
174
return res;
179
175
}
180
176
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);
177
+ template <class StrInputIt >
178
+ inline std::string decode (string_view base, const std::array<char , 64 >& alphabet, StrInputIt fillStart,
179
+ StrInputIt fillEnd) {
180
+ const auto pad = count_padding (base, fillStart, fillEnd);
184
181
if (pad.count > 2 ) throw std::runtime_error (" Invalid input: too much fill" );
185
182
186
183
const size_t size = base.size () - pad.length ;
@@ -224,44 +221,42 @@ namespace jwt {
224
221
return res;
225
222
}
226
223
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;
224
+ inline std::string pad (string_view base, string_view fill) {
225
+ std::string res (base);
226
+ switch (res.size () % 4 ) {
227
+ case 1 : res += fill; JWT_FALLTHROUGH;
228
+ case 2 : res += fill; JWT_FALLTHROUGH;
229
+ case 3 : res += fill; JWT_FALLTHROUGH;
238
230
default : break ;
239
231
}
240
-
241
- return base + padding;
232
+ return res;
242
233
}
243
234
244
- inline std::string trim (const std::string& base, const std::string& fill) {
235
+ inline std::string trim (string_view base, string_view fill) {
245
236
auto pos = base.find (fill);
246
- return base.substr (0 , pos);
237
+ return static_cast <std::string>( base.substr (0 , pos) );
247
238
}
248
239
} // namespace details
249
240
250
241
template <typename T>
251
- std::string encode (const std::string& bin) {
252
- return details::encode (bin, T::data (), T::fill ());
242
+ std::string encode (string_view bin) {
243
+ static const auto fills = T::fill ();
244
+ return details::encode (bin, T::data (), fills.front ());
253
245
}
254
246
template <typename T>
255
- std::string decode (const std::string& base) {
256
- return details::decode (base, T::data (), T::fill ());
247
+ std::string decode (string_view base) {
248
+ static const auto fills = T::fill ();
249
+ return details::decode (base, T::data (), fills.begin (), fills.end ());
257
250
}
258
251
template <typename T>
259
- std::string pad (const std::string& base) {
260
- return details::pad (base, T::fill ());
252
+ std::string pad (string_view base) {
253
+ static const auto fills = T::fill ();
254
+ return details::pad (base, fills.front ());
261
255
}
262
256
template <typename T>
263
- std::string trim (const std::string& base) {
264
- return details::trim (base, T::fill ());
257
+ std::string trim (string_view base) {
258
+ static const auto fills = T::fill ();
259
+ return details::trim (base, fills.front ());
265
260
}
266
261
} // namespace base
267
262
} // namespace jwt
0 commit comments