48 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
61 size_t char_len = (( input.size() / 3 ) + ( input.size() % 3 > 0 )) * 4;
62 size_t char_res = char_len;
63 if( line_length > 0 ) {
65 char_res += char_res / line_length - ( char_res % line_length == 0 );
67 encoded.reserve( char_res );
71 auto put_char = [&](
char c ){
73 assert( encoded.size() + 1 <= char_res );
74 assert( encoded.size() + 1 <= encoded.capacity() );
75 encoded.append( 1, c );
80 if( line_length > 0 && out_cnt % line_length == 0 && out_cnt < char_len ) {
81 assert( encoded.size() + 1 <= char_res );
82 assert( encoded.size() + 1 <= encoded.capacity() );
83 encoded.append( 1,
'\n' );
88 std::uint32_t temp = 0;
89 auto it = input.begin();
90 for( std::size_t i = 0; i < input.size() / 3; ++i ) {
96 assert( it != input.end() );
97 temp =
static_cast<std::uint32_t
>(
static_cast<unsigned char>( *it++ )) << 16;
98 assert( it != input.end() );
99 temp +=
static_cast<std::uint32_t
>(
static_cast<unsigned char>( *it++ )) << 8;
100 assert( it != input.end() );
101 temp +=
static_cast<std::uint32_t
>(
static_cast<unsigned char>( *it++ ));
111 switch( input.size() % 3 ) {
115 assert( it != input.end() );
116 temp =
static_cast<std::uint32_t
>(
static_cast<unsigned char>( *it++ )) << 16;
117 assert( it != input.end() );
118 temp +=
static_cast<std::uint32_t
>(
static_cast<unsigned char>( *it++ )) << 8;
130 assert( it != input.end() );
131 temp = (*it++) << 16;
141 assert( it == input.end() );
147 assert( encoded.size() == char_res );
155 if( input.size() == 0 ) {
164 for(
auto c : input ) {
166 static_assert( (
int)
true == 1 && (
int)
false == 0,
"Boolean counting does not work." );
170 throw std::runtime_error(
"Invalid base64 length that is not a multiple of 4");
174 std::size_t padding = 0;
175 assert( char_cnt >= 4 );
187 size_t const char_res = (( char_cnt / 4 ) * 3 ) - padding;
188 decoded.reserve( char_res );
191 std::uint32_t temp = 0;
194 static_assert( 0x41 ==
'A' && 0x5A ==
'Z',
"Non-ASCII encoding detected. We expect ASCII." );
195 static_assert( 0x61 ==
'a' && 0x7A ==
'z',
"Non-ASCII encoding detected. We expect ASCII." );
196 static_assert( 0x30 ==
'0' && 0x39 ==
'9',
"Non-ASCII encoding detected. We expect ASCII." );
197 static_assert( 0x2B ==
'+' && 0x2F ==
'/',
"Non-ASCII encoding detected. We expect ASCII." );
200 auto it = input.begin();
201 while( it < input.end() ) {
204 for( std::size_t i = 0; i < 4; ++i ) {
213 if ( *it >= 0x41 && *it <= 0x5A ) {
215 }
else if( *it >= 0x61 && *it <= 0x7A ) {
217 }
else if( *it >= 0x30 && *it <= 0x39 ) {
219 }
else if( *it == 0x2B ) {
221 }
else if( *it == 0x2F ) {
224 switch( input.end() - it ) {
227 assert( decoded.size() + 2 <= char_res );
228 assert( decoded.size() + 2 <= decoded.capacity() );
229 decoded.push_back(( temp >> 16 ) & 0x000000FF );
230 decoded.push_back(( temp >> 8 ) & 0x000000FF );
235 assert( decoded.size() + 1 <= char_res );
236 assert( decoded.size() + 1 <= decoded.capacity() );
237 decoded.push_back(( temp >> 10 ) & 0x000000FF );
241 throw std::runtime_error(
"Invalid padding in base64 decoding" );
245 throw std::runtime_error(
"Invalid character in base64 decoding" );
251 assert( decoded.size() + 3 <= char_res );
252 assert( decoded.size() + 3 <= decoded.capacity() );
253 decoded.push_back(( temp >> 16 ) & 0x000000FF );
254 decoded.push_back(( temp >> 8 ) & 0x000000FF );
255 decoded.push_back(( temp ) & 0x000000FF );
259 assert( decoded.size() == char_res );
267 std::string
base64_encode( std::vector<std::uint8_t>
const& input,
size_t line_length )
279 using ContainerType = std::vector<std::uint8_t>;
280 return base64_decode_<ContainerType>( input );
285 using ContainerType = std::string;
286 return base64_decode_<ContainerType>( input );