I've been able to encode a std::vector<char>
to Base64 using boost and the following code:
using namespace boost::archive::iterators;
std::string message(binary.begin(), binary.end());
std::stringstream os;
using base64_text = insert_linebreaks<base64_from_binary<transform_width<const char *, 6, 8>>, 72>;
std::copy(
base64_text(message.c_str()),
base64_text(message.c_str() + message.size()),
ostream_iterator<char>(os)
);
return os.str();
I found this on Stackoverflow. Well, now I want to to the same thing backwards, putting in a Base64 formatted std::string
and end up with a std::vector<char>
. But I can't adapt my example to do the thing in reverse. I found some other code online, which works nice with a Hello World example, but when there's an actual bigger Base64 which also contains some critical characters like backslashes, the whole thing crashes.
This is what I'm doing now to decode:
using namespace std;
using namespace boost::archive::iterators;
typedef
transform_width<
binary_from_base64<string::const_iterator>, 8, 6
> binary_t;
string dec(binary_t(str.begin()), binary_t(str.end()));
return dec;
It crashes in the last line before the return, when I'm about to create the string. Do you see what's wrong with it?
base64
requires both input and output to be padded into multiples of 3 and 4 respectively.
Here's a function for decoding base64 using boost
:
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <algorithm>
std::string decode(std::string input)
{
using namespace boost::archive::iterators;
typedef transform_width<binary_from_base64<remove_whitespace
<std::string::const_iterator> >, 8, 6> ItBinaryT;
try
{
// If the input isn't a multiple of 4, pad with =
size_t num_pad_chars((4 - input.size() % 4) % 4);
input.append(num_pad_chars, '=');
size_t pad_chars(std::count(input.begin(), input.end(), '='));
std::replace(input.begin(), input.end(), '=', 'A');
std::string output(ItBinaryT(input.begin()), ItBinaryT(input.end()));
output.erase(output.end() - pad_chars, output.end());
return output;
}
catch (std::exception const&)
{
return std::string("");
}
}
It was taken from here, where an encoding function with padding using boost
can also be found.
I tried kenba's accepted solution and ran into a few problems I've fixed below. First, trailing whitespace will cause any remove_whitespace iterator to skip past end(), causing a memory fault. Second, because you are calculating padding on the unfiltered string, any base64 encoded string which has whitespace in it will yield the incorrect number of pad_chars. The solution is to pre-filter whitespace before doing anything else with the string.
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <algorithm>
inline void decode_base64( std::string input, std::vector<char>& output )
{
using namespace boost::archive::iterators;
typedef remove_whitespace<std::string::const_iterator> StripIt;
typedef transform_width<binary_from_base64<std::string::const_iterator>, 8, 6> ItBinaryT;
try
{
/// Trailing whitespace makes remove_whitespace barf because the iterator never == end().
while (!input.empty() && std::isspace( input.back() )) { input.pop_back(); }
input.swap( std::string( StripIt( input.begin() ), StripIt( input.end() ) ) );
/// If the input isn't a multiple of 4, pad with =
input.append( (4 - input.size() % 4) % 4, '=' );
size_t pad_chars( std::count( input.end() - 4, input.end(), '=' ) );
std::replace( input.end() - 4, input.end(), '=', 'A' );
output.clear();
output.reserve( input.size() * 1.3334 );
output.assign( ItBinaryT( input.begin() ), ItBinaryT( input.end() ) );
output.erase( output.end() - (pad_chars < 2 ? pad_chars : 2), output.end() );
}
catch (std::exception const&)
{
output.clear();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With