1 /* 2 3 Copyright (c) 2003-2018, 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_IO_HPP_INCLUDED 34 #define TORRENT_IO_HPP_INCLUDED 35 36 #include <cstdint> 37 #include <string> 38 #include <algorithm> // for copy 39 #include <cstring> // for memcpy 40 #include <type_traits> 41 #include <iterator> 42 43 #include "assert.hpp" 44 45 namespace libtorrent { 46 namespace detail { 47 48 template <class T> struct type {}; 49 50 // reads an integer from a byte stream 51 // in big endian byte order and converts 52 // it to native endianess 53 template <class T, class InIt> read_impl(InIt & start,type<T>)54 inline T read_impl(InIt& start, type<T>) 55 { 56 T ret = 0; 57 for (int i = 0; i < int(sizeof(T)); ++i) 58 { 59 ret <<= 8; 60 ret |= static_cast<std::uint8_t>(*start); 61 ++start; 62 } 63 return ret; 64 } 65 66 template <class InIt> read_impl(InIt & start,type<std::uint8_t>)67 std::uint8_t read_impl(InIt& start, type<std::uint8_t>) 68 { 69 return static_cast<std::uint8_t>(*start++); 70 } 71 72 template <class InIt> read_impl(InIt & start,type<std::int8_t>)73 std::int8_t read_impl(InIt& start, type<std::int8_t>) 74 { 75 return static_cast<std::int8_t>(*start++); 76 } 77 78 template <class T, class In, class OutIt> 79 typename std::enable_if<(std::is_integral<In>::value 80 && !std::is_same<In, bool>::value) 81 || std::is_enum<In>::value, void>::type write_impl(In data,OutIt & start)82 write_impl(In data, OutIt& start) 83 { 84 // Note: the test for [OutItT==void] below is necessary because 85 // in C++11 std::back_insert_iterator::value_type is void. 86 // This could change in C++17 or above 87 using OutItT = typename std::iterator_traits<OutIt>::value_type; 88 using Byte = typename std::conditional< 89 std::is_same<OutItT, void>::value, char, OutItT>::type; 90 static_assert(sizeof(Byte) == 1, "wrong iterator or pointer type"); 91 92 T val = static_cast<T>(data); 93 TORRENT_ASSERT(data == static_cast<In>(val)); 94 for (int i = int(sizeof(T)) - 1; i >= 0; --i) 95 { 96 *start = static_cast<Byte>((val >> (i * 8)) & 0xff); 97 ++start; 98 } 99 } 100 101 template <class T, class Val, class OutIt> 102 typename std::enable_if<std::is_same<Val, bool>::value, void>::type write_impl(Val val,OutIt & start)103 write_impl(Val val, OutIt& start) 104 { write_impl<T>(val ? 1 : 0, start); } 105 106 // -- adaptors 107 108 template <class InIt> read_int64(InIt & start)109 std::int64_t read_int64(InIt& start) 110 { return read_impl(start, type<std::int64_t>()); } 111 112 template <class InIt> read_uint64(InIt & start)113 std::uint64_t read_uint64(InIt& start) 114 { return read_impl(start, type<std::uint64_t>()); } 115 116 template <class InIt> read_uint32(InIt & start)117 std::uint32_t read_uint32(InIt& start) 118 { return read_impl(start, type<std::uint32_t>()); } 119 120 template <class InIt> read_int32(InIt & start)121 std::int32_t read_int32(InIt& start) 122 { return read_impl(start, type<std::int32_t>()); } 123 124 template <class InIt> read_int16(InIt & start)125 std::int16_t read_int16(InIt& start) 126 { return read_impl(start, type<std::int16_t>()); } 127 128 template <class InIt> read_uint16(InIt & start)129 std::uint16_t read_uint16(InIt& start) 130 { return read_impl(start, type<std::uint16_t>()); } 131 132 template <class InIt> read_int8(InIt & start)133 std::int8_t read_int8(InIt& start) 134 { return read_impl(start, type<std::int8_t>()); } 135 136 template <class InIt> read_uint8(InIt & start)137 std::uint8_t read_uint8(InIt& start) 138 { return read_impl(start, type<std::uint8_t>()); } 139 140 141 template <class T, class OutIt> write_uint64(T val,OutIt & start)142 void write_uint64(T val, OutIt& start) 143 { write_impl<std::uint64_t>(val, start); } 144 145 template <class T, class OutIt> write_int64(T val,OutIt & start)146 void write_int64(T val, OutIt& start) 147 { write_impl<std::int64_t>(val, start); } 148 149 template <class T, class OutIt> write_uint32(T val,OutIt & start)150 void write_uint32(T val, OutIt& start) 151 { write_impl<std::uint32_t>(val, start); } 152 153 template <class T, class OutIt> write_int32(T val,OutIt & start)154 void write_int32(T val, OutIt& start) 155 { write_impl<std::int32_t>(val, start); } 156 157 template <class T, class OutIt> write_uint16(T val,OutIt & start)158 void write_uint16(T val, OutIt& start) 159 { write_impl<std::uint16_t>(val, start); } 160 161 template <class T, class OutIt> write_int16(T val,OutIt & start)162 void write_int16(T val, OutIt& start) 163 { write_impl<std::int16_t>(val, start); } 164 165 template <class T, class OutIt> write_uint8(T val,OutIt & start)166 void write_uint8(T val, OutIt& start) 167 { write_impl<std::uint8_t>(val, start); } 168 169 template <class T, class OutIt> write_int8(T val,OutIt & start)170 void write_int8(T val, OutIt& start) 171 { write_impl<std::int8_t>(val, start); } 172 write_string(std::string const & str,char * & start)173 inline int write_string(std::string const& str, char*& start) 174 { 175 std::memcpy(reinterpret_cast<void*>(start), str.c_str(), str.size()); 176 start += str.size(); 177 return int(str.size()); 178 } 179 180 template <class OutIt> write_string(std::string const & val,OutIt & out)181 int write_string(std::string const& val, OutIt& out) 182 { 183 for (auto const c : val) *out++ = c; 184 return int(val.length()); 185 } 186 } // namespace detail 187 } 188 189 #endif // TORRENT_IO_HPP_INCLUDED 190