/src/libtorrent/include/libtorrent/bencode.hpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | Copyright (c) 2003-2005, 2007-2009, 2012-2019, Arvid Norberg |
4 | | Copyright (c) 2016, Alden Torres |
5 | | Copyright (c) 2019, Amir Abrams |
6 | | All rights reserved. |
7 | | |
8 | | Redistribution and use in source and binary forms, with or without |
9 | | modification, are permitted provided that the following conditions |
10 | | are met: |
11 | | |
12 | | * Redistributions of source code must retain the above copyright |
13 | | notice, this list of conditions and the following disclaimer. |
14 | | * Redistributions in binary form must reproduce the above copyright |
15 | | notice, this list of conditions and the following disclaimer in |
16 | | the documentation and/or other materials provided with the distribution. |
17 | | * Neither the name of the author nor the names of its |
18 | | contributors may be used to endorse or promote products derived |
19 | | from this software without specific prior written permission. |
20 | | |
21 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
22 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
25 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | | POSSIBILITY OF SUCH DAMAGE. |
32 | | |
33 | | */ |
34 | | |
35 | | #ifndef TORRENT_BENCODE_HPP_INCLUDED |
36 | | #define TORRENT_BENCODE_HPP_INCLUDED |
37 | | |
38 | | // OVERVIEW |
39 | | // |
40 | | // Bencoding is a common representation in bittorrent used for dictionary, |
41 | | // list, int and string hierarchies. It's used to encode .torrent files and |
42 | | // some messages in the network protocol. libtorrent also uses it to store |
43 | | // settings, resume data and other session state. |
44 | | // |
45 | | // Strings in bencoded structures do not necessarily represent text. |
46 | | // Strings are raw byte buffers of a certain length. If a string is meant to be |
47 | | // interpreted as text, it is required to be UTF-8 encoded. See `BEP 3`_. |
48 | | // |
49 | | // The function for decoding bencoded data bdecode(), returning a bdecode_node. |
50 | | // This function builds a tree that points back into the original buffer. The |
51 | | // returned bdecode_node will not be valid once the buffer it was parsed out of |
52 | | // is discarded. |
53 | | // |
54 | | // It's possible to construct an entry from a bdecode_node, if a structure needs |
55 | | // to be altered and re-encoded. |
56 | | |
57 | | #include <string> |
58 | | #include <iterator> // for distance |
59 | | |
60 | | #include "libtorrent/config.hpp" |
61 | | #include "libtorrent/entry.hpp" |
62 | | #include "libtorrent/assert.hpp" |
63 | | #include "libtorrent/io.hpp" // for write_string |
64 | | #include "libtorrent/string_util.hpp" // for is_digit |
65 | | |
66 | | namespace libtorrent { |
67 | | |
68 | | #if TORRENT_ABI_VERSION == 1 |
69 | | using invalid_encoding = system_error; |
70 | | #endif |
71 | | |
72 | | namespace aux { |
73 | | |
74 | | template <class OutIt, class In, typename Cond |
75 | | = typename std::enable_if<std::is_integral<In>::value>::type> |
76 | | int write_integer(OutIt& out, In data) |
77 | 3.11M | { |
78 | 3.11M | entry::integer_type const val = entry::integer_type(data); |
79 | 3.11M | TORRENT_ASSERT(data == In(val)); |
80 | | // the stack allocated buffer for keeping the |
81 | | // decimal representation of the number can |
82 | | // not hold number bigger than this: |
83 | 3.11M | static_assert(sizeof(entry::integer_type) <= 8, "64 bit integers required"); |
84 | 3.11M | static_assert(sizeof(data) <= sizeof(entry::integer_type), "input data too big, see entry::integer_type"); |
85 | 3.11M | std::array<char, 21> buf; |
86 | 3.11M | auto const str = integer_to_str(buf, val); |
87 | 3.11M | for (char const c : str) |
88 | 3.33M | { |
89 | 3.33M | *out = c; |
90 | 3.33M | ++out; |
91 | 3.33M | } |
92 | 3.11M | return static_cast<int>(str.size()); |
93 | 3.11M | } int libtorrent::aux::write_integer<std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >, long, void>(std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >&, long) Line | Count | Source | 77 | 151k | { | 78 | 151k | entry::integer_type const val = entry::integer_type(data); | 79 | 151k | TORRENT_ASSERT(data == In(val)); | 80 | | // the stack allocated buffer for keeping the | 81 | | // decimal representation of the number can | 82 | | // not hold number bigger than this: | 83 | 151k | static_assert(sizeof(entry::integer_type) <= 8, "64 bit integers required"); | 84 | 151k | static_assert(sizeof(data) <= sizeof(entry::integer_type), "input data too big, see entry::integer_type"); | 85 | 151k | std::array<char, 21> buf; | 86 | 151k | auto const str = integer_to_str(buf, val); | 87 | 151k | for (char const c : str) | 88 | 190k | { | 89 | 190k | *out = c; | 90 | 190k | ++out; | 91 | 190k | } | 92 | 151k | return static_cast<int>(str.size()); | 93 | 151k | } |
int libtorrent::aux::write_integer<std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >, unsigned long, void>(std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >&, unsigned long) Line | Count | Source | 77 | 2.96M | { | 78 | 2.96M | entry::integer_type const val = entry::integer_type(data); | 79 | 2.96M | TORRENT_ASSERT(data == In(val)); | 80 | | // the stack allocated buffer for keeping the | 81 | | // decimal representation of the number can | 82 | | // not hold number bigger than this: | 83 | 2.96M | static_assert(sizeof(entry::integer_type) <= 8, "64 bit integers required"); | 84 | 2.96M | static_assert(sizeof(data) <= sizeof(entry::integer_type), "input data too big, see entry::integer_type"); | 85 | 2.96M | std::array<char, 21> buf; | 86 | 2.96M | auto const str = integer_to_str(buf, val); | 87 | 2.96M | for (char const c : str) | 88 | 3.14M | { | 89 | 3.14M | *out = c; | 90 | 3.14M | ++out; | 91 | 3.14M | } | 92 | 2.96M | return static_cast<int>(str.size()); | 93 | 2.96M | } |
Unexecuted instantiation: int libtorrent::aux::write_integer<std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >, long, void>(std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >&, long) Unexecuted instantiation: int libtorrent::aux::write_integer<std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >, unsigned long, void>(std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >&, unsigned long) Unexecuted instantiation: int libtorrent::aux::write_integer<char*, long, void>(char*&, long) Unexecuted instantiation: int libtorrent::aux::write_integer<char*, unsigned long, void>(char*&, unsigned long) Unexecuted instantiation: int libtorrent::aux::write_integer<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, long, void>(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, long) Unexecuted instantiation: int libtorrent::aux::write_integer<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, unsigned long, void>(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, unsigned long) |
94 | | |
95 | | template <class OutIt> |
96 | | void write_char(OutIt& out, char c) |
97 | 8.18M | { |
98 | 8.18M | *out = c; |
99 | 8.18M | ++out; |
100 | 8.18M | } void libtorrent::aux::write_char<std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >&, char) Line | Count | Source | 97 | 8.18M | { | 98 | 8.18M | *out = c; | 99 | 8.18M | ++out; | 100 | 8.18M | } |
Unexecuted instantiation: void libtorrent::aux::write_char<std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > > >(std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >&, char) Unexecuted instantiation: void libtorrent::aux::write_char<char*>(char*&, char) Unexecuted instantiation: void libtorrent::aux::write_char<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, char) |
101 | | |
102 | | template <class InIt> |
103 | | std::string read_until(InIt& in, InIt end, char end_token, bool& err) |
104 | | { |
105 | | std::string ret; |
106 | | if (in == end) |
107 | | { |
108 | | err = true; |
109 | | return ret; |
110 | | } |
111 | | while (*in != end_token) |
112 | | { |
113 | | ret += *in; |
114 | | ++in; |
115 | | if (in == end) |
116 | | { |
117 | | err = true; |
118 | | return ret; |
119 | | } |
120 | | } |
121 | | return ret; |
122 | | } |
123 | | |
124 | | template<class InIt> |
125 | | void read_string(InIt& in, InIt end, int len, std::string& str, bool& err) |
126 | | { |
127 | | TORRENT_ASSERT(len >= 0); |
128 | | for (int i = 0; i < len; ++i) |
129 | | { |
130 | | if (in == end) |
131 | | { |
132 | | err = true; |
133 | | return; |
134 | | } |
135 | | str += *in; |
136 | | ++in; |
137 | | } |
138 | | } |
139 | | |
140 | | template<class OutIt> |
141 | | int bencode_recursive(OutIt& out, const entry& e) |
142 | 5.37M | { |
143 | 5.37M | int ret = 0; |
144 | 5.37M | switch(e.type()) |
145 | 5.37M | { |
146 | 151k | case entry::int_t: |
147 | 151k | write_char(out, 'i'); |
148 | 151k | ret += write_integer(out, e.integer()); |
149 | 151k | write_char(out, 'e'); |
150 | 151k | ret += 2; |
151 | 151k | break; |
152 | 2.75M | case entry::string_t: |
153 | 2.75M | ret += write_integer(out, e.string().length()); |
154 | 2.75M | write_char(out, ':'); |
155 | 2.75M | ret += write_string(e.string(), out); |
156 | 2.75M | ret += 1; |
157 | 2.75M | break; |
158 | 22.5k | case entry::list_t: |
159 | 22.5k | write_char(out, 'l'); |
160 | 22.5k | for (auto const& i : e.list()) |
161 | 5.16M | ret += bencode_recursive(out, i); |
162 | 22.5k | write_char(out, 'e'); |
163 | 22.5k | ret += 2; |
164 | 22.5k | break; |
165 | 5.07k | case entry::dictionary_t: |
166 | 5.07k | write_char(out, 'd'); |
167 | 5.07k | for (auto const& i : e.dict()) |
168 | 202k | { |
169 | | // write key |
170 | 202k | ret += write_integer(out, i.first.length()); |
171 | 202k | write_char(out, ':'); |
172 | 202k | ret += write_string(i.first, out); |
173 | | // write value |
174 | 202k | ret += bencode_recursive(out, i.second); |
175 | 202k | ret += 1; |
176 | 202k | } |
177 | 5.07k | write_char(out, 'e'); |
178 | 5.07k | ret += 2; |
179 | 5.07k | break; |
180 | 66 | case entry::preformatted_t: |
181 | 66 | std::copy(e.preformatted().begin(), e.preformatted().end(), out); |
182 | 66 | ret += static_cast<int>(e.preformatted().size()); |
183 | 66 | break; |
184 | 2.43M | case entry::undefined_t: |
185 | | |
186 | | // empty string |
187 | 2.43M | write_char(out, '0'); |
188 | 2.43M | write_char(out, ':'); |
189 | | |
190 | 2.43M | ret += 2; |
191 | 2.43M | break; |
192 | 5.37M | } |
193 | 5.37M | return ret; |
194 | 5.37M | } int libtorrent::aux::bencode_recursive<std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >&, libtorrent::entry const&) Line | Count | Source | 142 | 5.37M | { | 143 | 5.37M | int ret = 0; | 144 | 5.37M | switch(e.type()) | 145 | 5.37M | { | 146 | 151k | case entry::int_t: | 147 | 151k | write_char(out, 'i'); | 148 | 151k | ret += write_integer(out, e.integer()); | 149 | 151k | write_char(out, 'e'); | 150 | 151k | ret += 2; | 151 | 151k | break; | 152 | 2.75M | case entry::string_t: | 153 | 2.75M | ret += write_integer(out, e.string().length()); | 154 | 2.75M | write_char(out, ':'); | 155 | 2.75M | ret += write_string(e.string(), out); | 156 | 2.75M | ret += 1; | 157 | 2.75M | break; | 158 | 22.5k | case entry::list_t: | 159 | 22.5k | write_char(out, 'l'); | 160 | 22.5k | for (auto const& i : e.list()) | 161 | 5.16M | ret += bencode_recursive(out, i); | 162 | 22.5k | write_char(out, 'e'); | 163 | 22.5k | ret += 2; | 164 | 22.5k | break; | 165 | 5.07k | case entry::dictionary_t: | 166 | 5.07k | write_char(out, 'd'); | 167 | 5.07k | for (auto const& i : e.dict()) | 168 | 202k | { | 169 | | // write key | 170 | 202k | ret += write_integer(out, i.first.length()); | 171 | 202k | write_char(out, ':'); | 172 | 202k | ret += write_string(i.first, out); | 173 | | // write value | 174 | 202k | ret += bencode_recursive(out, i.second); | 175 | 202k | ret += 1; | 176 | 202k | } | 177 | 5.07k | write_char(out, 'e'); | 178 | 5.07k | ret += 2; | 179 | 5.07k | break; | 180 | 66 | case entry::preformatted_t: | 181 | 66 | std::copy(e.preformatted().begin(), e.preformatted().end(), out); | 182 | 66 | ret += static_cast<int>(e.preformatted().size()); | 183 | 66 | break; | 184 | 2.43M | case entry::undefined_t: | 185 | | | 186 | | // empty string | 187 | 2.43M | write_char(out, '0'); | 188 | 2.43M | write_char(out, ':'); | 189 | | | 190 | 2.43M | ret += 2; | 191 | 2.43M | break; | 192 | 5.37M | } | 193 | 5.37M | return ret; | 194 | 5.37M | } |
Unexecuted instantiation: int libtorrent::aux::bencode_recursive<std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > > >(std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >&, libtorrent::entry const&) Unexecuted instantiation: int libtorrent::aux::bencode_recursive<char*>(char*&, libtorrent::entry const&) Unexecuted instantiation: int libtorrent::aux::bencode_recursive<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, libtorrent::entry const&) |
195 | | #if TORRENT_ABI_VERSION == 1 |
196 | | template<class InIt> |
197 | | void bdecode_recursive(InIt& in, InIt end, entry& ret, bool& err, int depth) |
198 | | { |
199 | | if (depth >= 100) |
200 | | { |
201 | | err = true; |
202 | | return; |
203 | | } |
204 | | |
205 | | if (in == end) |
206 | | { |
207 | | err = true; |
208 | | #if TORRENT_USE_ASSERTS |
209 | | ret.m_type_queried = false; |
210 | | #endif |
211 | | return; |
212 | | } |
213 | | switch (*in) |
214 | | { |
215 | | |
216 | | // ---------------------------------------------- |
217 | | // integer |
218 | | case 'i': |
219 | | { |
220 | | ++in; // 'i' |
221 | | std::string const val = read_until(in, end, 'e', err); |
222 | | if (err) return; |
223 | | TORRENT_ASSERT(*in == 'e'); |
224 | | ++in; // 'e' |
225 | | ret = entry(entry::int_t); |
226 | | char* end_pointer; |
227 | | ret.integer() = std::strtoll(val.c_str(), &end_pointer, 10); |
228 | | #if TORRENT_USE_ASSERTS |
229 | | ret.m_type_queried = false; |
230 | | #endif |
231 | | if (end_pointer == val.c_str()) |
232 | | { |
233 | | err = true; |
234 | | return; |
235 | | } |
236 | | } |
237 | | break; |
238 | | |
239 | | // ---------------------------------------------- |
240 | | // list |
241 | | case 'l': |
242 | | ret = entry(entry::list_t); |
243 | | ++in; // 'l' |
244 | | while (*in != 'e') |
245 | | { |
246 | | ret.list().emplace_back(); |
247 | | entry& e = ret.list().back(); |
248 | | bdecode_recursive(in, end, e, err, depth + 1); |
249 | | if (err) |
250 | | { |
251 | | #if TORRENT_USE_ASSERTS |
252 | | ret.m_type_queried = false; |
253 | | #endif |
254 | | return; |
255 | | } |
256 | | if (in == end) |
257 | | { |
258 | | err = true; |
259 | | #if TORRENT_USE_ASSERTS |
260 | | ret.m_type_queried = false; |
261 | | #endif |
262 | | return; |
263 | | } |
264 | | } |
265 | | #if TORRENT_USE_ASSERTS |
266 | | ret.m_type_queried = false; |
267 | | #endif |
268 | | TORRENT_ASSERT(*in == 'e'); |
269 | | ++in; // 'e' |
270 | | break; |
271 | | |
272 | | // ---------------------------------------------- |
273 | | // dictionary |
274 | | case 'd': |
275 | | ret = entry(entry::dictionary_t); |
276 | | ++in; // 'd' |
277 | | while (*in != 'e') |
278 | | { |
279 | | entry key; |
280 | | bdecode_recursive(in, end, key, err, depth + 1); |
281 | | if (err || key.type() != entry::string_t) |
282 | | { |
283 | | #if TORRENT_USE_ASSERTS |
284 | | ret.m_type_queried = false; |
285 | | #endif |
286 | | return; |
287 | | } |
288 | | entry& e = ret[key.string()]; |
289 | | bdecode_recursive(in, end, e, err, depth + 1); |
290 | | if (err) |
291 | | { |
292 | | #if TORRENT_USE_ASSERTS |
293 | | ret.m_type_queried = false; |
294 | | #endif |
295 | | return; |
296 | | } |
297 | | if (in == end) |
298 | | { |
299 | | err = true; |
300 | | #if TORRENT_USE_ASSERTS |
301 | | ret.m_type_queried = false; |
302 | | #endif |
303 | | return; |
304 | | } |
305 | | } |
306 | | #if TORRENT_USE_ASSERTS |
307 | | ret.m_type_queried = false; |
308 | | #endif |
309 | | TORRENT_ASSERT(*in == 'e'); |
310 | | ++in; // 'e' |
311 | | break; |
312 | | |
313 | | // ---------------------------------------------- |
314 | | // string |
315 | | default: |
316 | | static_assert(sizeof(*in) == 1, "Input iterator to 8 bit data required"); |
317 | | if (is_digit(char(*in))) |
318 | | { |
319 | | std::string len_s = read_until(in, end, ':', err); |
320 | | if (err) |
321 | | { |
322 | | #if TORRENT_USE_ASSERTS |
323 | | ret.m_type_queried = false; |
324 | | #endif |
325 | | return; |
326 | | } |
327 | | TORRENT_ASSERT(*in == ':'); |
328 | | ++in; // ':' |
329 | | int len = atoi(len_s.c_str()); |
330 | | ret = entry(entry::string_t); |
331 | | read_string(in, end, len, ret.string(), err); |
332 | | if (err) |
333 | | { |
334 | | #if TORRENT_USE_ASSERTS |
335 | | ret.m_type_queried = false; |
336 | | #endif |
337 | | return; |
338 | | } |
339 | | } |
340 | | else |
341 | | { |
342 | | err = true; |
343 | | #if TORRENT_USE_ASSERTS |
344 | | ret.m_type_queried = false; |
345 | | #endif |
346 | | return; |
347 | | } |
348 | | #if TORRENT_USE_ASSERTS |
349 | | ret.m_type_queried = false; |
350 | | #endif |
351 | | } |
352 | | } |
353 | | #endif // TORRENT_ABI_VERSION |
354 | | } |
355 | | |
356 | | // This function will encode data to bencoded form. |
357 | | // |
358 | | // The entry_ class is the internal representation of the bencoded data |
359 | | // and it can be used to retrieve information, an entry_ can also be build by |
360 | | // the program and given to ``bencode()`` to encode it into the ``OutIt`` |
361 | | // iterator. |
362 | | // |
363 | | // ``OutIt`` is an OutputIterator_. It's a template and usually |
364 | | // instantiated as ostream_iterator_ or back_insert_iterator_. This |
365 | | // function assumes the value_type of the iterator is a ``char``. |
366 | | // In order to encode entry ``e`` into a buffer, do:: |
367 | | // |
368 | | // std::vector<char> buf; |
369 | | // bencode(std::back_inserter(buf), e); |
370 | | // |
371 | | // .. _OutputIterator: https://en.cppreference.com/w/cpp/named_req/OutputIterator |
372 | | // .. _ostream_iterator: https://en.cppreference.com/w/cpp/iterator/ostream_iterator |
373 | | // .. _back_insert_iterator: https://en.cppreference.com/w/cpp/iterator/back_insert_iterator |
374 | | template<class OutIt> int bencode(OutIt out, const entry& e) |
375 | 5.01k | { |
376 | 5.01k | return aux::bencode_recursive(out, e); |
377 | 5.01k | } int libtorrent::bencode<std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::vector<char, std::__1::allocator<char> > >, libtorrent::entry const&) Line | Count | Source | 375 | 5.01k | { | 376 | 5.01k | return aux::bencode_recursive(out, e); | 377 | 5.01k | } |
Unexecuted instantiation: int libtorrent::bencode<std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > > >(std::__1::back_insert_iterator<libtorrent::aux::noexcept_movable<std::__1::vector<char, std::__1::allocator<char> > > >, libtorrent::entry const&) Unexecuted instantiation: int libtorrent::bencode<char*>(char*, libtorrent::entry const&) Unexecuted instantiation: int libtorrent::bencode<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, libtorrent::entry const&) |
378 | | |
379 | | #if TORRENT_ABI_VERSION == 1 |
380 | | template<class InIt> |
381 | | TORRENT_DEPRECATED |
382 | | entry bdecode(InIt start, InIt end) |
383 | | { |
384 | | entry e; |
385 | | bool err = false; |
386 | | aux::bdecode_recursive(start, end, e, err, 0); |
387 | | TORRENT_ASSERT(e.m_type_queried == false); |
388 | | if (err) return entry(); |
389 | | return e; |
390 | | } |
391 | | template<class InIt> |
392 | | TORRENT_DEPRECATED |
393 | | entry bdecode(InIt start, InIt end |
394 | | , typename std::iterator_traits<InIt>::difference_type& len) |
395 | | { |
396 | | entry e; |
397 | | bool err = false; |
398 | | InIt s = start; |
399 | | aux::bdecode_recursive(start, end, e, err, 0); |
400 | | len = std::distance(s, start); |
401 | | TORRENT_ASSERT(len >= 0); |
402 | | if (err) return entry(); |
403 | | return e; |
404 | | } |
405 | | #endif |
406 | | } |
407 | | |
408 | | #endif // TORRENT_BENCODE_HPP_INCLUDED |