2016-03-14 10:11:38 -04:00
|
|
|
#ifndef OSRM_BASE64_HPP
|
|
|
|
#define OSRM_BASE64_HPP
|
2014-11-28 04:07:06 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
#include <iterator>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <string>
|
2016-03-14 14:08:41 -04:00
|
|
|
#include <type_traits>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <vector>
|
2014-11-28 04:07:06 -05:00
|
|
|
|
2016-02-02 08:49:41 -05:00
|
|
|
#include <climits>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <cstddef>
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <boost/algorithm/string/trim.hpp>
|
2016-03-14 14:08:41 -04:00
|
|
|
#include <boost/archive/iterators/base64_from_binary.hpp>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <boost/archive/iterators/binary_from_base64.hpp>
|
2016-03-14 14:08:41 -04:00
|
|
|
#include <boost/archive/iterators/transform_width.hpp>
|
|
|
|
#include <boost/range/algorithm/copy.hpp>
|
|
|
|
|
2016-04-29 14:05:50 -04:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
|
2016-03-14 10:25:36 -04:00
|
|
|
// RFC 4648 "The Base16, Base32, and Base64 Data Encodings"
|
|
|
|
// See: https://tools.ietf.org/html/rfc4648
|
2016-03-14 14:08:41 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
namespace detail
|
|
|
|
{
|
2016-03-14 14:08:41 -04:00
|
|
|
// The C++ standard guarantees none of this by default, but we need it in the following.
|
|
|
|
static_assert(CHAR_BIT == 8u, "we assume a byte holds 8 bits");
|
|
|
|
static_assert(sizeof(char) == 1u, "we assume a char is one byte large");
|
2016-03-14 10:25:36 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
using Base64FromBinary = boost::archive::iterators::base64_from_binary<
|
|
|
|
boost::archive::iterators::transform_width<const char *, // sequence of chars
|
|
|
|
6, // get view of 6 bit
|
|
|
|
8 // from sequence of 8 bit
|
|
|
|
>>;
|
|
|
|
|
|
|
|
using BinaryFromBase64 = boost::archive::iterators::transform_width<
|
|
|
|
boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
|
|
|
|
8, // get a view of 8 bit
|
|
|
|
6 // from a sequence of 6 bit
|
|
|
|
>;
|
|
|
|
} // ns detail
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace engine
|
|
|
|
{
|
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// Encoding Implementation
|
|
|
|
|
|
|
|
// Encodes a chunk of memory to Base64.
|
|
|
|
inline std::string encodeBase64(const unsigned char *first, std::size_t size)
|
2016-02-02 08:49:41 -05:00
|
|
|
{
|
2016-03-24 07:31:05 -04:00
|
|
|
std::vector<unsigned char> bytes{first, first + size};
|
|
|
|
BOOST_ASSERT(!bytes.empty());
|
2016-03-14 14:08:41 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
std::size_t bytes_to_pad{0};
|
2016-03-14 14:08:41 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
while (bytes.size() % 3 != 0)
|
|
|
|
{
|
|
|
|
bytes_to_pad += 1;
|
|
|
|
bytes.push_back(0);
|
|
|
|
}
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2);
|
|
|
|
BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3");
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
std::string encoded{detail::Base64FromBinary{bytes.data()},
|
|
|
|
detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}};
|
2016-03-14 14:08:41 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
return encoded.append(bytes_to_pad, '=');
|
2016-03-14 14:08:41 -04:00
|
|
|
}
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// C++11 standard 3.9.1/1: Plain char, signed char, and unsigned char are three distinct types
|
|
|
|
|
|
|
|
// Overload for signed char catches (not only but also) C-string literals.
|
|
|
|
inline std::string encodeBase64(const signed char *first, std::size_t size)
|
|
|
|
{
|
|
|
|
return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overload for char catches (not only but also) C-string literals.
|
|
|
|
inline std::string encodeBase64(const char *first, std::size_t size)
|
|
|
|
{
|
|
|
|
return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience specialization, encoding from string instead of byte-dumping it.
|
|
|
|
inline std::string encodeBase64(const std::string &x) { return encodeBase64(x.data(), x.size()); }
|
|
|
|
|
|
|
|
// Encode any sufficiently trivial object to Base64.
|
|
|
|
template <typename T> std::string encodeBase64Bytewise(const T &x)
|
2014-11-28 04:07:06 -05:00
|
|
|
{
|
2016-02-02 09:09:32 -05:00
|
|
|
#if not defined __GNUC__ or __GNUC__ > 4
|
|
|
|
static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
|
|
|
|
#endif
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
return encodeBase64(reinterpret_cast<const unsigned char *>(&x), sizeof(T));
|
|
|
|
}
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// Decoding Implementation
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// Decodes into a chunk of memory that is at least as large as the input.
|
|
|
|
template <typename OutputIter> void decodeBase64(const std::string &encoded, OutputIter out)
|
|
|
|
{
|
2016-03-24 07:31:05 -04:00
|
|
|
auto unpadded = encoded;
|
2016-03-14 14:08:41 -04:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
const auto num_padded = std::count(begin(encoded), end(encoded), '=');
|
|
|
|
std::replace(begin(unpadded), end(unpadded), '=', 'A'); // A_64 == \0
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
std::string decoded{detail::BinaryFromBase64{begin(unpadded)},
|
|
|
|
detail::BinaryFromBase64{begin(unpadded) + unpadded.length()}};
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-24 07:31:05 -04:00
|
|
|
decoded.erase(end(decoded) - num_padded, end(decoded));
|
|
|
|
std::copy(begin(decoded), end(decoded), out);
|
2016-03-14 14:08:41 -04:00
|
|
|
}
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// Convenience specialization, filling string instead of byte-dumping into it.
|
|
|
|
inline std::string decodeBase64(const std::string &encoded)
|
|
|
|
{
|
|
|
|
std::string rv;
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
decodeBase64(encoded, std::back_inserter(rv));
|
|
|
|
|
|
|
|
return rv;
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
// Decodes from Base 64 to any sufficiently trivial object.
|
|
|
|
template <typename T> T decodeBase64Bytewise(const std::string &encoded)
|
2016-02-02 08:49:41 -05:00
|
|
|
{
|
2016-02-02 09:09:32 -05:00
|
|
|
#if not defined __GNUC__ or __GNUC__ > 4
|
|
|
|
static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
|
|
|
|
#endif
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
T x;
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
decodeBase64(encoded, reinterpret_cast<unsigned char *>(&x));
|
2016-02-02 08:49:41 -05:00
|
|
|
|
2016-03-14 14:08:41 -04:00
|
|
|
return x;
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
|
|
|
|
2016-02-02 08:49:41 -05:00
|
|
|
} // ns engine
|
|
|
|
} // ns osrm
|
|
|
|
|
2016-03-14 10:11:38 -04:00
|
|
|
#endif /* OSRM_BASE64_HPP */
|