diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index 7a8e8dd98..7f749436d 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -90,6 +90,8 @@ namespace libtorrent attribute_symlink = 8 }; + void reserve(int num_files); + void add_file(file_entry const& e); void add_file(std::string const& p, size_type size, int flags = 0 , std::time_t mtime = 0, std::string const& s_p = ""); diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index 4fff0f63c..4afc425a0 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -145,6 +145,7 @@ namespace libtorrent { return const_cast(this)->dict_find(name); } std::string dict_find_string_value(char const* name) const; + pascal_string dict_find_pstr(char const* name) const; size_type dict_find_int_value(char const* name, size_type default_val = 0) const; lazy_entry const* dict_find_dict(char const* name) const; lazy_entry const* dict_find_list(char const* name) const; @@ -187,6 +188,7 @@ namespace libtorrent { return const_cast(this)->list_at(i); } std::string list_string_value_at(int i) const; + pascal_string list_pstr_at(int i) const; size_type list_int_value_at(int i, size_type default_val = 0) const; int list_size() const diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index acd8371bd..287f62427 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -173,6 +173,7 @@ namespace libtorrent #endif // TORRENT_USE_WSTRING #endif + torrent_info(torrent_info const& t); torrent_info(sha1_hash const& info_hash); torrent_info(lazy_entry const& torrent_file, error_code& ec); torrent_info(char const* buffer, int size, error_code& ec); @@ -320,6 +321,9 @@ namespace libtorrent private: + // not assignable + torrent_info const& operator=(torrent_info const&); + void copy_on_write(); bool parse_torrent_file(lazy_entry const& libtorrent, error_code& ec); diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 2c7ae3c49..f9123acbf 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -46,6 +46,11 @@ namespace libtorrent , m_num_pieces(0) {} + void file_storage::reserve(int num_files) + { + m_files.reserve(num_files); + } + int file_storage::piece_size(int index) const { TORRENT_ASSERT(index >= 0 && index < num_pieces()); diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index eb6f9c056..c8aae871d 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -49,7 +49,7 @@ namespace libtorrent { int fail_bdecode(lazy_entry& ret) { - ret = lazy_entry(); + ret.clear(); return -1; } @@ -264,6 +264,13 @@ namespace libtorrent return e->string_value(); } + pascal_string lazy_entry::dict_find_pstr(char const* name) const + { + lazy_entry const* e = dict_find(name); + if (e == 0 || e->type() != lazy_entry::string_t) return pascal_string(0, 0); + return e->string_pstr(); + } + lazy_entry const* lazy_entry::dict_find_string(char const* name) const { lazy_entry const* e = dict_find(name); @@ -338,6 +345,13 @@ namespace libtorrent return e->string_value(); } + pascal_string lazy_entry::list_pstr_at(int i) const + { + lazy_entry const* e = list_at(i); + if (e == 0 || e->type() != lazy_entry::string_t) return pascal_string(0, 0); + return e->string_pstr(); + } + size_type lazy_entry::list_int_value_at(int i, size_type default_val) const { lazy_entry const* e = list_at(i); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 32857ffa8..eea0b730e 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -303,14 +303,24 @@ namespace libtorrent return true; } - struct pascal_string + struct string_less_no_case { - int len; - char const* ptr; - bool operator<(pascal_string const& rhs) const + bool operator()(std::string const& lhs, std::string const& rhs) { - return memcmp(ptr, rhs.ptr, (std::min)(len, rhs.len)) < 0 - || len < rhs.len; + char c1, c2; + char const* s1 = lhs.c_str(); + char const* s2 = rhs.c_str(); + + while (*s1 != 0 && *s2 != 0) + { + c1 = to_lower(*s1); + c2 = to_lower(*s2); + if (c1 < c2) return true; + if (c1 > c2) return false; + ++s1; + ++s2; + } + return false; } }; @@ -318,29 +328,23 @@ namespace libtorrent , std::string const& root_dir) { if (list.type() != lazy_entry::list_t) return false; + target.reserve(list.list_size()); for (int i = 0, end(list.list_size()); i < end; ++i) { file_entry e; if (!extract_single_file(*list.list_at(i), e, root_dir)) return false; int cnt = 0; - std::set files; - pascal_string = - while (!files.insert(path).second) - for (file_storage::iterator k = target.begin() - , end(target.end()); k != end; ++k) + std::set files; + + // as long as we this file already exists + // increase the counter + while (!files.insert(e.path).second) { - if (string_equal_no_case(e.path.c_str() - , k->path.c_str())) ++cnt; - } - if (cnt) - { - char suffix[15]; - snprintf(suffix, sizeof(suffix), ".%d", cnt); - replace_extension(e.path, suffix + extension(e.path)); - // TODO: we should really make sure that this new name - // doesn't already exist as well, otherwise we might - // just create another collision + ++cnt; + char suffix[50]; + snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(e.path).c_str()); + replace_extension(e.path, suffix); } target.add_file(e); } @@ -403,6 +407,42 @@ namespace libtorrent updating = false; } + torrent_info::torrent_info(torrent_info const& t) + : m_files(t.m_files) + , m_orig_files(t.m_orig_files) + , m_urls(t.m_urls) + , m_url_seeds(t.m_url_seeds) + , m_http_seeds(t.m_http_seeds) + , m_nodes(t.m_nodes) + , m_info_hash(t.m_info_hash) + , m_creation_date(t.m_creation_date) + , m_comment(t.m_comment) + , m_created_by(t.m_created_by) + , m_multifile(t.m_multifile) + , m_private(t.m_private) + , m_i2p(t.m_i2p) + , m_info_section_size(t.m_info_section_size) + , m_piece_hashes(t.m_piece_hashes) + , m_merkle_tree(t.m_merkle_tree) + , m_merkle_first_leaf(t.m_merkle_first_leaf) + { + if (m_info_section_size > 0) + { + m_info_section.reset(new char[m_info_section_size]); + memcpy(m_info_section.get(), t.m_info_section.get(), m_info_section_size); + int ret = lazy_bdecode(m_info_section.get(), m_info_section.get() + + m_info_section_size, m_info_dict); + + lazy_entry const* pieces = m_info_dict.dict_find_string("pieces"); + if (pieces && pieces->string_length() == m_files.num_pieces() * 20) + { + m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); + } + } + } + #ifndef TORRENT_NO_DEPRECATE // standard constructor that parses a torrent file torrent_info::torrent_info(entry const& torrent_file) @@ -638,7 +678,9 @@ namespace libtorrent swap(m_info_section, ti.m_info_section); swap(m_info_section_size, ti.m_info_section_size); swap(m_piece_hashes, ti.m_piece_hashes); - swap(m_info_dict, ti.m_info_dict); + m_info_dict.swap(ti.m_info_dict); + swap(m_merkle_tree, ti.m_merkle_tree); + swap(m_merkle_first_leaf, ti.m_merkle_first_leaf); } bool torrent_info::parse_info_section(lazy_entry const& info, error_code& ec)