diff --git a/include/ircd/base64.h b/include/ircd/base64.h new file mode 100644 index 000000000..da6d4352e --- /dev/null +++ b/include/ircd/base64.h @@ -0,0 +1,27 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_BASE64_H + +namespace ircd +{ + // Binary -> Base64 conversion suite + 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); + 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); +} diff --git a/include/ircd/lex_cast.h b/include/ircd/lex_cast.h index 62b70ccd8..590a8b681 100644 --- a/include/ircd/lex_cast.h +++ b/include/ircd/lex_cast.h @@ -47,18 +47,6 @@ namespace ircd // Binary <-> Hex conversion suite 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); - - // Binary -> Base64 conversion suite - 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); - 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 diff --git a/ircd/base64.cc b/ircd/base64.cc new file mode 100644 index 000000000..5cff71f53 --- /dev/null +++ b/ircd/base64.cc @@ -0,0 +1,181 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#include +#include +#include + +namespace ircd +{ + const char _b64_pad_ + { + '=' + }; + + using _b64_encoder = std::function; + 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(max, char{}); + const mutable_buffer buf + { + const_cast(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::b64encode(const mutable_buffer &out, + const const_raw_buffer &in) +{ + const auto pads + { + (3 - size(in) % 3) % 3 + }; + + const auto encoded + { + b64encode_unpadded(out, in) + }; + + assert(size(encoded) + pads <= size(out)); + memset(data(out) + size(encoded), _b64_pad_, pads); + + 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; + using b64fb = iterators::base64_from_binary; + + 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(max, char{}); + const mutable_raw_buffer buf + { + reinterpret_cast(const_cast(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; + using transform = iterators::transform_width; + + 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(size_t(len) <= size(out)); + return { data(out), size_t(len) }; +} diff --git a/ircd/lexical.cc b/ircd/lexical.cc index 6147fb910..4e4ed3940 100644 --- a/ircd/lexical.cc +++ b/ircd/lexical.cc @@ -30,9 +30,6 @@ #include -#include -#include /////////////////////////////////////////////////////////////////////////////// // @@ -665,174 +662,6 @@ ircd::replace(const string_view &s, return ret; } -namespace ircd -{ - const char _b64_pad_ - { - '=' - }; - - using _b64_encoder = std::function; - 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(max, char{}); - const mutable_buffer buf - { - const_cast(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::b64encode(const mutable_buffer &out, - const const_raw_buffer &in) -{ - const auto pads - { - (3 - size(in) % 3) % 3 - }; - - const auto encoded - { - b64encode_unpadded(out, in) - }; - - assert(size(encoded) + pads <= size(out)); - memset(data(out) + size(encoded), _b64_pad_, pads); - - 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; - using b64fb = iterators::base64_from_binary; - - 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(max, char{}); - const mutable_raw_buffer buf - { - reinterpret_cast(const_cast(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; - using transform = iterators::transform_width; - - 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(size_t(len) <= size(out)); - return { data(out), size_t(len) }; -} - ircd::const_raw_buffer ircd::a2u(const mutable_raw_buffer &out, const const_buffer &in)