mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 10:12:39 +01:00
ircd: Improve base64 suite.
This commit is contained in:
parent
c722ff6e71
commit
8c4925419a
2 changed files with 169 additions and 14 deletions
|
@ -48,9 +48,17 @@ namespace ircd
|
||||||
string_view u2a(const mutable_buffer &out, const const_raw_buffer &in);
|
string_view u2a(const mutable_buffer &out, const const_raw_buffer &in);
|
||||||
const_raw_buffer a2u(const mutable_raw_buffer &out, const const_buffer &in);
|
const_raw_buffer a2u(const mutable_raw_buffer &out, const const_buffer &in);
|
||||||
|
|
||||||
// Binary <-> Base64 conversion suite
|
// Binary -> Base64 conversion suite
|
||||||
string_view b64encode(const mutable_buffer &out, const const_raw_buffer &in);
|
string_view b64encode(const mutable_buffer &out, const const_raw_buffer &in);
|
||||||
|
std::string b64encode(const const_raw_buffer &in);
|
||||||
|
|
||||||
|
// Binary -> Base64 conversion without padding
|
||||||
string_view b64encode_unpadded(const mutable_buffer &out, const const_raw_buffer &in);
|
string_view b64encode_unpadded(const mutable_buffer &out, const const_raw_buffer &in);
|
||||||
|
std::string b64encode_unpadded(const const_raw_buffer &in);
|
||||||
|
|
||||||
|
// Base64 -> Binary conversion (padded or unpadded)
|
||||||
|
const_raw_buffer b64decode(const mutable_raw_buffer &out, const string_view &in);
|
||||||
|
std::string b64decode(const string_view &in);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ircd
|
namespace ircd
|
||||||
|
|
173
ircd/lexical.cc
173
ircd/lexical.cc
|
@ -31,9 +31,8 @@
|
||||||
#include <RB_INC_BOOST_TOKENIZER_HPP
|
#include <RB_INC_BOOST_TOKENIZER_HPP
|
||||||
#include <RB_INC_BOOST_LEXICAL_CAST_HPP
|
#include <RB_INC_BOOST_LEXICAL_CAST_HPP
|
||||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||||
#include <boost/archive/iterators/insert_linebreaks.hpp>
|
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||||
#include <boost/archive/iterators/transform_width.hpp>
|
#include <boost/archive/iterators/transform_width.hpp>
|
||||||
#include <boost/archive/iterators/ostream_iterator.hpp>
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -561,26 +560,174 @@ ircd::try_lex_cast<long double>(const string_view &s)
|
||||||
// ircd/stringops.h
|
// ircd/stringops.h
|
||||||
//
|
//
|
||||||
|
|
||||||
ircd::string_view
|
namespace ircd
|
||||||
ircd::b64encode_unpadded(const mutable_buffer &out,
|
|
||||||
const const_raw_buffer &in)
|
|
||||||
{
|
{
|
||||||
return rstrip(b64encode(out, in), '=');
|
const char _b64_pad_
|
||||||
|
{
|
||||||
|
'='
|
||||||
|
};
|
||||||
|
|
||||||
|
using _b64_encoder = std::function<string_view (const mutable_buffer &, const const_raw_buffer &)>;
|
||||||
|
static std::string _b64encode(const const_raw_buffer &in, const _b64_encoder &);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocate and return a string without padding from the encoding of in
|
||||||
|
std::string
|
||||||
|
ircd::b64encode_unpadded(const const_raw_buffer &in)
|
||||||
|
{
|
||||||
|
return _b64encode(in, [](const auto &out, const auto &in)
|
||||||
|
{
|
||||||
|
return b64encode_unpadded(out, in);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate and return a string from the encoding of in
|
||||||
|
std::string
|
||||||
|
ircd::b64encode(const const_raw_buffer &in)
|
||||||
|
{
|
||||||
|
return _b64encode(in, [](const auto &out, const auto &in)
|
||||||
|
{
|
||||||
|
return b64encode(out, in);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal; dedupes encoding functions that create and return a string
|
||||||
|
static std::string
|
||||||
|
ircd::_b64encode(const const_raw_buffer &in,
|
||||||
|
const _b64_encoder &encoder)
|
||||||
|
{
|
||||||
|
// Allocate a buffer 1.33 times larger than input with pessimistic
|
||||||
|
// extra space for any padding and nulling.
|
||||||
|
const auto max
|
||||||
|
{
|
||||||
|
ceil(size(in) * (4.0 / 3.0)) + 4
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
ret.resize(max, char{});
|
||||||
|
const mutable_buffer buf
|
||||||
|
{
|
||||||
|
const_cast<char *>(ret.data()), ret.size()
|
||||||
|
};
|
||||||
|
|
||||||
|
const string_view encoded
|
||||||
|
{
|
||||||
|
encoder(buf, in)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(size(encoded) <= ret.size());
|
||||||
|
ret.resize(size(encoded));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encoding in to base64 at out. Out must be 1.33+ larger than in
|
||||||
|
/// padding is not present in the returned view.
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::b64encode(const mutable_buffer &out,
|
ircd::b64encode(const mutable_buffer &out,
|
||||||
const const_raw_buffer &in)
|
const const_raw_buffer &in)
|
||||||
{
|
{
|
||||||
|
const auto pads
|
||||||
|
{
|
||||||
|
(3 - size(in) % 3) % 3
|
||||||
|
};
|
||||||
|
|
||||||
using transform = boost::archive::iterators::transform_width<unsigned char *, 6, 8>;
|
const auto encoded
|
||||||
using b64fb = boost::archive::iterators::base64_from_binary<transform>;
|
{
|
||||||
using ostream_iterator = boost::archive::iterators::ostream_iterator<char>;
|
b64encode_unpadded(out, in)
|
||||||
|
};
|
||||||
|
|
||||||
std::stringstream ss;
|
assert(size(encoded) + pads <= size(out));
|
||||||
std::copy(b64fb(data(in)), b64fb(data(in) + size(in)), ostream_iterator(ss));
|
memset(data(out) + size(encoded), _b64_pad_, pads);
|
||||||
const auto outlen(ss.str().copy(data(out), size(out)));
|
|
||||||
return { data(out), outlen };
|
const auto len
|
||||||
|
{
|
||||||
|
size(encoded) + pads
|
||||||
|
};
|
||||||
|
|
||||||
|
return { data(out), len };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encoding in to base64 at out. Out must be 1.33+ larger than in.
|
||||||
|
ircd::string_view
|
||||||
|
ircd::b64encode_unpadded(const mutable_buffer &out,
|
||||||
|
const const_raw_buffer &in)
|
||||||
|
{
|
||||||
|
namespace iterators = boost::archive::iterators;
|
||||||
|
using transform = iterators::transform_width<unsigned char *, 6, 8>;
|
||||||
|
using b64fb = iterators::base64_from_binary<transform>;
|
||||||
|
|
||||||
|
const auto cpsz
|
||||||
|
{
|
||||||
|
std::min(size(in), size_t(size(out) * (3.0 / 4.0)))
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto end
|
||||||
|
{
|
||||||
|
std::copy(b64fb(data(in)), b64fb(data(in) + cpsz), begin(out))
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto len
|
||||||
|
{
|
||||||
|
size_t(std::distance(begin(out), end))
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(len <= size(out));
|
||||||
|
return { data(out), len };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
ircd::b64decode(const string_view &in)
|
||||||
|
{
|
||||||
|
// Allocate a buffer 75% than input with pessimistic extra space
|
||||||
|
const auto max
|
||||||
|
{
|
||||||
|
ceil(size(in) * 0.75) + 4
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
ret.resize(max, char{});
|
||||||
|
const mutable_raw_buffer buf
|
||||||
|
{
|
||||||
|
reinterpret_cast<unsigned char *>(const_cast<char *>(ret.data())), ret.size()
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto decoded
|
||||||
|
{
|
||||||
|
b64decode(buf, in)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(size(decoded) <= ret.size());
|
||||||
|
ret.resize(size(decoded));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode base64 from in to the buffer at out; out can be 75% of the size
|
||||||
|
/// of in.
|
||||||
|
ircd::const_raw_buffer
|
||||||
|
ircd::b64decode(const mutable_raw_buffer &out,
|
||||||
|
const string_view &in)
|
||||||
|
{
|
||||||
|
namespace iterators = boost::archive::iterators;
|
||||||
|
using b64bf = iterators::binary_from_base64<const char *>;
|
||||||
|
using transform = iterators::transform_width<b64bf, 8, 6>;
|
||||||
|
|
||||||
|
const auto pads
|
||||||
|
{
|
||||||
|
endswith_count(in, _b64_pad_)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto e
|
||||||
|
{
|
||||||
|
std::copy(transform(begin(in)), transform(begin(in) + size(in) - pads), begin(out))
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto len
|
||||||
|
{
|
||||||
|
std::distance(begin(out), e)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(len <= size(out));
|
||||||
|
return { data(out), size_t(len) };
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::const_raw_buffer
|
ircd::const_raw_buffer
|
||||||
|
|
Loading…
Reference in a new issue