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:
67 if( b64chars_found >= 2u )
68 expects = expected_type::b64ch_or_padding;
74 case expected_type::b64ch_or_padding:
78 expects = expected_type::padding;
90 case expected_type::padding:
95 if( paddings_found > 2u )
112 return static_cast<uint_type_t>(
static_cast<unsigned char>(ch));
115template<
unsigned int Shift>
119 return ::restinio::utils::impl::bitops::n_bits_from< char, Shift, 6 >(bs);
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 )
157 result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
158 result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
160 result.push_back(
'=');
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(
'=');
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) ];
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 ) };
Exception class for all exceptions thrown by RESTinio.
A special wrapper around fmtlib include files.
void throw_exception_on_invalid_base64_string(string_view_t str)
char sixbits_char(uint_type_t bs)
std::uint_fast32_t uint_type_t
bool is_base64_char(char c) noexcept
std::string decode(string_view_t str)
bool is_valid_base64_string(string_view_t str) noexcept
expected_t< std::string, decoding_error_t > try_decode(string_view_t str)
decoding_error_t
Description of base64 decode error.
@ invalid_base64_sequence
std::string encode(string_view_t str)
T n_bits_from(F value)
Extract N bits from a bigger integer value.
nonstd::string_view string_view_t
nonstd::expected< T, E > expected_t