1 /* 2 3 Copyright (c) 2016, Arvid Norberg 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in 14 the documentation and/or other materials provided with the distribution. 15 * Neither the name of the author nor the names of its 16 contributors may be used to endorse or promote products derived 17 from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 POSSIBILITY OF SUCH DAMAGE. 30 31 */ 32 33 #ifndef TORRENT_AUX_IO_HPP_INCLUDED 34 #define TORRENT_AUX_IO_HPP_INCLUDED 35 36 #include <cstdint> 37 #include <string> 38 #include <type_traits> 39 #include "libtorrent/span.hpp" 40 #include "libtorrent/aux_/numeric_cast.hpp" 41 42 namespace libtorrent { namespace aux { 43 44 template <class T> struct type {}; 45 46 // reads an integer from a byte stream 47 // in big endian byte order and converts 48 // it to native endianess 49 template <class T, class Byte> 50 inline typename std::enable_if<sizeof(Byte)==1, T>::type read_impl(span<Byte> & view,type<T>)51 read_impl(span<Byte>& view, type<T>) 52 { 53 T ret = 0; 54 for (Byte const b : view.first(sizeof(T))) 55 { 56 ret <<= 8; 57 ret |= static_cast<std::uint8_t>(b); 58 } 59 view = view.subspan(int(sizeof(T))); 60 return ret; 61 } 62 63 template <class T, class In, class Byte> 64 inline typename std::enable_if<std::is_integral<T>::value 65 && (std::is_integral<In>::value || std::is_enum<In>::value) 66 && sizeof(Byte)==1>::type write_impl(In data,span<Byte> & view)67 write_impl(In data, span<Byte>& view) 68 { 69 T val = static_cast<T>(data); 70 TORRENT_ASSERT(data == static_cast<In>(val)); 71 int shift = int(sizeof(T)) * 8; 72 for (Byte& b : view.first(sizeof(T))) 73 { 74 shift -= 8; 75 b = static_cast<Byte>((val >> shift) & 0xff); 76 } 77 view = view.subspan(int(sizeof(T))); 78 } 79 80 // the single-byte case is separate to avoid a warning on the shift-left by 81 // 8 bits (which invokes undefined behavior) 82 83 template <class Byte> 84 inline typename std::enable_if<sizeof(Byte)==1, std::uint8_t>::type read_impl(span<Byte> & view,type<std::uint8_t>)85 read_impl(span<Byte>& view, type<std::uint8_t>) 86 { 87 std::uint8_t ret = static_cast<std::uint8_t>(view[0]); 88 view = view.subspan(1); 89 return ret; 90 } 91 92 template <class Byte> 93 inline typename std::enable_if<sizeof(Byte)==1, std::int8_t>::type read_impl(span<Byte> & view,type<std::int8_t>)94 read_impl(span<Byte>& view, type<std::int8_t>) 95 { 96 std::uint8_t ret = static_cast<std::int8_t>(view[0]); 97 view = view.subspan(1); 98 return ret; 99 } 100 101 // -- adaptors 102 103 template <typename Byte> read_int64(span<Byte> & view)104 std::int64_t read_int64(span<Byte>& view) 105 { return read_impl(view, type<std::int64_t>()); } 106 107 template <typename Byte> read_uint64(span<Byte> & view)108 std::uint64_t read_uint64(span<Byte>& view) 109 { return read_impl(view, type<std::uint64_t>()); } 110 111 template <typename Byte> read_uint32(span<Byte> & view)112 std::uint32_t read_uint32(span<Byte>& view) 113 { return read_impl(view, type<std::uint32_t>()); } 114 115 template <typename Byte> read_int32(span<Byte> & view)116 std::int32_t read_int32(span<Byte>& view) 117 { return read_impl(view, type<std::int32_t>()); } 118 119 template <typename Byte> read_int16(span<Byte> & view)120 std::int16_t read_int16(span<Byte>& view) 121 { return read_impl(view, type<std::int16_t>()); } 122 123 template <typename Byte> read_uint16(span<Byte> & view)124 std::uint16_t read_uint16(span<Byte>& view) 125 { return read_impl(view, type<std::uint16_t>()); } 126 127 template <typename Byte> read_int8(span<Byte> & view)128 std::int8_t read_int8(span<Byte>& view) 129 { return read_impl(view, type<std::int8_t>()); } 130 131 template <typename Byte> read_uint8(span<Byte> & view)132 std::uint8_t read_uint8(span<Byte>& view) 133 { return read_impl(view, type<std::uint8_t>()); } 134 135 136 template <typename T, typename Byte> write_uint64(T val,span<Byte> & view)137 void write_uint64(T val, span<Byte>& view) 138 { write_impl<std::uint64_t>(val, view); } 139 140 template <typename T, typename Byte> write_int64(T val,span<Byte> & view)141 void write_int64(T val, span<Byte>& view) 142 { write_impl<std::int64_t>(val, view); } 143 144 template <typename T, typename Byte> write_uint32(T val,span<Byte> & view)145 void write_uint32(T val, span<Byte>& view) 146 { write_impl<std::uint32_t>(val, view); } 147 148 template <typename T, typename Byte> write_int32(T val,span<Byte> & view)149 void write_int32(T val, span<Byte>& view) 150 { write_impl<std::int32_t>(val, view); } 151 152 template <typename T, typename Byte> write_uint16(T val,span<Byte> & view)153 void write_uint16(T val, span<Byte>& view) 154 { write_impl<std::uint16_t>(val, view); } 155 156 template <typename T, typename Byte> write_int16(T val,span<Byte> & view)157 void write_int16(T val, span<Byte>& view) 158 { write_impl<std::int16_t>(val, view); } 159 160 template <typename T, typename Byte> write_uint8(T val,span<Byte> & view)161 void write_uint8(T val, span<Byte>& view) 162 { write_impl<std::uint8_t>(val, view); } 163 164 template <typename T, typename Byte> write_int8(T val,span<Byte> & view)165 void write_int8(T val, span<Byte>& view) 166 { write_impl<std::int8_t>(val, view); } 167 168 template<typename Byte> write_string(std::string const & str,span<Byte> & view)169 inline int write_string(std::string const& str, span<Byte>& view) 170 { 171 TORRENT_ASSERT(view.size() >= numeric_cast<int>(str.size())); 172 std::copy(str.begin(), str.end(), view.begin()); 173 view = view.subspan(int(str.size())); 174 return int(str.size()); 175 } 176 177 }} 178 179 #endif // TORRENT_AUX_IO_HPP_INCLUDED 180