added new preformatted type to bencode entry (#698)
added new preformatted type to bencode entry to support carrying a verbatim copy of an already bencoded subtree. This is to support saving torrents in resume data and create_torrent based on existing torrents, in order to preserve key order
This commit is contained in:
parent
f9bc6dbc54
commit
985436636e
|
@ -1,5 +1,6 @@
|
||||||
1.1.1 release
|
1.1.1 release
|
||||||
|
|
||||||
|
* added a new "preformatted" type to bencode entry variant type
|
||||||
* improved Socks5 support and test coverage
|
* improved Socks5 support and test coverage
|
||||||
* fix set_settings in python binding
|
* fix set_settings in python binding
|
||||||
* Added missing alert categories in python binding
|
* Added missing alert categories in python binding
|
||||||
|
|
|
@ -210,6 +210,10 @@ namespace libtorrent
|
||||||
write_char(out, 'e');
|
write_char(out, 'e');
|
||||||
ret += 2;
|
ret += 2;
|
||||||
break;
|
break;
|
||||||
|
case entry::preformatted_t:
|
||||||
|
std::copy(e.preformatted().begin(), e.preformatted().end(), out);
|
||||||
|
ret += e.preformatted().size();
|
||||||
|
break;
|
||||||
case entry::undefined_t:
|
case entry::undefined_t:
|
||||||
// trying to encode a structure with uninitialized values!
|
// trying to encode a structure with uninitialized values!
|
||||||
// TORRENT_ASSERT_VAL(false, e.type());
|
// TORRENT_ASSERT_VAL(false, e.type());
|
||||||
|
|
|
@ -108,6 +108,7 @@ namespace libtorrent
|
||||||
typedef std::string string_type;
|
typedef std::string string_type;
|
||||||
typedef std::list<entry> list_type;
|
typedef std::list<entry> list_type;
|
||||||
typedef boost::int64_t integer_type;
|
typedef boost::int64_t integer_type;
|
||||||
|
typedef std::vector<char> preformatted_type;
|
||||||
|
|
||||||
// the types an entry can have
|
// the types an entry can have
|
||||||
enum data_type
|
enum data_type
|
||||||
|
@ -116,7 +117,8 @@ namespace libtorrent
|
||||||
string_t,
|
string_t,
|
||||||
list_t,
|
list_t,
|
||||||
dictionary_t,
|
dictionary_t,
|
||||||
undefined_t
|
undefined_t,
|
||||||
|
preformatted_t
|
||||||
};
|
};
|
||||||
|
|
||||||
// returns the concrete type of the entry
|
// returns the concrete type of the entry
|
||||||
|
@ -129,6 +131,7 @@ namespace libtorrent
|
||||||
entry(string_type const&);
|
entry(string_type const&);
|
||||||
entry(list_type const&);
|
entry(list_type const&);
|
||||||
entry(integer_type const&);
|
entry(integer_type const&);
|
||||||
|
entry(preformatted_type const&);
|
||||||
|
|
||||||
// construct an empty entry of the specified type.
|
// construct an empty entry of the specified type.
|
||||||
// see data_type enum.
|
// see data_type enum.
|
||||||
|
@ -158,6 +161,7 @@ namespace libtorrent
|
||||||
void operator=(string_type const&);
|
void operator=(string_type const&);
|
||||||
void operator=(list_type const&);
|
void operator=(list_type const&);
|
||||||
void operator=(integer_type const&);
|
void operator=(integer_type const&);
|
||||||
|
void operator=(preformatted_type const&);
|
||||||
|
|
||||||
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
||||||
// are accessors that return the respective type. If the ``entry`` object
|
// are accessors that return the respective type. If the ``entry`` object
|
||||||
|
@ -214,6 +218,8 @@ namespace libtorrent
|
||||||
const list_type& list() const;
|
const list_type& list() const;
|
||||||
dictionary_type& dict();
|
dictionary_type& dict();
|
||||||
const dictionary_type& dict() const;
|
const dictionary_type& dict() const;
|
||||||
|
preformatted_type& preformatted();
|
||||||
|
const preformatted_type& preformatted() const;
|
||||||
|
|
||||||
// swaps the content of *this* with ``e``.
|
// swaps the content of *this* with ``e``.
|
||||||
void swap(entry& e);
|
void swap(entry& e);
|
||||||
|
@ -266,17 +272,19 @@ namespace libtorrent
|
||||||
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
|
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
|
||||||
// and sizeof(list<char>) == sizeof(list<entry>)
|
// and sizeof(list<char>) == sizeof(list<entry>)
|
||||||
enum { union_size
|
enum { union_size
|
||||||
= max4<sizeof(std::list<char>)
|
= max5<sizeof(std::list<char>)
|
||||||
, sizeof(std::map<std::string, char>)
|
, sizeof(std::map<std::string, char>)
|
||||||
, sizeof(string_type)
|
, sizeof(string_type)
|
||||||
, sizeof(integer_type)>::value
|
, sizeof(integer_type)
|
||||||
|
, sizeof(preformatted_type)>::value
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
enum { union_size
|
enum { union_size
|
||||||
= max4<sizeof(list_type)
|
= max5<sizeof(list_type)
|
||||||
, sizeof(dictionary_type)
|
, sizeof(dictionary_type)
|
||||||
, sizeof(string_type)
|
, sizeof(string_type)
|
||||||
, sizeof(integer_type)>::value
|
, sizeof(integer_type)
|
||||||
|
, sizeof(preformatted_type)>::value
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
integer_type data[(union_size + sizeof(integer_type) - 1)
|
integer_type data[(union_size + sizeof(integer_type) - 1)
|
||||||
|
|
|
@ -416,7 +416,9 @@ namespace libtorrent
|
||||||
m_piece_hash.resize(m_files.num_pieces());
|
m_piece_hash.resize(m_files.num_pieces());
|
||||||
for (int i = 0; i < num_pieces(); ++i) set_hash(i, ti.hash_for_piece(i));
|
for (int i = 0; i < num_pieces(); ++i) set_hash(i, ti.hash_for_piece(i));
|
||||||
|
|
||||||
m_info_dict = bdecode(&ti.metadata()[0], &ti.metadata()[0] + ti.metadata_size());
|
boost::shared_array<char> const info = ti.metadata();
|
||||||
|
int const size = ti.metadata_size();
|
||||||
|
m_info_dict.preformatted().assign(&info[0], &info[0] + size);
|
||||||
m_info_hash = ti.info_hash();
|
m_info_hash = ti.info_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +510,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
entry& info = dict["info"];
|
entry& info = dict["info"];
|
||||||
if (m_info_dict.type() == entry::dictionary_t)
|
if (m_info_dict.type() == entry::dictionary_t
|
||||||
|
|| m_info_dict.type() == entry::preformatted_t)
|
||||||
{
|
{
|
||||||
info = m_info_dict;
|
info = m_info_dict;
|
||||||
return dict;
|
return dict;
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void entry::operator=(const entry& e)
|
void entry::operator=(const entry& e)
|
||||||
{
|
{
|
||||||
|
if (&e == this) return;
|
||||||
destruct();
|
destruct();
|
||||||
copy(e);
|
copy(e);
|
||||||
}
|
}
|
||||||
|
@ -254,6 +255,29 @@ namespace libtorrent
|
||||||
return *reinterpret_cast<const dictionary_type*>(data);
|
return *reinterpret_cast<const dictionary_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry::preformatted_type& entry::preformatted()
|
||||||
|
{
|
||||||
|
if (m_type == undefined_t) construct(preformatted_t);
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
if (m_type != preformatted_t) throw_type_error();
|
||||||
|
#elif defined TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_type_queried);
|
||||||
|
#endif
|
||||||
|
TORRENT_ASSERT(m_type == preformatted_t);
|
||||||
|
return *reinterpret_cast<preformatted_type*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry::preformatted_type const& entry::preformatted() const
|
||||||
|
{
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
if (m_type != preformatted_t) throw_type_error();
|
||||||
|
#elif defined TORRENT_DEBUG
|
||||||
|
TORRENT_ASSERT(m_type_queried);
|
||||||
|
#endif
|
||||||
|
TORRENT_ASSERT(m_type == preformatted_t);
|
||||||
|
return *reinterpret_cast<const preformatted_type*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
entry::entry()
|
entry::entry()
|
||||||
: m_type(undefined_t)
|
: m_type(undefined_t)
|
||||||
{
|
{
|
||||||
|
@ -320,6 +344,16 @@ namespace libtorrent
|
||||||
m_type = int_t;
|
m_type = int_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry::entry(preformatted_type const& v)
|
||||||
|
: m_type(undefined_t)
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
m_type_queried = true;
|
||||||
|
#endif
|
||||||
|
new(data) preformatted_type(v);
|
||||||
|
m_type = preformatted_t;
|
||||||
|
}
|
||||||
|
|
||||||
// convert a bdecode_node into an old skool entry
|
// convert a bdecode_node into an old skool entry
|
||||||
void entry::operator=(bdecode_node const& e)
|
void entry::operator=(bdecode_node const& e)
|
||||||
{
|
{
|
||||||
|
@ -396,6 +430,16 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void entry::operator=(preformatted_type const& v)
|
||||||
|
{
|
||||||
|
destruct();
|
||||||
|
new(data) preformatted_type(v);
|
||||||
|
m_type = preformatted_t;
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
m_type_queried = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void entry::operator=(dictionary_type const& v)
|
void entry::operator=(dictionary_type const& v)
|
||||||
{
|
{
|
||||||
destruct();
|
destruct();
|
||||||
|
@ -450,6 +494,8 @@ namespace libtorrent
|
||||||
return list() == e.list();
|
return list() == e.list();
|
||||||
case dictionary_t:
|
case dictionary_t:
|
||||||
return dict() == e.dict();
|
return dict() == e.dict();
|
||||||
|
case preformatted_t:
|
||||||
|
return preformatted() == e.preformatted();
|
||||||
default:
|
default:
|
||||||
TORRENT_ASSERT(m_type == undefined_t);
|
TORRENT_ASSERT(m_type == undefined_t);
|
||||||
return true;
|
return true;
|
||||||
|
@ -474,6 +520,9 @@ namespace libtorrent
|
||||||
break;
|
break;
|
||||||
case undefined_t:
|
case undefined_t:
|
||||||
break;
|
break;
|
||||||
|
case preformatted_t:
|
||||||
|
new (data) preformatted_type;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
m_type = t;
|
m_type = t;
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
|
@ -499,6 +548,10 @@ namespace libtorrent
|
||||||
break;
|
break;
|
||||||
case undefined_t:
|
case undefined_t:
|
||||||
TORRENT_ASSERT(e.type() == undefined_t);
|
TORRENT_ASSERT(e.type() == undefined_t);
|
||||||
|
break;
|
||||||
|
case preformatted_t:
|
||||||
|
new (data) preformatted_type(e.preformatted());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
m_type = e.type();
|
m_type = e.type();
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
|
@ -522,6 +575,9 @@ namespace libtorrent
|
||||||
case dictionary_t:
|
case dictionary_t:
|
||||||
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
||||||
break;
|
break;
|
||||||
|
case preformatted_t:
|
||||||
|
call_destructor(reinterpret_cast<preformatted_type*>(data));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
TORRENT_ASSERT(m_type == undefined_t);
|
TORRENT_ASSERT(m_type == undefined_t);
|
||||||
break;
|
break;
|
||||||
|
@ -572,6 +628,10 @@ namespace libtorrent
|
||||||
std::swap(*reinterpret_cast<dictionary_type*>(data)
|
std::swap(*reinterpret_cast<dictionary_type*>(data)
|
||||||
, *reinterpret_cast<dictionary_type*>(e.data));
|
, *reinterpret_cast<dictionary_type*>(e.data));
|
||||||
break;
|
break;
|
||||||
|
case preformatted_t:
|
||||||
|
std::swap(*reinterpret_cast<preformatted_type*>(data)
|
||||||
|
, *reinterpret_cast<preformatted_type*>(e.data));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -664,6 +724,9 @@ namespace libtorrent
|
||||||
i->second.to_string_impl(out, indent+2);
|
i->second.to_string_impl(out, indent+2);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case preformatted_t:
|
||||||
|
out += "<preformatted>\n";
|
||||||
|
break;
|
||||||
case undefined_t:
|
case undefined_t:
|
||||||
default:
|
default:
|
||||||
out += "<uninitialized>\n";
|
out += "<uninitialized>\n";
|
||||||
|
|
|
@ -7188,8 +7188,11 @@ namespace libtorrent
|
||||||
if (valid_metadata())
|
if (valid_metadata())
|
||||||
{
|
{
|
||||||
if (m_magnet_link || (m_save_resume_flags & torrent_handle::save_info_dict))
|
if (m_magnet_link || (m_save_resume_flags & torrent_handle::save_info_dict))
|
||||||
ret["info"] = bdecode(&torrent_file().metadata()[0]
|
{
|
||||||
, &torrent_file().metadata()[0] + torrent_file().metadata_size());
|
boost::shared_array<char> const info = torrent_file().metadata();
|
||||||
|
int const size = torrent_file().metadata_size();
|
||||||
|
ret["info"].preformatted().assign(&info[0], &info[0] + size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blocks per piece
|
// blocks per piece
|
||||||
|
|
|
@ -108,6 +108,7 @@ feature.compose <launcher>valgrind : <testing.launcher>"valgrind --tool=memcheck
|
||||||
test-suite libtorrent :
|
test-suite libtorrent :
|
||||||
[ run
|
[ run
|
||||||
test_primitives.cpp
|
test_primitives.cpp
|
||||||
|
test_create_torrent.cpp
|
||||||
test_packet_buffer.cpp
|
test_packet_buffer.cpp
|
||||||
test_timestamp_history.cpp
|
test_timestamp_history.cpp
|
||||||
test_sha1_hash.cpp
|
test_sha1_hash.cpp
|
||||||
|
|
|
@ -26,6 +26,7 @@ test_programs = \
|
||||||
test_torrent \
|
test_torrent \
|
||||||
test_tracker \
|
test_tracker \
|
||||||
test_transfer \
|
test_transfer \
|
||||||
|
test_create_torrent \
|
||||||
enum_if \
|
enum_if \
|
||||||
test_utp \
|
test_utp \
|
||||||
test_session \
|
test_session \
|
||||||
|
@ -206,6 +207,7 @@ test_ssl_SOURCES = test_ssl.cpp
|
||||||
test_torrent_SOURCES = test_torrent.cpp
|
test_torrent_SOURCES = test_torrent.cpp
|
||||||
test_tracker_SOURCES = test_tracker.cpp
|
test_tracker_SOURCES = test_tracker.cpp
|
||||||
test_transfer_SOURCES = test_transfer.cpp
|
test_transfer_SOURCES = test_transfer.cpp
|
||||||
|
test_create_torrent_SOURCES = test_create_torrent.cpp
|
||||||
enum_if_SOURCES = enum_if.cpp
|
enum_if_SOURCES = enum_if.cpp
|
||||||
test_utp_SOURCES = test_utp.cpp
|
test_utp_SOURCES = test_utp.cpp
|
||||||
test_session_SOURCES = test_session.cpp
|
test_session_SOURCES = test_session.cpp
|
||||||
|
|
|
@ -58,54 +58,72 @@ entry decode(std::string const& str)
|
||||||
return bdecode(str.begin(), str.end());
|
return bdecode(str.begin(), str.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(bencoding)
|
TORRENT_TEST(strings)
|
||||||
{
|
{
|
||||||
// ** strings **
|
entry e("spam");
|
||||||
{
|
TEST_CHECK(encode(e) == "4:spam");
|
||||||
entry e("spam");
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
TEST_CHECK(encode(e) == "4:spam");
|
}
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ** integers **
|
TORRENT_TEST(integers)
|
||||||
{
|
{
|
||||||
entry e(3);
|
entry e(3);
|
||||||
TEST_CHECK(encode(e) == "i3e");
|
TEST_CHECK(encode(e) == "i3e");
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
TORRENT_TEST(integers2)
|
||||||
entry e(-3);
|
{
|
||||||
TEST_CHECK(encode(e) == "i-3e");
|
entry e(-3);
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(encode(e) == "i-3e");
|
||||||
}
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
TORRENT_TEST(integers3)
|
||||||
entry e(int(0));
|
{
|
||||||
TEST_CHECK(encode(e) == "i0e");
|
entry e(int(0));
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(encode(e) == "i0e");
|
||||||
}
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
|
}
|
||||||
|
|
||||||
// ** lists **
|
TORRENT_TEST(lists)
|
||||||
{
|
{
|
||||||
entry::list_type l;
|
entry::list_type l;
|
||||||
l.push_back(entry("spam"));
|
l.push_back(entry("spam"));
|
||||||
l.push_back(entry("eggs"));
|
l.push_back(entry("eggs"));
|
||||||
entry e(l);
|
entry e(l);
|
||||||
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ** dictionaries **
|
TORRENT_TEST(dictionaries)
|
||||||
{
|
{
|
||||||
entry e(entry::dictionary_t);
|
entry e(entry::dictionary_t);
|
||||||
e["spam"] = entry("eggs");
|
e["spam"] = entry("eggs");
|
||||||
e["cow"] = entry("moo");
|
e["cow"] = entry("moo");
|
||||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(preformatted)
|
||||||
|
{
|
||||||
|
entry e(entry::preformatted_t);
|
||||||
|
char const str[] = "foobar";
|
||||||
|
e.preformatted().assign(str, str + sizeof(str)-1);
|
||||||
|
TEST_EQUAL(encode(e), "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(preformatted_node)
|
||||||
|
{
|
||||||
|
entry e(entry::dictionary_t);
|
||||||
|
char const str[] = "foobar";
|
||||||
|
e["info"] = entry::preformatted_type(str, str + sizeof(str)-1);
|
||||||
|
TEST_EQUAL(encode(e), "d4:infofoobare");
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
TORRENT_TEST(lazy_entry)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
char b[] = "i12453e";
|
char b[] = "i12453e";
|
||||||
lazy_entry e;
|
lazy_entry e;
|
||||||
|
@ -609,8 +627,6 @@ TORRENT_TEST(bencoding)
|
||||||
printf("%s\n", print_entry(e).c_str());
|
printf("%s\n", print_entry(e).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // TORRENT_NO_DEPRECATE
|
|
||||||
}
|
}
|
||||||
|
#endif // TORRENT_NO_DEPRECATE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.hpp"
|
||||||
|
|
||||||
|
#include "libtorrent/torrent_info.hpp"
|
||||||
|
#include "libtorrent/create_torrent.hpp"
|
||||||
|
#include "libtorrent/bencode.hpp"
|
||||||
|
#include "libtorrent/aux_/escape_string.hpp" // for convert_path_to_posix
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace lt = libtorrent;
|
||||||
|
|
||||||
|
// make sure creating a torrent from an existing handle preserves the
|
||||||
|
// info-dictionary verbatim, so as to not alter the info-hash
|
||||||
|
TORRENT_TEST(create_verbatim_torrent)
|
||||||
|
{
|
||||||
|
char const test_torrent[] = "d4:infod4:name6:foobar6:lengthi12345e12:piece lengthi65536e6:pieces20:ababababababababababee";
|
||||||
|
|
||||||
|
lt::torrent_info info(test_torrent, sizeof(test_torrent) - 1);
|
||||||
|
|
||||||
|
lt::create_torrent t(info);
|
||||||
|
|
||||||
|
std::vector<char> buffer;
|
||||||
|
lt::bencode(std::back_inserter(buffer), t.generate());
|
||||||
|
|
||||||
|
// now, make sure the info dictionary was unchanged
|
||||||
|
buffer.push_back('\0');
|
||||||
|
char const* dest_info = std::strstr(&buffer[0], "4:info");
|
||||||
|
|
||||||
|
TEST_CHECK(dest_info != NULL);
|
||||||
|
|
||||||
|
// +1 and -2 here is to strip the outermost dictionary from the source
|
||||||
|
// torrent, since create_torrent may have added items next to the info dict
|
||||||
|
TEST_CHECK(memcmp(dest_info, test_torrent + 1, sizeof(test_torrent)-3) == 0);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue