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