improve interoperability between bdecode_node and entry (for encoding). Make it possible to construct an entry from a bdecode_node. move comparison operators out of entry to support implicit conversions from bdecode_node

This commit is contained in:
arvidn 2018-11-18 12:59:52 +01:00 committed by Arvid Norberg
parent 295bcc08e5
commit 8841c58435
10 changed files with 65 additions and 58 deletions

View File

@ -438,6 +438,8 @@ TORRENT_EXPORT int bdecode(char const* start, char const* end, bdecode_node& ret
TORRENT_EXPORT bdecode_node bdecode(span<char const> buffer
, error_code& ec, int* error_pos = nullptr, int depth_limit = 100
, int token_limit = 2000000);
TORRENT_EXPORT bdecode_node bdecode(span<char const> buffer
, int depth_limit = 100, int token_limit = 2000000);
}

View File

@ -434,7 +434,6 @@ namespace detail {
if (err) return entry();
return e;
}
entry bdecode(span<char const> buffer);
}
#endif // TORRENT_BENCODE_HPP_INCLUDED

View File

@ -178,16 +178,15 @@ namespace aux {
entry(entry const& e);
entry(entry&& e) noexcept;
// construct from bdecode_node parsed form (see bdecode())
entry(bdecode_node const& n); // NOLINT
// hidden
entry();
// hidden
~entry();
// hidden
bool operator==(entry const& e) const;
bool operator!=(entry const& e) const { return !(*this == e); }
// copies the structure of the right hand side into this
// entry.
#if TORRENT_ABI_VERSION == 1
@ -340,9 +339,13 @@ namespace aux {
mutable std::uint8_t m_type_queried:1;
};
TORRENT_EXPORT bool operator==(entry const& lhs, entry const& rhs);
inline bool operator!=(entry const& lhs, entry const& rhs) { return !(lhs == rhs); }
namespace detail {
TORRENT_EXTRA_EXPORT string_view integer_to_str(span<char> buf
// internal
TORRENT_EXPORT string_view integer_to_str(span<char> buf
, entry::integer_type val);
}

View File

@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bdecode.hpp"
#include "libtorrent/aux_/alloca.hpp"
#include "libtorrent/aux_/numeric_cast.hpp"
#include "libtorrent/error_code.hpp"
#include <limits>
#include <cstring> // for memset
#include <cstdio> // for snprintf
@ -735,6 +736,14 @@ namespace {
return ec ? -1 : 0;
}
bdecode_node bdecode(span<char const> buffer, int depth_limit, int token_limit)
{
error_code ec;
bdecode_node ret = bdecode(buffer, ec, nullptr, depth_limit, token_limit);
if (ec) throw system_error(ec);
return ret;
}
bdecode_node bdecode(span<char const> buffer
, error_code& ec, int* error_pos, int depth_limit, int token_limit)
{

View File

@ -68,17 +68,6 @@ namespace detail {
}
} // detail
entry bdecode(span<char const> buffer)
{
entry e;
bool err = false;
auto it = buffer.begin();
detail::bdecode_recursive(it, buffer.end(), e, err, 0);
TORRENT_ASSERT(e.m_type_queried == false);
if (err) return entry();
return e;
}
namespace {
inline void TORRENT_NO_RETURN throw_error()
@ -311,6 +300,12 @@ namespace {
this->operator=(std::move(e));
}
entry::entry(bdecode_node const& n)
: m_type(undefined_t)
{
this->operator=(n);
}
entry::entry(dictionary_type v)
: m_type(undefined_t)
{
@ -494,26 +489,26 @@ namespace {
return *this;
}
bool entry::operator==(entry const& e) const
bool operator==(entry const& lhs, entry const& rhs)
{
if (type() != e.type()) return false;
if (lhs.type() != rhs.type()) return false;
switch (m_type)
switch (lhs.type())
{
case int_t:
return integer() == e.integer();
case string_t:
return string() == e.string();
case list_t:
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);
case entry::int_t:
return lhs.integer() == rhs.integer();
case entry::string_t:
return lhs.string() == rhs.string();
case entry::list_t:
return lhs.list() == rhs.list();
case entry::dictionary_t:
return lhs.dict() == rhs.dict();
case entry::preformatted_t:
return lhs.preformatted() == rhs.preformatted();
case entry::undefined_t:
return true;
}
return false;
}
void entry::construct(data_type t)

View File

@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/aux_/vector.hpp>
#include <libtorrent/aux_/numeric_cast.hpp>
#include <libtorrent/broadcast_socket.hpp> // for ip_v4
#include <libtorrent/bdecode.hpp>
namespace libtorrent { namespace dht {
namespace {
@ -355,8 +356,8 @@ namespace {
auto const i = m_immutable_table.find(target);
if (i == m_immutable_table.end()) return false;
item["v"] = bdecode(i->second.value.get()
, i->second.value.get() + i->second.size);
error_code ec;
item["v"] = bdecode({i->second.value.get(), i->second.size}, ec);
return true;
}
@ -412,7 +413,8 @@ namespace {
item["seq"] = f.seq.value;
if (force_fill || (sequence_number(0) <= seq && seq < f.seq))
{
item["v"] = bdecode(f.value.get(), f.value.get() + f.size);
error_code ec;
item["v"] = bdecode({f.value.get(), f.size}, ec);
item["sig"] = f.sig.bytes;
item["k"] = f.key.bytes;
}

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/bencode.hpp"
#include "libtorrent/bdecode.hpp"
#include <iostream>
#include <cstring>
@ -56,39 +57,34 @@ std::string encode(entry const& e)
return ret;
}
entry decode(std::string const& str)
{
return bdecode(str.begin(), str.end());
}
} // anonymous namespace
TORRENT_TEST(strings)
{
entry e("spam");
TEST_CHECK(encode(e) == "4:spam");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(integers)
{
entry e(3);
TEST_CHECK(encode(e) == "i3e");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(integers2)
{
entry e(-3);
TEST_CHECK(encode(e) == "i-3e");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(integers3)
{
entry e(int(0));
TEST_CHECK(encode(e) == "i0e");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(lists)
@ -98,7 +94,7 @@ TORRENT_TEST(lists)
l.push_back(entry("eggs"));
entry e(l);
TEST_CHECK(encode(e) == "l4:spam4:eggse");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(dictionaries)
@ -107,7 +103,7 @@ TORRENT_TEST(dictionaries)
e["spam"] = entry("eggs");
e["cow"] = entry("moo");
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
TEST_CHECK(decode(encode(e)) == e);
TEST_CHECK(bdecode(encode(e)) == e);
}
TORRENT_TEST(preformatted)
@ -620,7 +616,8 @@ TORRENT_TEST(lazy_entry)
{
unsigned char buf[] = { 0x44, 0x91, 0x3a };
entry ent = bdecode(reinterpret_cast<char*>(buf), reinterpret_cast<char*>(buf) + sizeof(buf));
error_code ec;
entry ent = bdecode({reinterpret_cast<char*>(buf), int(sizeof(buf))}, ec);
TEST_CHECK(ent == entry());
}

View File

@ -154,7 +154,7 @@ void print_message(char const* buffer, int len)
else if (msg == 20 && len > 4 && buffer[1] == 0 )
{
std::snprintf(extra, sizeof(extra), "%s"
, bdecode(buffer + 2, buffer + len).to_string().c_str());
, print_entry(bdecode({buffer + 2, len - 2})).c_str());
}
}
@ -356,7 +356,7 @@ entry read_extension_handshake(tcp::socket& s, char* recv_buffer, int size)
int extmsg = recv_buffer[1];
if (extmsg != 0) continue;
return bdecode(recv_buffer + 2, recv_buffer + len);
return bdecode({recv_buffer + 2, len - 2});
}
}
@ -409,7 +409,7 @@ entry read_ut_metadata_msg(tcp::socket& s, char* recv_buffer, int size)
int extmsg = recv_buffer[1];
if (extmsg != 1) continue;
return bdecode(recv_buffer + 2, recv_buffer + len);
return bdecode({recv_buffer + 2, len - 2});
}
}
#endif // TORRENT_DISABLE_EXTENSIONS
@ -831,7 +831,7 @@ TORRENT_TEST(dont_have)
{
print_session_log(*ses);
int len = read_message(s, recv_buffer, sizeof(recv_buffer));
int const len = read_message(s, recv_buffer, sizeof(recv_buffer));
if (len == -1) break;
print_message(recv_buffer, len);
if (len == 0) continue;
@ -840,15 +840,15 @@ TORRENT_TEST(dont_have)
int ext_msg = recv_buffer[1];
if (ext_msg != 0) continue;
bdecode_node e;
int pos = 0;
int ret = bdecode(recv_buffer + 2, recv_buffer + len, e, ec, &pos);
if (ret != 0)
ec.clear();
bdecode_node e = bdecode({recv_buffer + 2, len - 2}, ec, &pos);
if (ec)
{
log("failed to parse extension handshake: %s at pos %d"
, ec.message().c_str(), pos);
}
TEST_EQUAL(ret, 0);
TEST_CHECK(!ec);
log("extension handshake: %s", print_entry(e).c_str());
bdecode_node m = e.dict_find_dict("m");

View File

@ -201,7 +201,7 @@ TORRENT_TEST(read_resume_torrent)
rd["file-format"] = "libtorrent resume file";
rd["file-version"] = 1;
rd["info-hash"] = ti->info_hash().to_string();
rd["info"] = bdecode(ti->metadata().get(), ti->metadata().get() + ti->metadata_size());
rd["info"] = bdecode({ti->metadata().get(), ti->metadata_size()});
std::vector<char> resume_data;
bencode(std::back_inserter(resume_data), rd);

View File

@ -890,7 +890,7 @@ TORRENT_TEST(backwards_compatible_resume_info_dict)
rd["name"] = ti->name();
rd["info-hash"] = ti->info_hash();
auto metainfo = ti->metadata();
rd["info"] = bdecode(metainfo.get(), metainfo.get() + ti->metadata_size());
rd["info"] = bdecode({metainfo.get(), ti->metadata_size()});
std::vector<char> resume_data;
bencode(back_inserter(resume_data), rd);
@ -917,7 +917,7 @@ TORRENT_TEST(resume_info_dict)
rd["name"] = ti->name();
rd["info-hash"] = ti->info_hash();
auto metainfo = ti->metadata();
rd["info"] = bdecode(metainfo.get(), metainfo.get() + ti->metadata_size());
rd["info"] = bdecode({metainfo.get(), ti->metadata_size()});
std::vector<char> resume_data;
bencode(back_inserter(resume_data), rd);