11 #include <restinio/exception.hpp> 12 #include <restinio/expected.hpp> 14 #include <restinio/utils/impl/bitops.hpp> 16 #include <restinio/impl/include_fmtlib.hpp> 39 return 1 == is_base64_char_lut<
unsigned char >()[
40 static_cast<
unsigned char>(c) ];
46 enum class expected_type { b64ch, b64ch_or_padding, padding };
51 expected_type expects = expected_type::b64ch;
52 std::uint_fast8_t b64chars_found = 0u;
53 std::uint_fast8_t paddings_found = 0u;
54 for(
const auto ch : str )
58 case expected_type::b64ch:
64 else if( is_base64_char( ch ) )
67 if( b64chars_found >= 2u )
68 expects = expected_type::b64ch_or_padding;
74 case expected_type::b64ch_or_padding:
78 expects = expected_type::padding;
81 else if( is_base64_char( ch ) )
90 case expected_type::padding:
95 if( paddings_found > 2u )
112 return static_cast<uint_type_t>(
static_cast<
unsigned char>(ch));
115 template<
unsigned int Shift>
127 const auto at = [&str](
auto index) {
return uch(str[index]); };
129 const auto alphabet_char = [](
auto ch) {
130 return static_cast<
char>(
131 base64_alphabet<
unsigned char >()[
132 static_cast<
unsigned char>(ch) ]);
135 constexpr std::size_t group_size = 3u;
136 const auto remaining = str.size() % group_size;
138 result.reserve( (str.size()/group_size + (remaining ? 1:0)) * 4 );
141 for(; i < str.size() - remaining; i += group_size )
143 uint_type_t bs = (at(i) << 16) | (at(i+1) << 8) | at(i+2);
145 result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
146 result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
147 result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
148 result.push_back( alphabet_char( sixbits_char<0>(bs) ) );
154 if( 1u == remaining )
156 uint_type_t bs = (at(i) << 16);
157 result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
158 result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
160 result.push_back(
'=');
164 uint_type_t bs = (at(i) << 16) | (at(i+1) << 8);
166 result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
167 result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
168 result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
171 result.push_back(
'=');
186 if( !is_valid_base64_string( str ) )
187 return make_unexpected( decoding_error_t::invalid_base64_sequence );
189 constexpr std::size_t group_size = 4;
192 result.reserve( (str.size() / group_size) * 3 );
194 const unsigned char *
const decode_table = base64_decode_lut<
unsigned char >();
196 const auto at = [&str](
auto index) {
197 return static_cast<
unsigned char>(str[index]);
200 for( size_t i = 0 ; i < str.size(); i += group_size)
204 int paddings_found = 0u;
206 bs |= decode_table[ at(i) ];
209 bs |= decode_table[ at(i+1) ];
212 if(
'=' == str[i+2] )
218 bs |= decode_table[ at(i+2) ];
222 if(
'=' == str[i+3] )
228 bs |= decode_table[ at(i+3) ];
231 using ::restinio::utils::impl::bitops::n_bits_from;
233 result.push_back( n_bits_from<
char, 16 >(bs) );
234 if( paddings_found < 2 )
236 result.push_back( n_bits_from<
char, 8 >(bs) );
238 if( paddings_found < 1 )
240 result.push_back( n_bits_from<
char, 0 >(bs) );
253 constexpr size_t max_allowed_len = 32u;
256 if( str.size() > max_allowed_len )
258 fmt::format(
"invalid base64 string that starts with '{}'",
259 str.substr( 0u, max_allowed_len ) )
263 fmt::format(
"invalid base64 string '{}'", str ) };
271 auto result = try_decode( str );
273 impl::throw_exception_on_invalid_base64_string( str );
275 return std::move( *result );
char sixbits_char(uint_type_t bs)
bool is_base64_char(char c) noexcept
bool is_valid_base64_string(string_view_t str) noexcept
expected_t< std::string, decoding_error_t > try_decode(string_view_t str)
std::string decode(string_view_t str)
decoding_error_t
Description of base64 decode error.
void normalize_to(string_view_t what, char *dest)
Perform normalization of URI value.
std::string encode(string_view_t str)
void throw_exception_on_invalid_base64_string(string_view_t str)
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container ¶ms, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...