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