forked from premiere/premiere-libtorrent
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
|
||||
|
||||
* added a new "preformatted" type to bencode entry variant type
|
||||
* improved Socks5 support and test coverage
|
||||
* fix set_settings in python binding
|
||||
* Added missing alert categories in python binding
|
||||
|
|
|
@ -210,6 +210,10 @@ namespace libtorrent
|
|||
write_char(out, 'e');
|
||||
ret += 2;
|
||||
break;
|
||||
case entry::preformatted_t:
|
||||
std::copy(e.preformatted().begin(), e.preformatted().end(), out);
|
||||
ret += e.preformatted().size();
|
||||
break;
|
||||
case entry::undefined_t:
|
||||
// trying to encode a structure with uninitialized values!
|
||||
// TORRENT_ASSERT_VAL(false, e.type());
|
||||
|
|
|
@ -108,6 +108,7 @@ namespace libtorrent
|
|||
typedef std::string string_type;
|
||||
typedef std::list<entry> list_type;
|
||||
typedef boost::int64_t integer_type;
|
||||
typedef std::vector<char> preformatted_type;
|
||||
|
||||
// the types an entry can have
|
||||
enum data_type
|
||||
|
@ -116,7 +117,8 @@ namespace libtorrent
|
|||
string_t,
|
||||
list_t,
|
||||
dictionary_t,
|
||||
undefined_t
|
||||
undefined_t,
|
||||
preformatted_t
|
||||
};
|
||||
|
||||
// returns the concrete type of the entry
|
||||
|
@ -129,6 +131,7 @@ namespace libtorrent
|
|||
entry(string_type const&);
|
||||
entry(list_type const&);
|
||||
entry(integer_type const&);
|
||||
entry(preformatted_type const&);
|
||||
|
||||
// construct an empty entry of the specified type.
|
||||
// see data_type enum.
|
||||
|
@ -158,6 +161,7 @@ namespace libtorrent
|
|||
void operator=(string_type const&);
|
||||
void operator=(list_type const&);
|
||||
void operator=(integer_type const&);
|
||||
void operator=(preformatted_type const&);
|
||||
|
||||
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
||||
// are accessors that return the respective type. If the ``entry`` object
|
||||
|
@ -214,6 +218,8 @@ namespace libtorrent
|
|||
const list_type& list() const;
|
||||
dictionary_type& dict();
|
||||
const dictionary_type& dict() const;
|
||||
preformatted_type& preformatted();
|
||||
const preformatted_type& preformatted() const;
|
||||
|
||||
// swaps the content of *this* with ``e``.
|
||||
void swap(entry& e);
|
||||
|
@ -266,17 +272,19 @@ namespace libtorrent
|
|||
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
|
||||
// and sizeof(list<char>) == sizeof(list<entry>)
|
||||
enum { union_size
|
||||
= max4<sizeof(std::list<char>)
|
||||
= max5<sizeof(std::list<char>)
|
||||
, sizeof(std::map<std::string, char>)
|
||||
, sizeof(string_type)
|
||||
, sizeof(integer_type)>::value
|
||||
, sizeof(integer_type)
|
||||
, sizeof(preformatted_type)>::value
|
||||
};
|
||||
#else
|
||||
enum { union_size
|
||||
= max4<sizeof(list_type)
|
||||
= max5<sizeof(list_type)
|
||||
, sizeof(dictionary_type)
|
||||
, sizeof(string_type)
|
||||
, sizeof(integer_type)>::value
|
||||
, sizeof(integer_type)
|
||||
, sizeof(preformatted_type)>::value
|
||||
};
|
||||
#endif
|
||||
integer_type data[(union_size + sizeof(integer_type) - 1)
|
||||
|
|
|
@ -416,7 +416,9 @@ namespace libtorrent
|
|||
m_piece_hash.resize(m_files.num_pieces());
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -508,7 +510,8 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
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;
|
||||
return dict;
|
||||
|
|
|
@ -158,6 +158,7 @@ namespace libtorrent
|
|||
|
||||
void entry::operator=(const entry& e)
|
||||
{
|
||||
if (&e == this) return;
|
||||
destruct();
|
||||
copy(e);
|
||||
}
|
||||
|
@ -254,6 +255,29 @@ namespace libtorrent
|
|||
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()
|
||||
: m_type(undefined_t)
|
||||
{
|
||||
|
@ -320,6 +344,16 @@ namespace libtorrent
|
|||
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
|
||||
void entry::operator=(bdecode_node const& e)
|
||||
{
|
||||
|
@ -396,6 +430,16 @@ namespace libtorrent
|
|||
}
|
||||
#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)
|
||||
{
|
||||
destruct();
|
||||
|
@ -450,6 +494,8 @@ namespace libtorrent
|
|||
return list() == e.list();
|
||||
case dictionary_t:
|
||||
return dict() == e.dict();
|
||||
case preformatted_t:
|
||||
return preformatted() == e.preformatted();
|
||||
default:
|
||||
TORRENT_ASSERT(m_type == undefined_t);
|
||||
return true;
|
||||
|
@ -474,6 +520,9 @@ namespace libtorrent
|
|||
break;
|
||||
case undefined_t:
|
||||
break;
|
||||
case preformatted_t:
|
||||
new (data) preformatted_type;
|
||||
break;
|
||||
}
|
||||
m_type = t;
|
||||
#ifdef TORRENT_DEBUG
|
||||
|
@ -499,6 +548,10 @@ namespace libtorrent
|
|||
break;
|
||||
case undefined_t:
|
||||
TORRENT_ASSERT(e.type() == undefined_t);
|
||||
break;
|
||||
case preformatted_t:
|
||||
new (data) preformatted_type(e.preformatted());
|
||||
break;
|
||||
}
|
||||
m_type = e.type();
|
||||
#ifdef TORRENT_DEBUG
|
||||
|
@ -522,6 +575,9 @@ namespace libtorrent
|
|||
case dictionary_t:
|
||||
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
||||
break;
|
||||
case preformatted_t:
|
||||
call_destructor(reinterpret_cast<preformatted_type*>(data));
|
||||
break;
|
||||
default:
|
||||
TORRENT_ASSERT(m_type == undefined_t);
|
||||
break;
|
||||
|
@ -572,6 +628,10 @@ namespace libtorrent
|
|||
std::swap(*reinterpret_cast<dictionary_type*>(data)
|
||||
, *reinterpret_cast<dictionary_type*>(e.data));
|
||||
break;
|
||||
case preformatted_t:
|
||||
std::swap(*reinterpret_cast<preformatted_type*>(data)
|
||||
, *reinterpret_cast<preformatted_type*>(e.data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -664,6 +724,9 @@ namespace libtorrent
|
|||
i->second.to_string_impl(out, indent+2);
|
||||
}
|
||||
} break;
|
||||
case preformatted_t:
|
||||
out += "<preformatted>\n";
|
||||
break;
|
||||
case undefined_t:
|
||||
default:
|
||||
out += "<uninitialized>\n";
|
||||
|
|
|
@ -7188,8 +7188,11 @@ namespace libtorrent
|
|||
if (valid_metadata())
|
||||
{
|
||||
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
|
||||
|
|
|
@ -108,6 +108,7 @@ feature.compose <launcher>valgrind : <testing.launcher>"valgrind --tool=memcheck
|
|||
test-suite libtorrent :
|
||||
[ run
|
||||
test_primitives.cpp
|
||||
test_create_torrent.cpp
|
||||
test_packet_buffer.cpp
|
||||
test_timestamp_history.cpp
|
||||
test_sha1_hash.cpp
|
||||
|
|
|
@ -26,6 +26,7 @@ test_programs = \
|
|||
test_torrent \
|
||||
test_tracker \
|
||||
test_transfer \
|
||||
test_create_torrent \
|
||||
enum_if \
|
||||
test_utp \
|
||||
test_session \
|
||||
|
@ -206,6 +207,7 @@ test_ssl_SOURCES = test_ssl.cpp
|
|||
test_torrent_SOURCES = test_torrent.cpp
|
||||
test_tracker_SOURCES = test_tracker.cpp
|
||||
test_transfer_SOURCES = test_transfer.cpp
|
||||
test_create_torrent_SOURCES = test_create_torrent.cpp
|
||||
enum_if_SOURCES = enum_if.cpp
|
||||
test_utp_SOURCES = test_utp.cpp
|
||||
test_session_SOURCES = test_session.cpp
|
||||
|
|
|
@ -58,54 +58,72 @@ entry decode(std::string const& str)
|
|||
return bdecode(str.begin(), str.end());
|
||||
}
|
||||
|
||||
TORRENT_TEST(bencoding)
|
||||
TORRENT_TEST(strings)
|
||||
{
|
||||
// ** strings **
|
||||
{
|
||||
entry e("spam");
|
||||
TEST_CHECK(encode(e) == "4:spam");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
entry e("spam");
|
||||
TEST_CHECK(encode(e) == "4:spam");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** integers **
|
||||
{
|
||||
entry e(3);
|
||||
TEST_CHECK(encode(e) == "i3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers)
|
||||
{
|
||||
entry e(3);
|
||||
TEST_CHECK(encode(e) == "i3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
{
|
||||
entry e(-3);
|
||||
TEST_CHECK(encode(e) == "i-3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers2)
|
||||
{
|
||||
entry e(-3);
|
||||
TEST_CHECK(encode(e) == "i-3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
{
|
||||
entry e(int(0));
|
||||
TEST_CHECK(encode(e) == "i0e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers3)
|
||||
{
|
||||
entry e(int(0));
|
||||
TEST_CHECK(encode(e) == "i0e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** lists **
|
||||
{
|
||||
entry::list_type l;
|
||||
l.push_back(entry("spam"));
|
||||
l.push_back(entry("eggs"));
|
||||
entry e(l);
|
||||
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(lists)
|
||||
{
|
||||
entry::list_type l;
|
||||
l.push_back(entry("spam"));
|
||||
l.push_back(entry("eggs"));
|
||||
entry e(l);
|
||||
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** dictionaries **
|
||||
{
|
||||
entry e(entry::dictionary_t);
|
||||
e["spam"] = entry("eggs");
|
||||
e["cow"] = entry("moo");
|
||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(dictionaries)
|
||||
{
|
||||
entry e(entry::dictionary_t);
|
||||
e["spam"] = entry("eggs");
|
||||
e["cow"] = entry("moo");
|
||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||
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
|
||||
TORRENT_TEST(lazy_entry)
|
||||
{
|
||||
{
|
||||
char b[] = "i12453e";
|
||||
lazy_entry e;
|
||||
|
@ -609,8 +627,6 @@ TORRENT_TEST(bencoding)
|
|||
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