diff --git a/ChangeLog b/ChangeLog index ab723b828..9aa046a68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * handle torrents with duplicate filenames * piece timeouts are adjusted to download rate limits * encodes urls in torrent files that needs to be encoded * fixed not passing &supportcrypto=1 when encryption is disabled diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index f24923015..4590cfb9a 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -50,6 +50,7 @@ namespace libtorrent char TORRENT_EXPORT to_lower(char c); bool TORRENT_EXPORT string_begins_no_case(char const* s1, char const* s2); + bool TORRENT_EXPORT string_equal_no_case(char const* s1, char const* s2); std::string TORRENT_EXPORT unescape_string(std::string const& s, error_code& ec); // replaces all disallowed URL characters by their %-encoding diff --git a/src/escape_string.cpp b/src/escape_string.cpp index 0578cd46c..228492feb 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -111,6 +111,17 @@ namespace libtorrent return true; } + bool string_equal_no_case(char const* s1, char const* s2) + { + while (to_lower(*s1) == to_lower(*s2)) + { + if (*s1 == 0) return true; + ++s1; + ++s2; + } + return false; + } + std::string unescape_string(std::string const& s, error_code& ec) { std::string ret; diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 5f500d745..d30b3fb0e 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -264,7 +264,7 @@ namespace libtorrent case 'p': target.pad_file = true; break; } } - } + } return true; } @@ -278,6 +278,22 @@ namespace libtorrent file_entry e; if (!extract_single_file(*list.list_at(i), e, root_dir)) return false; + int cnt = 0; + for (file_storage::iterator k = target.begin() + , end(target.end()); k != end; ++k) + { + if (string_equal_no_case(e.path.string().c_str() + , k->path.string().c_str())) ++cnt; + } + if (cnt) + { + char suffix[15]; + snprintf(suffix, sizeof(suffix), ".%d", cnt); + e.path.replace_extension(suffix + e.path.extension()); + // TODO: we should really make sure that this new name + // doesn't already exist as well, otherwise we might + // just create another collision + } target.add_file(e); } return true; diff --git a/src/upnp.cpp b/src/upnp.cpp index 81fac31fd..0cd755e11 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -746,17 +746,6 @@ namespace dst.clear(); while (*src) dst.push_back(to_lower(*src++)); } - - bool string_equal_nocase(char const* lhs, char const* rhs) - { - while (to_lower(*lhs) == to_lower(*rhs)) - { - if (*lhs == 0) return true; - ++lhs; - ++rhs; - } - return false; - } } struct parse_state @@ -781,10 +770,10 @@ struct parse_state { std::list::reverse_iterator i = tag_stack.rbegin(); if (i == tag_stack.rend()) return false; - if (!string_equal_nocase(i->c_str(), str2)) return false; + if (!string_equal_no_case(i->c_str(), str2)) return false; ++i; if (i == tag_stack.rend()) return false; - if (!string_equal_nocase(i->c_str(), str1)) return false; + if (!string_equal_no_case(i->c_str(), str1)) return false; return true; } }; @@ -814,7 +803,7 @@ void find_control_url(int type, char const* string, parse_state& state) // std::cout << " " << string << std::endl; if (!state.in_service && state.top_tags("service", "servicetype")) { - if (string_equal_nocase(string, state.service_type)) + if (string_equal_no_case(string, state.service_type)) state.in_service = true; } else if (state.in_service && state.top_tags("service", "controlurl")) diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index a4bdffaaa..a38f3482a 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -423,6 +423,13 @@ int test_main() TEST_CHECK(to_lower('-') == '-'); TEST_CHECK(to_lower('&') == '&'); + // test string_equal_no_case + + TEST_CHECK(string_equal_no_case("foobar", "FoobAR")); + TEST_CHECK(string_equal_no_case("foobar", "foobar")); + TEST_CHECK(!string_equal_no_case("foobar", "foobar ")); + TEST_CHECK(!string_equal_no_case("foobar", "F00")); + // test string_begins_no_case TEST_CHECK(string_begins_no_case("foobar", "FoobAR --"));