From d7def063b6868955a67d4e00862a36641f5d7ea2 Mon Sep 17 00:00:00 2001
From: Jason Volk <jason@zemos.net>
Date: Fri, 22 Sep 2017 15:50:28 -0700
Subject: [PATCH] ircd: Add tools for binary/hex/b64 conversions.

---
 include/ircd/lexical.h | 16 ++++++++
 ircd/lexical.cc        | 89 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/include/ircd/lexical.h b/include/ircd/lexical.h
index 6bf080562..ae4ad7020 100644
--- a/include/ircd/lexical.h
+++ b/include/ircd/lexical.h
@@ -87,6 +87,22 @@ namespace ircd
 	const size_t LEX_CAST_BUFS {256}; // plenty
 	template<class T> string_view lex_cast(const T &t);
 
+	//
+	// Binary / Hex / Base64 conversion suite
+	//
+
+	// Binary buffer to null terminated string of hex (out must be 2*in + 1).
+	string_view u2a(const mutable_buffer &out, const uint8_t *const &in, const size_t &len);
+	string_view u2a(const mutable_buffer &out, const const_buffer &in);
+
+	// String of hex to binary buffer.
+	const_buffer a2u(uint8_t *const &out, const size_t &max, const const_buffer &in);
+	const_buffer a2u(const mutable_buffer &out, const const_buffer &in);
+
+	// Binary buffer to string of base64
+	string_view b64encode(const mutable_buffer &out, const uint8_t *const &in, const size_t &len);
+	string_view b64encode(const mutable_buffer &out, const const_buffer &in);
+
 	//
 	// String tokenization.
 	//
diff --git a/ircd/lexical.cc b/ircd/lexical.cc
index 23af92af5..c37945b5e 100644
--- a/ircd/lexical.cc
+++ b/ircd/lexical.cc
@@ -22,6 +22,10 @@
 
 #include <RB_INC_BOOST_TOKENIZER_HPP
 #include <RB_INC_BOOST_LEXICAL_CAST_HPP
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/insert_linebreaks.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/archive/iterators/ostream_iterator.hpp>
 
 ircd::string_view
 ircd::tokens_after(const string_view &str,
@@ -231,6 +235,91 @@ ircd::tokens(const string_view &str,
 	std::for_each(begin(view), end(view), closure);
 }
 
+ircd::string_view
+ircd::b64encode(const mutable_buffer &out,
+                const const_buffer &in)
+{
+	const auto ptr
+	{
+		reinterpret_cast<const uint8_t *>(data(in))
+	};
+
+	return b64encode(out, ptr, size(in));
+}
+
+ircd::string_view
+ircd::b64encode(const mutable_buffer &out,
+                const uint8_t *const &in,
+                const size_t &len)
+{
+
+	using transform = boost::archive::iterators::transform_width<unsigned char *, 6, 8>;
+	using b64fb = boost::archive::iterators::base64_from_binary<transform>;
+	using ostream_iterator = boost::archive::iterators::ostream_iterator<char>;
+
+	std::stringstream ss;
+	std::copy(b64fb(in), b64fb(in + len), ostream_iterator(ss));
+	const auto outlen(ss.str().copy(data(out), size(out)));
+	return { data(out), outlen };
+}
+
+ircd::const_buffer
+ircd::a2u(const mutable_buffer &out,
+          const const_buffer &in)
+{
+	const auto ptr
+	{
+		reinterpret_cast<uint8_t *>(data(out))
+	};
+
+	return a2u(ptr, size(out), in);
+}
+
+ircd::const_buffer
+ircd::a2u(uint8_t *const &out,
+          const size_t &max,
+          const const_buffer &in)
+{
+	const size_t len{size(in) / 2};
+	for(size_t i(0); i < len; ++i)
+	{
+		const char gl[3]
+		{
+			in[i * 2],
+			in[i * 2 + 1],
+			'\0'
+		};
+
+		out[i] = strtol(gl, nullptr, 16);
+	}
+
+	return { reinterpret_cast<const char *>(out), len };
+}
+
+ircd::string_view
+ircd::u2a(const mutable_buffer &out,
+          const const_buffer &in)
+{
+	const auto ptr
+	{
+		reinterpret_cast<const uint8_t *>(data(in))
+	};
+
+	return u2a(out, ptr, size(in));
+}
+
+ircd::string_view
+ircd::u2a(const mutable_buffer &out,
+          const uint8_t *const &in,
+          const size_t &len)
+{
+	char *p(data(out));
+	for(size_t i(0); i < len; ++i)
+		p += snprintf(p, size(out) - (p - data(out)), "%02x", in[i]);
+
+	return { data(out), size_t(p - data(out)) };
+}
+
 namespace ircd {
 
 const size_t LEX_CAST_BUFSIZE {64};