diff options
| -rw-r--r-- | rfc4251.H | 160 |
1 files changed, 48 insertions, 112 deletions
@@ -10,7 +10,7 @@ * those structs contain the objects in their RFC 4251 representation, * conversions are provided via constructors and cast operators * - * Copyright (C) 2013-2015 Timo Weingärtner <timo@tiwe.de> + * Copyright (C) 2013-2015,2021 Timo Weingärtner <timo@tiwe.de> * * This file is part of ssh-agent-filter. * @@ -28,132 +28,69 @@ * along with ssh-agent-filter. If not, see <http://www.gnu.org/licenses/>. */ +#include <type_traits> +#include <cstdint> +#include <array> #include <vector> #include <string> #include <iostream> #include <limits> #include <stdexcept> -#include <arpa/inet.h> // ntohl() / htonl() #include <gmpxx.h> #include <boost/operators.hpp> namespace rfc4251 { -struct byte { - union { - uint8_t value; - char buf[1]; - }; - - byte () = default; - explicit byte (uint8_t v) : value(v) {} - inline explicit byte (std::istream &); - - operator uint8_t () const { return value; } -}; - -inline std::istream & operator>> (std::istream & is, byte & x) { - return is.read(x.buf, sizeof(x.buf)); -} - -inline std::ostream & operator<< (std::ostream & os, byte const & x) { - return os.write(x.buf, sizeof(x.buf)); -} - -inline byte::byte (std::istream & is) { - is >> *this; -} - -struct boolean { - union { - bool value; - char buf[1]; - }; - - boolean () = default; - explicit boolean (uint8_t v) : value(v) {} - inline explicit boolean (std::istream &); - - operator uint8_t () const { return value; } -}; - -inline std::istream & operator>> (std::istream & is, boolean & x) { - return is.read(x.buf, sizeof(x.buf)); -} - -inline std::ostream & operator<< (std::ostream & os, boolean const & x) { - return os.write(x.buf, sizeof(x.buf)); -} - -inline boolean::boolean (std::istream & is) { - is >> *this; -} +namespace internal { + template<typename T> + constexpr inline auto host_to_network (T value) noexcept { + static_assert(std::is_unsigned_v<T>, "shift is only supported on unsigned"); + + std::array<char, sizeof(T)> ret; + for (auto it{rbegin(ret)}; it != rend(ret); ++it) { + *it = value & 0xff; + if constexpr (sizeof(T) > 1) value >>= 8; + } + return ret; + } -struct uint32 { - union { - uint32_t value; - char buf[4]; - }; + template<typename T> + constexpr inline auto network_to_host (std::array<char, sizeof(T)> const buf) noexcept { + static_assert(std::is_unsigned_v<T>, "shift is only supported on unsigned"); - uint32 () = default; - explicit uint32 (uint32_t v) { value = htonl(v); } - inline explicit uint32 (std::istream &); + T ret{0}; + for (auto it{cbegin(buf)}; it != cend(buf); ++it) { + if constexpr (sizeof(T) > 1) ret <<= 8; + ret |= static_cast<uint8_t>(*it); + } + return ret; + } - operator uint32_t () const { return ntohl(value); } -}; + template<typename T> + struct fixed_length { + static_assert(std::is_unsigned_v<T>, "support for signed types might need more work"); -inline std::istream & operator>> (std::istream & is, uint32 & x) { - return is.read(x.buf, sizeof(x.buf)); -} + std::array<char, sizeof(T)> buf{}; -inline std::ostream & operator<< (std::ostream & os, uint32 const & x) { - return os.write(x.buf, sizeof(x.buf)); -} + constexpr fixed_length () noexcept = default; + constexpr explicit fixed_length (T const v) noexcept : buf{host_to_network(v)} {} + explicit fixed_length (std::istream & is) { is >> *this; } -inline uint32::uint32 (std::istream & is) { - is >> *this; -} + constexpr operator T () const noexcept { return network_to_host<T>(buf); } -struct uint64 { - union { - uint64_t value; - char buf[8]; + friend std::istream & operator>> (std::istream & is, fixed_length & x) { + return is.read(x.buf.data(), x.buf.size()); + } + friend std::ostream & operator<< (std::ostream & os, fixed_length const & x) { + return os.write(x.buf.data(), x.buf.size()); + } }; - - uint64 () = default; - inline explicit uint64 (uint64_t v); - inline explicit uint64 (std::istream &); - - inline explicit operator uint64_t () const; -}; - -inline uint64::uint64 (uint64_t v) { - for (int_fast8_t i{7}; i >= 0; --i) { - buf[i] = v & 0xff; - v >>= 8; - } -} - -inline uint64::operator uint64_t () const { - uint64_t ret{0}; - for (uint_fast8_t i{0}; i < 8; ++i) { - ret <<= 8; - ret |= static_cast<uint8_t>(buf[i]); - } - return ret; } -inline std::istream & operator>> (std::istream & is, uint64 & x) { - return is.read(x.buf, sizeof(x.buf)); -} - -inline std::ostream & operator<< (std::ostream & os, uint64 const & x) { - return os.write(x.buf, sizeof(x.buf)); -} - -inline uint64::uint64 (std::istream & is) { - is >> *this; -} +using byte = internal::fixed_length<uint8_t>; +using boolean = internal::fixed_length<bool>; +using uint32 = internal::fixed_length<uint32_t>; +using uint64 = internal::fixed_length<uint64_t>; struct string : boost::totally_ordered<string> { std::vector<char> value; @@ -166,9 +103,9 @@ struct string : boost::totally_ordered<string> { explicit string (mpz_class const & x) : string{x.get_mpz_t()} {} inline explicit string (std::istream &); - size_t size () const { return value.size(); } - char const * data () const { return value.data(); } - char * data () { return value.data(); } + size_t size () const noexcept { return value.size(); } + char const * data () const noexcept { return value.data(); } + char * data () noexcept { return value.data(); } operator std::string () const { return {value.begin(), value.end()}; } operator std::vector<std::string> () const; @@ -183,8 +120,7 @@ inline string::string (char const * s, size_t l) { inline std::istream & operator>> (std::istream & is, string & s) { s.value.clear(); - uint32 len; - if (is >> len) { + if (uint32_t const len{uint32{is}}; is) { s.value.resize(len); is.read(s.value.data(), len); } |
