// check if the fastresume data is up to date // if it is, use it and return true. If it // isn't return false and the full check // will be run int piece_manager::check_fastresume( lazy_entry const& rd, error_code& error) { mutex::scoped_lock lock(m_mutex); INVARIANT_CHECK; TORRENT_ASSERT(m_files.piece_length() > 0); m_current_slot = 0; // if we don't have any resume data, return if (rd.type() == lazy_entry::none_t) return check_no_fastresume(error); if (rd.type() != lazy_entry::dict_t) { error = errors::not_a_dictionary; return check_no_fastresume(error); } int block_size = (std::min)(16 * 1024, m_files.piece_length()); int blocks_per_piece = int(rd.dict_find_int_value("blocks per piece", -1)); if (blocks_per_piece != -1 && blocks_per_piece != m_files.piece_length() / block_size) { error = errors::invalid_blocks_per_piece; return check_no_fastresume(error); } if (!m_storage->verify_resume_data(rd, error)) return check_no_fastresume(error); return check_init_storage(error); }
bool uTorrentParser::parse_torrent_file(lazy_entry const& torrent_file, error_code& ec) { if (torrent_file.type() != lazy_entry::dict_t) { ec = errors::torrent_is_no_dict; return false; } mTorrents.clear(); for (int i = 0, end(torrent_file.dict_size()); i < end; ++i) { std::pair<std::string, lazy_entry const*> n = torrent_file.dict_at(i); if (lazy_entry::dict_t == n.second->type()) { std::pair<std::string, std::string> torrent; torrent.first = n.first; torrent.second = n.second->dict_find_string_value("path"); std::string caption = n.second->dict_find_string_value("caption"); if (caption.length() > 0) { size_t pos = torrent.second.find(caption.c_str(), 0, caption.length()); torrent.second = torrent.second.substr(0, pos); } mTorrents.push_back(torrent); } } return true; }
void feed::load_state(lazy_entry const& rd) { load_struct(rd, this, feed_map, sizeof(feed_map)/sizeof(feed_map[0])); lazy_entry const* e = rd.dict_find_list("items"); if (e) { m_items.reserve(e->list_size()); for (int i = 0; i < e->list_size(); ++i) { if (e->list_at(i)->type() != lazy_entry::dict_t) continue; m_items.push_back(feed_item()); load_struct(*e->list_at(i), &m_items.back(), feed_item_map , sizeof(feed_item_map)/sizeof(feed_item_map[0])); // don't load duplicates if (m_urls.find(m_items.back().url) != m_urls.end()) { m_items.pop_back(); continue; } m_urls.insert(m_items.back().url); } } load_struct(rd, &m_settings, feed_settings_map , sizeof(feed_settings_map)/sizeof(feed_settings_map[0])); e = rd.dict_find_dict("add_params"); if (e) { load_struct(*e, &m_settings.add_args, add_torrent_map , sizeof(add_torrent_map)/sizeof(add_torrent_map[0])); } e = rd.dict_find_list("history"); if (e) { for (int i = 0; i < e->list_size(); ++i) { if (e->list_at(i)->type() != lazy_entry::list_t) continue; lazy_entry const* item = e->list_at(i); if (item->list_size() != 2 || item->list_at(0)->type() != lazy_entry::string_t || item->list_at(1)->type() != lazy_entry::int_t) continue; m_added.insert(std::pair<std::string, time_t>( item->list_at(0)->string_value() , item->list_at(1)->int_value())); } } }
// convert a lazy_entry into an old skool entry void entry::operator=(lazy_entry const& e) { switch (e.type()) { case lazy_entry::string_t: this->string() = e.string_value(); break; case lazy_entry::int_t: this->integer() = e.int_value(); break; case lazy_entry::dict_t: { dictionary_type& d = this->dict(); for (int i = 0; i < e.dict_size(); ++i) { std::pair<std::string, lazy_entry const*> elem = e.dict_at(i); d[elem.first] = *elem.second; } break; } case lazy_entry::list_t: { list_type& l = this->list(); for (int i = 0; i < e.list_size(); ++i) { l.push_back(entry()); l.back() = *e.list_at(i); } break; } case lazy_entry::none_t: destruct(); break; } }
void session_handle::load_state(lazy_entry const& ses_state , std::uint32_t const flags) { if (ses_state.type() == lazy_entry::none_t) return; std::pair<char const*, int> buf = ses_state.data_section(); bdecode_node e; error_code ec; #if TORRENT_USE_ASSERTS || !defined BOOST_NO_EXCEPTIONS int ret = #endif bdecode(buf.first, buf.first + buf.second, e, ec); TORRENT_ASSERT(ret == 0); #ifndef BOOST_NO_EXCEPTIONS if (ret != 0) throw system_error(ec); #endif sync_call(&session_impl::load_state, &e, flags); }
int line_longer_than(lazy_entry const& e, int limit) { int line_len = 0; switch (e.type()) { case lazy_entry::list_t: line_len += 4; if (line_len > limit) return -1; for (int i = 0; i < e.list_size(); ++i) { int ret = line_longer_than(*e.list_at(i), limit - line_len); if (ret == -1) return -1; line_len += ret + 2; } break; case lazy_entry::dict_t: line_len += 4; if (line_len > limit) return -1; for (int i = 0; i < e.dict_size(); ++i) { line_len += 4 + e.dict_at(i).first.size(); if (line_len > limit) return -1; int ret = line_longer_than(*e.dict_at(i).second, limit - line_len); if (ret == -1) return -1; line_len += ret + 1; } break; case lazy_entry::string_t: line_len += 3 + e.string_length(); break; case lazy_entry::int_t: { size_type val = e.int_value(); while (val > 0) { ++line_len; val /= 10; } line_len += 2; } break; case lazy_entry::none_t: line_len += 4; break; } if (line_len > limit) return -1; return line_len; }
bool http_tracker_connection::extract_peer_info(lazy_entry const& info, peer_entry& ret) { // extract peer id (if any) if (info.type() != lazy_entry::dict_t) { fail(error_code(errors::invalid_peer_dict)); return false; } lazy_entry const* i = info.dict_find_string("peer id"); if (i != 0 && i->string_length() == 20) { std::copy(i->string_ptr(), i->string_ptr()+20, ret.pid.begin()); } else { // if there's no peer_id, just initialize it to a bunch of zeroes std::fill_n(ret.pid.begin(), 20, 0); } // extract ip i = info.dict_find_string("ip"); if (i == 0) { fail(error_code(errors::invalid_tracker_response)); return false; } ret.ip = i->string_value(); // extract port i = info.dict_find_int("port"); if (i == 0) { fail(error_code(errors::invalid_tracker_response)); return false; } ret.port = (unsigned short)i->int_value(); return true; }
bool default_storage::verify_resume_data(lazy_entry const& rd, error_code& error) { lazy_entry const* file_priority = rd.dict_find_list("file_priority"); if (file_priority && file_priority->list_size() == files().num_files()) { m_file_priority.resize(file_priority->list_size()); for (int i = 0; i < file_priority->list_size(); ++i) m_file_priority[i] = boost::uint8_t(file_priority->list_int_value_at(i, 1)); } bool seed = false; if (lazy_entry const* pieces = rd.dict_find_string("pieces")) { if (int(pieces->string_length()) == m_files.num_pieces()) { seed = true; char const* p = pieces->string_ptr(); for (int i = 0; i < pieces->string_length(); ++i) { if ((p[i] & 1) == 1) continue; seed = false; break; } } } else { error = errors::missing_pieces; return false; } int flags = (settings().ignore_resume_timestamps ? ignore_timestamps : 0); return true; }
std::string parse_dht_client(lazy_entry const& e) { lazy_entry const* ver = e.dict_find_string("v"); if (!ver) return "generic"; std::string const& client = ver->string_value(); if (client.size() < 2) { ++g_unknown_message_input; return client; } else if (std::equal(client.begin(), client.begin() + 2, "Az")) { ++g_az_message_input; return "Azureus"; } else if (std::equal(client.begin(), client.begin() + 2, "UT")) { ++g_ut_message_input; return "uTorrent"; } else if (std::equal(client.begin(), client.begin() + 2, "LT")) { ++g_lt_message_input; return "libtorrent"; } else if (std::equal(client.begin(), client.begin() + 2, "MP")) { ++g_mp_message_input; return "MooPolice"; } else if (std::equal(client.begin(), client.begin() + 2, "GR")) { ++g_gr_message_input; return "GetRight"; } else if (std::equal(client.begin(), client.begin() + 2, "MO")) { ++g_mo_message_input; return "Mono Torrent"; } else { ++g_unknown_message_input; return client; } }
void load_struct(lazy_entry const& e, void* s, bencode_map_entry const* m, int num) { for (int i = 0; i < num; ++i) { lazy_entry const* key = e.dict_find(m[i].name); if (key == 0) continue; void* dest = ((char*)s) + m[i].offset; switch (m[i].type) { case std_string: { if (key->type() != lazy_entry::string_t) continue; *((std::string*)dest) = key->string_value(); break; } case character: case boolean: case integer: case size_integer: case time_integer: case floating_point: { if (key->type() != lazy_entry::int_t) continue; size_type val = key->int_value(); switch (m[i].type) { case character: *((char*)dest) = char(val); break; case integer: *((int*)dest) = int(val); break; case size_integer: *((size_type*)dest) = size_type(val); break; case time_integer: *((time_t*)dest) = time_t(val); break; case floating_point: *((float*)dest) = float(val) / 1000.f; break; case boolean: *((bool*)dest) = (val != 0); break; } } } } }
void http_tracker_connection::parse(int status_code, lazy_entry const& e) { boost::shared_ptr<request_callback> cb = requester(); if (!cb) return; int interval = int(e.dict_find_int_value("interval", 1800)); int min_interval = int(e.dict_find_int_value("min interval", 60)); std::string trackerid; lazy_entry const* tracker_id = e.dict_find_string("tracker id"); if (tracker_id) trackerid = tracker_id->string_value(); // parse the response lazy_entry const* failure = e.dict_find_string("failure reason"); if (failure) { fail(error_code(errors::tracker_failure), status_code , failure->string_value().c_str(), interval, min_interval); return; } lazy_entry const* warning = e.dict_find_string("warning message"); if (warning) cb->tracker_warning(tracker_req(), warning->string_value()); std::vector<peer_entry> peer_list; if (tracker_req().kind == tracker_request::scrape_request) { std::string ih = tracker_req().info_hash.to_string(); lazy_entry const* files = e.dict_find_dict("files"); if (files == 0) { fail(error_code(errors::invalid_files_entry), -1, "" , interval, min_interval); return; } lazy_entry const* scrape_data = files->dict_find_dict(ih.c_str()); if (scrape_data == 0) { fail(error_code(errors::invalid_hash_entry), -1, "" , interval, min_interval); return; } int complete = int(scrape_data->dict_find_int_value("complete", -1)); int incomplete = int(scrape_data->dict_find_int_value("incomplete", -1)); int downloaded = int(scrape_data->dict_find_int_value("downloaded", -1)); int downloaders = int(scrape_data->dict_find_int_value("downloaders", -1)); cb->tracker_scrape_response(tracker_req(), complete , incomplete, downloaded, downloaders); return; } lazy_entry const* peers_ent = e.dict_find("peers"); if (peers_ent && peers_ent->type() == lazy_entry::string_t) { char const* peers = peers_ent->string_ptr(); int len = peers_ent->string_length(); for (int i = 0; i < len; i += 6) { if (len - i < 6) break; peer_entry p; p.pid.clear(); error_code ec; p.ip = detail::read_v4_address(peers).to_string(ec); p.port = detail::read_uint16(peers); if (ec) continue; peer_list.push_back(p); } } else if (peers_ent && peers_ent->type() == lazy_entry::list_t) { int len = peers_ent->list_size(); for (int i = 0; i < len; ++i) { peer_entry p; if (!extract_peer_info(*peers_ent->list_at(i), p)) return; peer_list.push_back(p); } } else { peers_ent = 0; } #if TORRENT_USE_IPV6 lazy_entry const* ipv6_peers = e.dict_find_string("peers6"); if (ipv6_peers) { char const* peers = ipv6_peers->string_ptr(); int len = ipv6_peers->string_length(); for (int i = 0; i < len; i += 18) { if (len - i < 18) break; peer_entry p; p.pid.clear(); error_code ec; p.ip = detail::read_v6_address(peers).to_string(ec); p.port = detail::read_uint16(peers); if (ec) continue; peer_list.push_back(p); } } else { ipv6_peers = 0; } #else lazy_entry const* ipv6_peers = 0; #endif // if we didn't receive any peers. We don't care if we're stopping anyway if (peers_ent == 0 && ipv6_peers == 0 && tracker_req().event != tracker_request::stopped) { fail(error_code(errors::invalid_peers_entry), -1, "" , interval, min_interval); return; } // look for optional scrape info address external_ip; lazy_entry const* ip_ent = e.dict_find_string("external ip"); if (ip_ent) { char const* p = ip_ent->string_ptr(); if (ip_ent->string_length() == address_v4::bytes_type().size()) external_ip = detail::read_v4_address(p); #if TORRENT_USE_IPV6 else if (ip_ent->string_length() == address_v6::bytes_type().size()) external_ip = detail::read_v6_address(p); #endif } int complete = int(e.dict_find_int_value("complete", -1)); int incomplete = int(e.dict_find_int_value("incomplete", -1)); std::list<address> ip_list; if (m_tracker_connection) { error_code ec; ip_list.push_back(m_tracker_connection->socket().remote_endpoint(ec).address()); std::list<tcp::endpoint> const& epts = m_tracker_connection->endpoints(); for (std::list<tcp::endpoint>::const_iterator i = epts.begin() , end(epts.end()); i != end; ++i) { ip_list.push_back(i->address()); } } cb->tracker_response(tracker_req(), m_tracker_ip, ip_list, peer_list , interval, min_interval, complete, incomplete, external_ip, trackerid); }
// return 0 = success int lazy_bdecode(char const* start, char const* end, lazy_entry& ret , error_code& ec, int* error_pos, int depth_limit, int item_limit) { char const* const orig_start = start; ret.clear(); if (start == end) return 0; std::vector<lazy_entry*> stack; stack.push_back(&ret); while (start < end) { if (stack.empty()) break; // done! lazy_entry* top = stack.back(); if (int(stack.size()) > depth_limit) TORRENT_FAIL_BDECODE(errors::depth_exceeded); if (start >= end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); char t = *start; ++start; if (start >= end && t != 'e') TORRENT_FAIL_BDECODE(errors::unexpected_eof); switch (top->type()) { case lazy_entry::dict_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } if (!is_digit(t)) TORRENT_FAIL_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(errors::expected_colon); ++start; if (start == end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); lazy_entry* ent = top->dict_append(start); if (ent == 0) TORRENT_FAIL_BDECODE(errors::no_memory); start += len; if (start >= end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); stack.push_back(ent); t = *start; ++start; break; } case lazy_entry::list_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } lazy_entry* ent = top->list_append(); if (ent == 0) TORRENT_FAIL_BDECODE(errors::no_memory); stack.push_back(ent); break; } default: break; } --item_limit; if (item_limit <= 0) TORRENT_FAIL_BDECODE(errors::limit_exceeded); top = stack.back(); switch (t) { case 'd': top->construct_dict(start - 1); continue; case 'l': top->construct_list(start - 1); continue; case 'i': { char const* int_start = start; start = find_char(start, end, 'e'); top->construct_int(int_start, start - int_start); if (start == end) TORRENT_FAIL_BDECODE(errors::unexpected_eof); TORRENT_ASSERT(*start == 'e'); ++start; stack.pop_back(); continue; } default: { if (!is_digit(t)) TORRENT_FAIL_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(errors::expected_colon); ++start; top->construct_string(start, int(len)); stack.pop_back(); start += len; continue; } } return 0; } return 0; }
std::string print_entry(lazy_entry const& e, bool single_line, int indent) { char indent_str[200]; memset(indent_str, ' ', 200); indent_str[0] = ','; indent_str[1] = '\n'; indent_str[199] = 0; if (indent < 197 && indent >= 0) indent_str[indent+2] = 0; std::string ret; switch (e.type()) { case lazy_entry::none_t: return "none"; case lazy_entry::int_t: { char str[100]; snprintf(str, sizeof(str), "%"PRId64, e.int_value()); return str; } case lazy_entry::string_t: { bool printable = true; 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; printable = false; break; } ret += "'"; if (printable) { ret += e.string_value(); ret += "'"; return ret; } 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; } case lazy_entry::list_t: { ret += '['; bool one_liner = line_longer_than(e, 200) != -1 || single_line; if (!one_liner) ret += indent_str + 1; for (int i = 0; i < e.list_size(); ++i) { if (i == 0 && one_liner) ret += " "; ret += print_entry(*e.list_at(i), single_line, indent + 2); if (i < e.list_size() - 1) ret += (one_liner?", ":indent_str); else ret += (one_liner?" ":indent_str+1); } ret += "]"; return ret; } case lazy_entry::dict_t: { ret += "{"; bool one_liner = line_longer_than(e, 200) != -1 || single_line; if (!one_liner) ret += indent_str+1; for (int i = 0; i < e.dict_size(); ++i) { if (i == 0 && one_liner) ret += " "; std::pair<std::string, lazy_entry const*> ent = e.dict_at(i); ret += "'"; ret += ent.first; ret += "': "; ret += print_entry(*ent.second, single_line, indent + 2); if (i < e.dict_size() - 1) ret += (one_liner?", ":indent_str); else ret += (one_liner?" ":indent_str+1); } ret += "}"; return ret; } } return ret; }
// return 0 = success int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit) { ret.clear(); if (start == end) return 0; std::vector<lazy_entry*> stack; stack.push_back(&ret); while (start < end) { if (stack.empty()) break; // done! lazy_entry* top = stack.back(); if (int(stack.size()) > depth_limit) return fail_bdecode(ret); if (start >= end) return fail_bdecode(ret); char t = *start; ++start; if (start >= end && t != 'e') return fail_bdecode(ret); switch (top->type()) { case lazy_entry::dict_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } boost::int64_t len = t - '0'; start = parse_int(start, end, ':', len); if (start == 0 || start + len + 3 > end || *start != ':') return fail_bdecode(ret); ++start; if (start == end) fail_bdecode(ret); lazy_entry* ent = top->dict_append(start); start += len; if (start >= end) fail_bdecode(ret); stack.push_back(ent); t = *start; ++start; break; } case lazy_entry::list_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } lazy_entry* ent = top->list_append(); stack.push_back(ent); break; } default: break; } top = stack.back(); switch (t) { case 'd': top->construct_dict(start - 1); continue; case 'l': top->construct_list(start - 1); continue; case 'i': { char const* int_start = start; start = find_char(start, end, 'e'); top->construct_int(int_start, start - int_start); if (start == end) return fail_bdecode(ret); TORRENT_ASSERT(*start == 'e'); ++start; stack.pop_back(); continue; } default: { if (!is_digit(t)) return fail_bdecode(ret); boost::int64_t len = t - '0'; start = parse_int(start, end, ':', len); if (start == 0 || start + len + 1 > end || *start != ':') return fail_bdecode(ret); ++start; top->construct_string(start, int(len)); stack.pop_back(); start += len; continue; } } return 0; } return 0; }
std::string print_entry(lazy_entry const& e) { std::string ret; switch (e.type()) { case lazy_entry::none_t: return "none"; case lazy_entry::int_t: { char str[100]; snprintf(str, sizeof(str), "%"PRId64, e.int_value()); return str; } case lazy_entry::string_t: { bool printable = true; 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; printable = false; break; } ret += "'"; if (printable) { ret += e.string_value(); ret += "'"; return ret; } 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; } case lazy_entry::list_t: { ret += '['; bool one_liner = (e.list_size() == 0 || (e.list_at(0)->type() == lazy_entry::int_t && e.list_size() < 20) || (e.list_at(0)->type() == lazy_entry::string_t && (e.list_at(0)->string_length() < 10 || e.list_size() < 2) && e.list_size() < 5)); if (!one_liner) ret += "\n"; for (int i = 0; i < e.list_size(); ++i) { if (i == 0 && one_liner) ret += " "; ret += print_entry(*e.list_at(i)); if (i < e.list_size() - 1) ret += (one_liner?", ":",\n"); else ret += (one_liner?" ":"\n"); } ret += "]"; return ret; } case lazy_entry::dict_t: { ret += "{"; bool one_liner = (e.dict_size() == 0 || e.dict_at(0).second->type() == lazy_entry::int_t || (e.dict_at(0).second->type() == lazy_entry::string_t && e.dict_at(0).second->string_length() < 30) || e.dict_at(0).first.size() < 10) && e.dict_size() < 5; if (!one_liner) ret += "\n"; for (int i = 0; i < e.dict_size(); ++i) { if (i == 0 && one_liner) ret += " "; std::pair<std::string, lazy_entry const*> ent = e.dict_at(i); ret += "'"; ret += ent.first; ret += "': "; ret += print_entry(*ent.second); if (i < e.dict_size() - 1) ret += (one_liner?", ":",\n"); else ret += (one_liner?" ":"\n"); } ret += "}"; return ret; } } return ret; }
std::string print_entry(lazy_entry const& e, bool single_line, int indent) { char indent_str[200]; memset(indent_str, ' ', 200); indent_str[0] = ','; indent_str[1] = '\n'; indent_str[199] = 0; if (indent < 197 && indent >= 0) indent_str[indent+2] = 0; std::string ret; switch (e.type()) { case lazy_entry::none_t: return "none"; case lazy_entry::int_t: { char str[100]; std::snprintf(str, sizeof(str), "%" PRId64, e.int_value()); return str; } case lazy_entry::string_t: { print_string(ret, e.string_ptr(), e.string_length(), single_line); return ret; } case lazy_entry::list_t: { ret += '['; bool one_liner = line_longer_than(e, 200) != -1 || single_line; if (!one_liner) ret += indent_str + 1; for (int i = 0; i < e.list_size(); ++i) { if (i == 0 && one_liner) ret += " "; ret += print_entry(*e.list_at(i), single_line, indent + 2); if (i < e.list_size() - 1) ret += (one_liner?", ":indent_str); else ret += (one_liner?" ":indent_str+1); } ret += "]"; return ret; } case lazy_entry::dict_t: { ret += "{"; bool one_liner = line_longer_than(e, 200) != -1 || single_line; if (!one_liner) ret += indent_str+1; for (int i = 0; i < e.dict_size(); ++i) { if (i == 0 && one_liner) ret += " "; std::pair<std::string, lazy_entry const*> ent = e.dict_at(i); print_string(ret, ent.first.c_str(), int(ent.first.size()), true); ret += ": "; ret += print_entry(*ent.second, single_line, indent + 2); if (i < e.dict_size() - 1) ret += (one_liner?", ":indent_str); else ret += (one_liner?" ":indent_str+1); } ret += "}"; return ret; } } return ret; }
// return 0 = success int lazy_bdecode(char const* start, char const* end, lazy_entry& ret , error_code& ec, int* error_pos, int depth_limit, int item_limit) { char const* const orig_start = start; ret.clear(); std::vector<lazy_entry*> stack; if (start == end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); stack.push_back(&ret); while (start <= end) { if (stack.empty()) break; // done! lazy_entry* top = stack.back(); if (int(stack.size()) > depth_limit) TORRENT_FAIL_BDECODE(bdecode_errors::depth_exceeded); if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); char t = *start; ++start; if (start >= end && t != 'e') TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); switch (top->type()) { case lazy_entry::dict_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_digit); std::int64_t len = t - '0'; bdecode_errors::error_code_enum e = bdecode_errors::no_error; start = parse_int(start, end, ':', len, e); if (e) TORRENT_FAIL_BDECODE(e); // remaining buffer size excluding ':' const ptrdiff_t buff_size = end - start - 1; if (len > buff_size) 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); if (ent == nullptr) TORRENT_FAIL_BDECODE(boost::system::errc::not_enough_memory); start += len; if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); stack.push_back(ent); t = *start; ++start; break; } case lazy_entry::list_t: { if (t == 'e') { top->set_end(start); stack.pop_back(); continue; } lazy_entry* ent = top->list_append(); if (ent == nullptr) TORRENT_FAIL_BDECODE(boost::system::errc::not_enough_memory); stack.push_back(ent); break; } case lazy_entry::int_t: case lazy_entry::string_t: case lazy_entry::none_t: break; } --item_limit; if (item_limit <= 0) TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded); top = stack.back(); switch (t) { case 'd': top->construct_dict(start - 1); break; case 'l': top->construct_list(start - 1); break; case 'i': { char const* int_start = start; start = find_char(start, end, 'e'); top->construct_int(int_start, start - int_start); if (start == end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); TORRENT_ASSERT(*start == 'e'); ++start; stack.pop_back(); break; } default: { if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_value); std::int64_t len = t - '0'; bdecode_errors::error_code_enum e = bdecode_errors::no_error; start = parse_int(start, end, ':', len, e); if (e) TORRENT_FAIL_BDECODE(e); // remaining buffer size excluding ':' const ptrdiff_t buff_size = end - start - 1; if (len > buff_size) 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); top->construct_string(start, int(len)); start += len; stack.pop_back(); break; } } } return 0; }