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 TORRENT_EXPORT bdecode_node bdecode(span<char const> buffer
, error_code& ec, int* error_pos = nullptr, int depth_limit = 100 , error_code& ec, int* error_pos = nullptr, int depth_limit = 100
, int token_limit = 2000000); , 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(); if (err) return entry();
return e; return e;
} }
entry bdecode(span<char const> buffer);
} }
#endif // TORRENT_BENCODE_HPP_INCLUDED #endif // TORRENT_BENCODE_HPP_INCLUDED

View File

@ -178,16 +178,15 @@ namespace aux {
entry(entry const& e); entry(entry const& e);
entry(entry&& e) noexcept; entry(entry&& e) noexcept;
// construct from bdecode_node parsed form (see bdecode())
entry(bdecode_node const& n); // NOLINT
// hidden // hidden
entry(); entry();
// hidden // hidden
~entry(); ~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 // copies the structure of the right hand side into this
// entry. // entry.
#if TORRENT_ABI_VERSION == 1 #if TORRENT_ABI_VERSION == 1
@ -340,9 +339,13 @@ namespace aux {
mutable std::uint8_t m_type_queried:1; 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 { 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); , entry::integer_type val);
} }

View File

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

View File

@ -68,17 +68,6 @@ namespace detail {
} }
} // 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 { namespace {
inline void TORRENT_NO_RETURN throw_error() inline void TORRENT_NO_RETURN throw_error()
@ -311,6 +300,12 @@ namespace {
this->operator=(std::move(e)); this->operator=(std::move(e));
} }
entry::entry(bdecode_node const& n)
: m_type(undefined_t)
{
this->operator=(n);
}
entry::entry(dictionary_type v) entry::entry(dictionary_type v)
: m_type(undefined_t) : m_type(undefined_t)
{ {
@ -494,26 +489,26 @@ namespace {
return *this; 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: case entry::int_t:
return integer() == e.integer(); return lhs.integer() == rhs.integer();
case string_t: case entry::string_t:
return string() == e.string(); return lhs.string() == rhs.string();
case list_t: case entry::list_t:
return list() == e.list(); return lhs.list() == rhs.list();
case dictionary_t: case entry::dictionary_t:
return dict() == e.dict(); return lhs.dict() == rhs.dict();
case preformatted_t: case entry::preformatted_t:
return preformatted() == e.preformatted(); return lhs.preformatted() == rhs.preformatted();
default: case entry::undefined_t:
TORRENT_ASSERT(m_type == undefined_t);
return true; return true;
} }
return false;
} }
void entry::construct(data_type t) void entry::construct(data_type t)

View File

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

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/bdecode.hpp"
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
@ -56,39 +57,34 @@ std::string encode(entry const& e)
return ret; return ret;
} }
entry decode(std::string const& str)
{
return bdecode(str.begin(), str.end());
}
} // anonymous namespace } // anonymous namespace
TORRENT_TEST(strings) TORRENT_TEST(strings)
{ {
entry e("spam"); entry e("spam");
TEST_CHECK(encode(e) == "4:spam"); TEST_CHECK(encode(e) == "4:spam");
TEST_CHECK(decode(encode(e)) == e); TEST_CHECK(bdecode(encode(e)) == e);
} }
TORRENT_TEST(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(bdecode(encode(e)) == e);
} }
TORRENT_TEST(integers2) TORRENT_TEST(integers2)
{ {
entry e(-3); entry e(-3);
TEST_CHECK(encode(e) == "i-3e"); TEST_CHECK(encode(e) == "i-3e");
TEST_CHECK(decode(encode(e)) == e); TEST_CHECK(bdecode(encode(e)) == e);
} }
TORRENT_TEST(integers3) TORRENT_TEST(integers3)
{ {
entry e(int(0)); entry e(int(0));
TEST_CHECK(encode(e) == "i0e"); TEST_CHECK(encode(e) == "i0e");
TEST_CHECK(decode(encode(e)) == e); TEST_CHECK(bdecode(encode(e)) == e);
} }
TORRENT_TEST(lists) TORRENT_TEST(lists)
@ -98,7 +94,7 @@ TORRENT_TEST(lists)
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(bdecode(encode(e)) == e);
} }
TORRENT_TEST(dictionaries) TORRENT_TEST(dictionaries)
@ -107,7 +103,7 @@ TORRENT_TEST(dictionaries)
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(bdecode(encode(e)) == e);
} }
TORRENT_TEST(preformatted) TORRENT_TEST(preformatted)
@ -620,7 +616,8 @@ TORRENT_TEST(lazy_entry)
{ {
unsigned char buf[] = { 0x44, 0x91, 0x3a }; 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()); 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 ) else if (msg == 20 && len > 4 && buffer[1] == 0 )
{ {
std::snprintf(extra, sizeof(extra), "%s" 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]; int extmsg = recv_buffer[1];
if (extmsg != 0) continue; 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]; int extmsg = recv_buffer[1];
if (extmsg != 1) continue; if (extmsg != 1) continue;
return bdecode(recv_buffer + 2, recv_buffer + len); return bdecode({recv_buffer + 2, len - 2});
} }
} }
#endif // TORRENT_DISABLE_EXTENSIONS #endif // TORRENT_DISABLE_EXTENSIONS
@ -831,7 +831,7 @@ TORRENT_TEST(dont_have)
{ {
print_session_log(*ses); 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; if (len == -1) break;
print_message(recv_buffer, len); print_message(recv_buffer, len);
if (len == 0) continue; if (len == 0) continue;
@ -840,15 +840,15 @@ TORRENT_TEST(dont_have)
int ext_msg = recv_buffer[1]; int ext_msg = recv_buffer[1];
if (ext_msg != 0) continue; if (ext_msg != 0) continue;
bdecode_node e;
int pos = 0; int pos = 0;
int ret = bdecode(recv_buffer + 2, recv_buffer + len, e, ec, &pos); ec.clear();
if (ret != 0) bdecode_node e = bdecode({recv_buffer + 2, len - 2}, ec, &pos);
if (ec)
{ {
log("failed to parse extension handshake: %s at pos %d" log("failed to parse extension handshake: %s at pos %d"
, ec.message().c_str(), pos); , ec.message().c_str(), pos);
} }
TEST_EQUAL(ret, 0); TEST_CHECK(!ec);
log("extension handshake: %s", print_entry(e).c_str()); log("extension handshake: %s", print_entry(e).c_str());
bdecode_node m = e.dict_find_dict("m"); 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-format"] = "libtorrent resume file";
rd["file-version"] = 1; rd["file-version"] = 1;
rd["info-hash"] = ti->info_hash().to_string(); 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; std::vector<char> resume_data;
bencode(std::back_inserter(resume_data), rd); 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["name"] = ti->name();
rd["info-hash"] = ti->info_hash(); rd["info-hash"] = ti->info_hash();
auto metainfo = ti->metadata(); 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; std::vector<char> resume_data;
bencode(back_inserter(resume_data), rd); bencode(back_inserter(resume_data), rd);
@ -917,7 +917,7 @@ TORRENT_TEST(resume_info_dict)
rd["name"] = ti->name(); rd["name"] = ti->name();
rd["info-hash"] = ti->info_hash(); rd["info-hash"] = ti->info_hash();
auto metainfo = ti->metadata(); 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; std::vector<char> resume_data;
bencode(back_inserter(resume_data), rd); bencode(back_inserter(resume_data), rd);