Skip to content
Permalink
Browse files Browse the repository at this point in the history
update version of lazy_bdecode from libtorrent
  • Loading branch information
arvidn committed Oct 23, 2014
1 parent 09d21f4 commit bbc0b71
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 44 deletions.
165 changes: 132 additions & 33 deletions lazy_bdecode.cpp
@@ -1,6 +1,6 @@
/*
Copyright (c) 2008-2012, Arvid Norberg
Copyright (c) 2008-2014, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -45,35 +45,62 @@ namespace
namespace libtorrent
{

#define TORRENT_FAIL_BDECODE(code) \
{ \
ec = make_error_code(code); \
while (!stack.empty()) { \
top = stack.back(); \
if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t) top->pop(); \
stack.pop_back(); \
} \
if (error_pos) *error_pos = start - orig_start; \
return -1; \
namespace
{
int fail(int* error_pos
, std::vector<lazy_entry*>& stack
, char const* start
, char const* orig_start)
{
while (!stack.empty()) {
lazy_entry* top = stack.back();
if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t)
{
top->pop();
break;
}
stack.pop_back();
}
if (error_pos) *error_pos = start - orig_start;
return -1;
}
}

bool is_digit(char c) { return c >= '0' && c <= '9'; }
#define TORRENT_FAIL_BDECODE(code) do { ec = make_error_code(code); return fail(error_pos, stack, start, orig_start); } while (false)

bool is_print(char c) { return c >= 32 && c < 127; }
namespace { bool numeric(char c) { return c >= '0' && c <= '9'; } }

// fills in 'val' with what the string between start and the
// first occurance of the delimiter is interpreted as an int.
// return the pointer to the delimiter, or 0 if there is a
// parse error. val should be initialized to zero
char const* parse_int(char const* start, char const* end, char delimiter, boost::int64_t& val)
char const* parse_int(char const* start, char const* end, char delimiter
, boost::int64_t& val, bdecode_errors::error_code_enum& ec)
{
while (start < end && *start != delimiter)
{
if (!is_digit(*start)) { return 0; }
if (!numeric(*start))
{
ec = bdecode_errors::expected_string;
return start;
}
if (val > INT64_MAX / 10)
{
ec = bdecode_errors::overflow;
return start;
}
val *= 10;
val += *start - '0';
int digit = *start - '0';
if (val > INT64_MAX - digit)
{
ec = bdecode_errors::overflow;
return start;
}
val += digit;
++start;
}
if (*start != delimiter)
ec = bdecode_errors::expected_colon;
return start;
}

Expand All @@ -94,7 +121,7 @@ namespace libtorrent
std::vector<lazy_entry*> stack;

stack.push_back(&ret);
while (start < end)
while (start <= end)
{
if (stack.empty()) break; // done!

Expand All @@ -116,11 +143,19 @@ namespace libtorrent
stack.pop_back();
continue;
}
if (!is_digit(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
boost::int64_t len = t - '0';
start = parse_int(start, end, ':', len);
if (start == 0 || start + len + 3 > end || *start != ':')
TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
bdecode_errors::error_code_enum e = bdecode_errors::no_error;
start = parse_int(start, end, ':', len, e);
if (e)
TORRENT_FAIL_BDECODE(e);

if (start + len + 1 > end)
TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);

if (len < 0)
TORRENT_FAIL_BDECODE(bdecode_errors::overflow);

++start;
if (start == end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
lazy_entry* ent = top->dict_append(start);
Expand Down Expand Up @@ -173,13 +208,19 @@ namespace libtorrent
}
default:
{
if (!is_digit(t))
if (!numeric(t))
TORRENT_FAIL_BDECODE(bdecode_errors::expected_value);

boost::int64_t len = t - '0';
start = parse_int(start, end, ':', len);
if (start == 0 || start + len + 1 > end || *start != ':')
TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
bdecode_errors::error_code_enum e = bdecode_errors::no_error;
start = parse_int(start, end, ':', len, e);
if (e)
TORRENT_FAIL_BDECODE(e);
if (start + len + 1 > end)
TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
if (len < 0)
TORRENT_FAIL_BDECODE(bdecode_errors::overflow);

++start;
top->construct_string(start, int(len));
stack.pop_back();
Expand All @@ -198,7 +239,10 @@ namespace libtorrent
boost::int64_t val = 0;
bool negative = false;
if (*m_data.start == '-') negative = true;
parse_int(negative?m_data.start+1:m_data.start, m_data.start + m_size, 'e', val);
bdecode_errors::error_code_enum ec = bdecode_errors::no_error;
parse_int(m_data.start + negative
, m_data.start + m_size, 'e', val, ec);
if (ec) return 0;
if (negative) val = -val;
return val;
}
Expand Down Expand Up @@ -331,6 +375,13 @@ namespace libtorrent
return e;
}

lazy_entry const* lazy_entry::dict_find_dict(std::string const& name) const
{
lazy_entry const* e = dict_find(name);
if (e == 0 || e->type() != lazy_entry::dict_t) return 0;
return e;
}

lazy_entry const* lazy_entry::dict_find_list(char const* name) const
{
lazy_entry const* e = dict_find(name);
Expand All @@ -350,6 +401,19 @@ namespace libtorrent
return 0;
}

lazy_entry* lazy_entry::dict_find(std::string const& name)
{
TORRENT_ASSERT(m_type == dict_t);
for (int i = 0; i < int(m_size); ++i)
{
lazy_dict_entry& e = m_data.dict[i];
if (name.size() != e.val.m_begin - e.name) continue;
if (std::equal(name.begin(), name.end(), e.name))
return &e.val;
}
return 0;
}

lazy_entry* lazy_entry::list_append()
{
TORRENT_ASSERT(m_type == list_t);
Expand Down Expand Up @@ -492,23 +556,50 @@ namespace libtorrent
char const* str = e.string_ptr();
for (int i = 0; i < e.string_length(); ++i)
{
using namespace std;
if (is_print((unsigned char)str[i])) continue;
char c = str[i];
if (c >= 32 && c < 127) continue;
printable = false;
break;
}
ret += "'";
if (printable)
{
ret += e.string_value();
if (single_line && e.string_length() > 30)
{
ret.append(e.string_ptr(), 14);
ret += "...";
ret.append(e.string_ptr() + e.string_length()-14, 14);
}
else
ret.append(e.string_ptr(), e.string_length());
ret += "'";
return ret;
}
for (int i = 0; i < e.string_length(); ++i)
if (single_line && e.string_length() > 20)
{
char tmp[5];
snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
ret += tmp;
for (int i = 0; i < 9; ++i)
{
char tmp[5];
snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
ret += tmp;
}
ret += "...";
for (int i = e.string_length() - 9
, len(e.string_length()); i < len; ++i)
{
char tmp[5];
snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
ret += tmp;
}
}
else
{
for (int i = 0; i < e.string_length(); ++i)
{
char tmp[5];
snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
ret += tmp;
}
}
ret += "'";
return ret;
Expand Down Expand Up @@ -577,6 +668,7 @@ namespace libtorrent
"expected value (list, dict, int or string) in bencoded string",
"bencoded nesting depth exceeded",
"bencoded item count limit exceeded",
"integer overflow",
};
if (ev < 0 || ev >= int(sizeof(msgs)/sizeof(msgs[0])))
return "Unknown error";
Expand All @@ -589,5 +681,12 @@ namespace libtorrent
return bdecode_category;
}

namespace bdecode_errors
{
boost::system::error_code make_error_code(error_code_enum e)
{
return boost::system::error_code(e, get_bdecode_category());
}
}
};

0 comments on commit bbc0b71

Please sign in to comment.