From edfa38cd305064d8f8c3b86fa52b81b64f6a9c9c Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 17 Nov 2014 03:41:01 +0000 Subject: [PATCH] merged changes from RC_1_0 --- CMakeLists.txt | 21 ++- ChangeLog | 1 + examples/CMakeLists.txt | 29 ++++ examples/Makefile.am | 2 +- examples/client_test.cpp | 143 +++++++++++++++---- examples/cmake/FindLibtorrentRasterbar.cmake | 47 ++++++ include/libtorrent/config.hpp | 15 +- src/enum_net.cpp | 8 +- src/file.cpp | 10 +- src/torrent_info.cpp | 109 ++++++-------- test/test_torrent_parse.cpp | 46 +++++- test/test_torrents/slash_path2.torrent | 1 + test/test_torrents/slash_path3.torrent | 1 + 13 files changed, 316 insertions(+), 117 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/cmake/FindLibtorrentRasterbar.cmake create mode 100644 test/test_torrents/slash_path2.torrent create mode 100644 test/test_torrents/slash_path3.torrent diff --git a/CMakeLists.txt b/CMakeLists.txt index 7244165db..fcc0ed13c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,8 @@ if (build_tests) add_definitions(-DTORRENT_EXPORT_EXTRA) endif (build_tests) +include_directories(${includes}) + if (encryption) list(APPEND sources pe_crypto asio_ssl) if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES) @@ -313,8 +315,6 @@ if (tcmalloc) target_link_libraries(torrent-rasterbar tcmalloc) endif() -include_directories(${includes}) - set_target_properties(torrent-rasterbar PROPERTIES SOVERSION ${SOVERSION}) @@ -326,9 +326,7 @@ foreach (s ${COMPILETIME_OPTIONS_LIST}) set (COMPILETIME_OPTIONS "${COMPILETIME_OPTIONS} -D${s}") endforeach (s) -if (MSVC) - configure_file(libtorrent-rasterbar-cmake.pc.in libtorrent-rasterbar.pc) -endif() +configure_file(libtorrent-rasterbar-cmake.pc.in libtorrent-rasterbar.pc) string (COMPARE EQUAL "${CMAKE_SIZEOF_VOID_P}" "8" IS64BITS) @@ -346,14 +344,13 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libtorrent-rasterbar.pc DESTINATION ${ # === build examples === if(build_examples) - FILE(GLOB examples RELATIVE "${PROJECT_SOURCE_DIR}" "examples/*.cpp") - foreach(s ${examples}) - get_filename_component (sn ${s} NAME_WE) - add_executable(${sn} ${s}) - target_link_libraries(${sn} torrent-rasterbar) - endforeach(s) + # this will make some internal functions available in the + # DLL interface, for the examples to access + add_definitions(-DTORRENT_EXPORT_EXTRA) - include_directories(${Boost_INCLUDE_DIR}) + # to build the examples, run cmake in this subdirectory + # after libtorrent is built + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/examples) endif() # === build tests === diff --git a/ChangeLog b/ChangeLog index e772b0abe..5e650ee77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,7 @@ 1.0.3 release + * handle overlong utf-8 sequences * fix link order bug in makefile for python binding * fix bug in interest calculation, causing premature disconnects * tweak flag_override_resume_data semantics to make more sense (breaks diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 000000000..e22fedbc7 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,29 @@ +project(libtorrent-examples) +cmake_minimum_required(VERSION 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + +# Add extra include and library search directories so examples can optionally +# be built without a prior "make install" of libtorrent. +list(APPEND CMAKE_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../include") +list(APPEND CMAKE_LIBRARY_PATH "${CMAKE_CURRENT_BINARY_DIR}/..") + +# Also use the generated pkg-config file prior to "make install". +# In an independent project, these lines would simply not exist. +set(PKG_CONFIG_CHANGED_PATH "${CMAKE_CURRENT_BINARY_DIR}/..;$ENV{PKG_CONFIG_PATH}") +if(UNIX) + string(REPLACE ";" ":" PKG_CONFIG_CHANGED_PATH "${PKG_CONFIG_CHANGED_PATH}") +endif () +set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_CHANGED_PATH}") + +find_package(LibtorrentRasterbar REQUIRED) +find_package(Boost REQUIRED COMPONENTS system) + +include_directories(${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) +add_definitions(${LibtorrentRasterbar_DEFINITIONS}) + +FILE(GLOB examples RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.cpp") +foreach(s ${examples}) + get_filename_component (sn ${s} NAME_WE) + add_executable(${sn} ${s}) + target_link_libraries(${sn} ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES}) +endforeach(s) diff --git a/examples/Makefile.am b/examples/Makefile.am index 9a2cbe072..10a2a185a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -13,7 +13,7 @@ bin_PROGRAMS = $(example_programs) endif EXTRA_PROGRAMS = $(example_programs) -EXTRA_DIST = Jamfile +EXTRA_DIST = Jamfile CMakeLists.txt cmake/FindLibtorrentRasterbar.cmake client_test_SOURCES = client_test.cpp print.cpp session_view.cpp torrent_view.cpp #client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 57e7115b8..9d16e5714 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -242,6 +242,41 @@ int load_file(std::string const& filename, std::vector& v return 0; } +bool is_absolute_path(std::string const& f) +{ + if (f.empty()) return false; +#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2) + int i = 0; + // match the xx:\ or xx:/ form + while (f[i] && strchr("abcdefghijklmnopqrstuvxyz", f[i])) ++i; + if (i < int(f.size()-1) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/')) + return true; + + // match the \\ form + if (int(f.size()) >= 2 && f[0] == '\\' && f[1] == '\\') + return true; + return false; +#else + if (f[0] == '/') return true; + return false; +#endif +} + +std::string path_append(std::string const& lhs, std::string const& rhs) +{ + if (lhs.empty() || lhs == ".") return rhs; + if (rhs.empty() || rhs == ".") return lhs; + +#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2) +#define TORRENT_SEPARATOR "\\" + bool need_sep = lhs[lhs.size()-1] != '\\' && lhs[lhs.size()-1] != '/'; +#else +#define TORRENT_SEPARATOR "/" + bool need_sep = lhs[lhs.size()-1] != '/'; +#endif + return lhs + (need_sep?TORRENT_SEPARATOR:"") + rhs; +} + bool is_hex(char const *in, int len) { for (char const* end = in + len; in < end; ++in) @@ -572,8 +607,7 @@ void add_torrent(libtorrent::session& ses if (share_mode) p.flags |= add_torrent_params::flag_share_mode; lazy_entry resume_data; - // TODO: implement combine_path in here, since it's internal to libtorrent - std::string filename = combine_path(save_path, combine_path(".resume" + std::string filename = path_append(save_path, path_append(".resume" , libtorrent::filename(torrent) + ".resume")); error_code ec; @@ -595,6 +629,67 @@ void add_torrent(libtorrent::session& ses files.insert(std::pair(torrent, torrent_handle())); } +std::vector list_dir(std::string path + , bool (*filter_fun)(std::string const&)) +{ + std::vector ret; +#ifdef TORRENT_WINDOWS + if (!f.empty() && f[f.size()-1] != '\\') f += "\\*"; + else f += "*"; + + std::wstring wpath; + libtorrent::utf8_wchar(path, wpath); + + WIN32_FIND_DATAW fd; + HANDLE handle = FindFirstFileW(wpath.c_str(), &fd); + if (handle == INVALID_HANDLE_VALUE) + return ret; + + do + { + std::string p; + libtorrent::wchar_utf8(fd.cFileName, p); + if (filter_fun(p)) + ret.push_back(p); + + } while (FindNextFileW(handle, &fd)); + FindClose(handle); +#else + + if (!path.empty() && path[path.size()-1] == '/') + path.resize(path.size()-1); + + DIR* handle = opendir(path.c_str()); + if (handle == 0) return ret; + + struct dirent de; + dirent* dummy; + while (readdir_r(handle, &de, &dummy) == 0) + { + if (dummy == 0) break; + + std::string p = de.d_name; + if (filter_fun(p)) + ret.push_back(p); + } +#endif + return ret; +} + +bool filter_fun(std::string const& p) +{ + for (int i = p.size() - 1; i >= 0; --i) + { + if (p[i] == '/') break; +#ifdef TORRENT_WINDOWS + if (p[i] == '\\') break; +#endif + if (p[i] != '.') continue; + return p.compare(i, 8, ".torrent") == 0; + } + return false; +} + void scan_dir(std::string const& dir_path , libtorrent::session& ses , handles_t& files @@ -609,20 +704,12 @@ void scan_dir(std::string const& dir_path using namespace libtorrent; error_code ec; - std::vector > ents; - // TODO: don't use internal directory type - for (directory i(dir_path, ec); !i.done(); i.next(ec)) - { - if (extension(i.file()) != ".torrent") continue; - ents.push_back(std::make_pair(i.inode(), i.file())); - } + std::vector ents = list_dir(dir_path, filter_fun); - std::sort(ents.begin(), ents.end()); - - for (std::vector >::iterator i = ents.begin() + for (std::vector::iterator i = ents.begin() , end(ents.end()); i != end; ++i) { - std::string file = combine_path(dir_path, i->second); + std::string file = path_append(dir_path, *i); handles_t::iterator k = files.find(file); if (k != files.end()) @@ -737,7 +824,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a torrent_handle h = p->handle; error_code ec; file_status st; - std::string base_name = combine_path("certificates", to_hex(h.info_hash().to_string())); + std::string base_name = path_append("certificates", to_hex(h.info_hash().to_string())); std::string cert = base_name + ".pem"; std::string priv = base_name + "_key.pem"; stat_file(cert, &st, ec); @@ -781,7 +868,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a bencode(std::back_inserter(buffer), te); sha1_hash hash = ti->info_hash(); std::string filename = ti->name() + "." + to_hex(hash.to_string()) + ".torrent"; - filename = combine_path(monitor_dir, filename); + filename = path_append(monitor_dir, filename); save_file(filename, buffer); files.insert(std::pair(filename, h)); @@ -871,7 +958,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a std::vector out; bencode(std::back_inserter(out), *p->resume_data); torrent_status st = h.status(torrent_handle::query_save_path); - save_file(combine_path(st.save_path, combine_path(".resume", libtorrent::filename( + save_file(path_append(st.save_path, path_append(".resume", libtorrent::filename( hash_to_filename[st.info_hash]) + ".resume")), out); if (h.is_valid() && non_files.find(h) == non_files.end() @@ -1321,10 +1408,10 @@ int main(int argc, char* argv[]) } // create directory for resume files - // TODO: don't use internal create_directory function - create_directory(combine_path(save_path, ".resume"), ec); - if (ec) - fprintf(stderr, "failed to create resume file directory: %s\n", ec.message().c_str()); + int ret = mkdir(path_append(save_path, ".resume").c_str(), 0777); + if (ret < 0) + fprintf(stderr, "failed to create resume file directory: (%d) %s\n" + , errno, strerror(errno)); if (bind_to_interface.empty()) bind_to_interface = "0.0.0.0"; settings.set_str(settings_pack::listen_interfaces, bind_to_interface + ":" + to_string(listen_port).elems); @@ -1382,7 +1469,7 @@ int main(int argc, char* argv[]) if (ec) continue; - std::string filename = combine_path(save_path, combine_path(".resume" + std::string filename = path_append(save_path, path_append(".resume" , to_hex(tmp.info_hash.to_string()) + ".resume")); load_file(filename.c_str(), p.resume_data, ec); @@ -1522,7 +1609,7 @@ int main(int argc, char* argv[]) if (ec) continue; - std::string filename = combine_path(save_path, combine_path(".resume" + std::string filename = path_append(save_path, path_append(".resume" , to_hex(tmp.info_hash.to_string()) + ".resume")); load_file(filename.c_str(), p.resume_data, ec); @@ -1550,10 +1637,10 @@ int main(int argc, char* argv[]) { error_code ec; std::string path; - if (is_complete(i->first)) path = i->first; - else path = combine_path(monitor_dir, i->first); - remove(path, ec); - if (ec) printf("failed to delete .torrent file: %s\n", ec.message().c_str()); + if (is_absolute_path(i->first)) path = i->first; + else path = path_append(monitor_dir, i->first); + if (::remove(path.c_str()) < 0) + printf("failed to delete .torrent file: %s\n", ec.message().c_str()); files.erase(i); } if (st.handle.is_valid()) @@ -2054,8 +2141,8 @@ int main(int argc, char* argv[]) torrent_status st = h.status(torrent_handle::query_save_path); std::vector out; bencode(std::back_inserter(out), *rd->resume_data); - save_file(combine_path(st.save_path, combine_path(".resume", libtorrent::filename( - hash_to_filename[st.info_hash]) + ".resume")), out); + save_file(path_append(st.save_path, path_append(".resume" + , libtorrent::filename(hash_to_filename[st.info_hash]) + ".resume")), out); } } diff --git a/examples/cmake/FindLibtorrentRasterbar.cmake b/examples/cmake/FindLibtorrentRasterbar.cmake new file mode 100644 index 000000000..0cab08bfe --- /dev/null +++ b/examples/cmake/FindLibtorrentRasterbar.cmake @@ -0,0 +1,47 @@ +# - Try to find libtorrent-rasterbar +# Once done this will define +# LibtorrentRasterbar_FOUND - System has libtorrent-rasterbar +# LibtorrentRasterbar_INCLUDE_DIRS - The libtorrent-rasterbar include directories +# LibtorrentRasterbar_LIBRARIES - The libraries needed to use libtorrent-rasterbar +# LibtorrentRasterbar_DEFINITIONS - Compiler switches required for using libtorrent-rasterbar + +find_package(PkgConfig) +pkg_check_modules(PC_LIBTORRENT_RASTERBAR libtorrent-rasterbar) + +if (PC_LIBTORRENT_RASTERBAR_FOUND) + set(LibtorrentRasterbar_DEFINITIONS ${PC_LIBTORRENT_RASTERBAR_CFLAGS}) +else () + # Without pkg-config, we can't possibly figure out the correct build flags. + # libtorrent is very picky about those. Let's take a set of defaults and + # hope that they apply. If not, you the user are on your own. + set(LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL -DTORRENT_DISABLE_GEO_IP -DTORRENT_LINKING_SHARED -DBOOST_ASIO_DYN_LINK -DBOOST_ASIO_ENABLE_CANCELIO -DBOOST_EXCEPTION_DISABLE -DBOOST_DATE_TIME_DYN_LINK -DBOOST_THREAD_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_CHRONO_DYN_LINK -DUNICODE -D_UNICODE -D_FILE_OFFSET_BITS=64) +endif () + +find_path(LibtorrentRasterbar_INCLUDE_DIR libtorrent + HINTS ${PC_LIBTORRENT_RASTERBAR_INCLUDEDIR} ${PC_LIBTORRENT_RASTERBAR_INCLUDE_DIRS} + PATH_SUFFIXES libtorrent-rasterbar) + +find_library(LibtorrentRasterbar_LIBRARY NAMES torrent-rasterbar + HINTS ${PC_LIBTORRENT_RASTERBAR_LIBDIR} ${PC_LIBTORRENT_RASTERBAR_LIBRARY_DIRS}) + +set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARY}) +set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIR}) + +if (NOT Boost_SYSTEM_FOUND OR NOT Boost_THREAD_FOUND OR NOT Boost_DATE_TIME_FOUND OR NOT Boost_CHRONO_FOUND) + find_package(Boost REQUIRED COMPONENTS system thread date_time chrono) + set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES}) + set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) +endif () + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LibtorrentRasterbar_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(LibtorrentRasterbar DEFAULT_MSG + LibtorrentRasterbar_LIBRARY + LibtorrentRasterbar_INCLUDE_DIR + Boost_SYSTEM_FOUND + Boost_THREAD_FOUND + Boost_DATE_TIME_FOUND + Boost_CHRONO_FOUND) + +mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY) diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index 0818067c8..5acf4c8e0 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -320,7 +320,13 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_READV 0 #else -#warning unknown OS, assuming BSD + +#ifdef _MSC_VER +#pragma message ( "unknown OS, assuming BSD" ) +#else +#warning "unknown OS, assuming BSD" +#endif + #define TORRENT_BSD #endif @@ -359,7 +365,12 @@ POSSIBILITY OF SUCH DAMAGE. // this is the maximum number of characters in a // path element / filename on windows #define TORRENT_MAX_PATH 255 -#warning unknown platform, assuming the longest path is 255 + +#ifdef _MSC_VER +#pragma message ( "unknown platform, assuming the longest path is 255" ) +#else +#warning "unknown platform, assuming the longest path is 255" +#endif #endif diff --git a/src/enum_net.cpp b/src/enum_net.cpp index 4373318ac..aa8b99b5c 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -643,7 +643,13 @@ namespace libtorrent } #else -#warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK + +#ifdef _MSC_VER +#pragma message ( "THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK" ) +#else +#warning "THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK" +#endif + // make a best guess of the interface we're using and its IP udp::resolver r(ios); udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec); diff --git a/src/file.cpp b/src/file.cpp index ad573570a..568f009af 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -293,10 +293,14 @@ BOOST_STATIC_ASSERT((libtorrent::file::rw_mask & libtorrent::file::attribute_mas BOOST_STATIC_ASSERT((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0); #endif -#ifdef TORRENT_WINDOWS -#if defined UNICODE && !TORRENT_USE_WSTRING -#warning wide character support not available. Files will be saved using narrow string names +#if defined TORRENT_WINDOWS && defined UNICODE && !TORRENT_USE_WSTRING + +#ifdef _MSC_VER +#pragma message ( "wide character support not available. Files will be saved using narrow string names" ) +#else +#warning "wide character support not available. Files will be saved using narrow string names" #endif + #endif // TORRENT_WINDOWS namespace libtorrent diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 14f9d4d44..34854192e 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include "libtorrent/config.hpp" +#include "libtorrent/ConvertUTF.h" #include "libtorrent/torrent_info.hpp" #include "libtorrent/escape_string.hpp" // is_space #include "libtorrent/bencode.hpp" @@ -95,85 +96,65 @@ namespace libtorrent std::string tmp_path; tmp_path.reserve(target.size()+5); bool valid_encoding = true; - for (std::string::iterator i = target.begin() - , end(target.end()); i != end; ++i) + + UTF8 const* ptr = (UTF8 const*)&target[0]; + UTF8 const* end = (UTF8 const*)&target[0] + target.size(); + while (ptr < end) { - // valid ascii-character - if ((*i & 0x80) == 0) + UTF32 codepoint; + UTF32* cp = &codepoint; + + // decode a single utf-8 character + ConversionResult res = ConvertUTF8toUTF32(&ptr, end, &cp, cp + 1 + , lenientConversion); + + // this was the last character, and nothing was + // written to the destination buffer (i.e. the source character was + // truncated) + if (res == sourceExhausted + || res == sourceIllegal) { - // replace invalid characters with '_' - if (!fix_paths || valid_path_character(*i)) + if (cp == &codepoint) { - tmp_path += *i; - } - else - { - tmp_path += '_'; + if (res == sourceExhausted) + ptr = end; + else + ++ptr; + + codepoint = '_'; valid_encoding = false; } - continue; } - - if (end - i < 2) + else if ((res != conversionOK && res != targetExhausted) + || codepoint == UNI_REPLACEMENT_CHAR) { - tmp_path += "_"; + // we expect the conversion to fail with targetExhausted, since we + // only pass in a single destination character slot. The last + // character will succeed though. Also, if the character was replaced, + // use our own replacement symbol (underscore). + codepoint = '_'; valid_encoding = false; - break; - } - - // valid 2-byte utf-8 character - if ((i[0] & 0xe0) == 0xc0 - && (i[1] & 0xc0) == 0x80) - { - tmp_path += i[0]; - tmp_path += i[1]; - i += 1; - continue; } - if (end - i < 3) + // if fix paths is true, also replace characters that are invalid + // in filenames + if (fix_paths && codepoint < 0x7f && !valid_path_character(codepoint)) { - tmp_path += "_"; + codepoint = '_'; valid_encoding = false; - break; } - // valid 3-byte utf-8 character - if ((i[0] & 0xf0) == 0xe0 - && (i[1] & 0xc0) == 0x80 - && (i[2] & 0xc0) == 0x80) - { - tmp_path += i[0]; - tmp_path += i[1]; - tmp_path += i[2]; - i += 2; - continue; - } + // encode codepoint into utf-8 + cp = &codepoint; + UTF8 sequence[5]; + UTF8* start = sequence; + res = ConvertUTF32toUTF8((const UTF32**)&cp, cp + 1, &start, start + 5, lenientConversion); + TORRENT_ASSERT(res == conversionOK); - if (end - i < 4) - { - tmp_path += "_"; - valid_encoding = false; - break; - } - - // valid 4-byte utf-8 character - if ((i[0] & 0xf8) == 0xf0 - && (i[1] & 0xc0) == 0x80 - && (i[2] & 0xc0) == 0x80 - && (i[3] & 0xc0) == 0x80) - { - tmp_path += i[0]; - tmp_path += i[1]; - tmp_path += i[2]; - tmp_path += i[3]; - i += 3; - continue; - } - - tmp_path += "_"; - valid_encoding = false; + for (int i = 0; i < start - sequence; ++i) + tmp_path += (char)sequence[i]; } + // the encoding was not valid utf-8 // save the original encoding and replace the // commonly used path with the correctly @@ -1229,7 +1210,7 @@ namespace libtorrent } m_multifile = true; } - files.set_name(name); + TORRENT_ASSERT(!files.name().empty()); // extract sha-1 hashes for all pieces // we want this division to round upwards, that's why we have the diff --git a/test/test_torrent_parse.cpp b/test/test_torrent_parse.cpp index dbdf3fa14..9a20edc47 100644 --- a/test/test_torrent_parse.cpp +++ b/test/test_torrent_parse.cpp @@ -54,6 +54,8 @@ test_torrent_t test_torrents[] = { "hidden_parent_path.torrent" }, { "single_multi_file.torrent" }, { "slash_path.torrent" }, + { "slash_path2.torrent" }, + { "slash_path3.torrent" }, { "backslash_path.torrent" }, { "url_list.torrent" }, { "url_list2.torrent" }, @@ -259,11 +261,7 @@ int test_main() bencode(std::back_inserter(buf), torrent); torrent_info ti2(&buf[0], buf.size(), ec); std::cerr << ti2.name() << std::endl; -#ifdef TORRENT_WINDOWS - TEST_CHECK(ti2.name() == "ctest1test2test3"); -#else - TEST_CHECK(ti2.name() == "test1test2test3"); -#endif + TEST_EQUAL(ti2.name(), "test1test2test3"); info["name.utf-8"] = "test2/../test3/.././../../test4"; torrent["info"] = info; @@ -271,7 +269,7 @@ int test_main() bencode(std::back_inserter(buf), torrent); torrent_info ti3(&buf[0], buf.size(), ec); std::cerr << ti3.name() << std::endl; - TEST_CHECK(ti3.name() == "test2..test3.......test4"); + TEST_EQUAL(ti3.name(), "test2..test3.......test4"); // verify_encoding std::string test = "\b?filename=4"; @@ -334,6 +332,27 @@ int test_main() fprintf(stderr, "%s\n", test.c_str()); TEST_CHECK(test == "filename_____foobar"); + // redundant (overlong) 2-byte sequence + // ascii code 0x2e encoded with a leading 0 + test = "filename\xc0\xae"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s\n", test.c_str()); + TEST_CHECK(test == "filename__"); + + // redundant (overlong) 3-byte sequence + // ascii code 0x2e encoded with two leading 0s + test = "filename\xe0\x80\xae"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s\n", test.c_str()); + TEST_CHECK(test == "filename___"); + + // redundant (overlong) 4-byte sequence + // ascii code 0x2e encoded with three leading 0s + test = "filename\xf0\x80\x80\xae"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s\n", test.c_str()); + TEST_CHECK(test == "filename____"); + std::string root_dir = parent_path(current_working_directory()); for (int i = 0; i < sizeof(test_torrents)/sizeof(test_torrents[0]); ++i) { @@ -417,6 +436,21 @@ int test_main() { TEST_EQUAL(ti->name(), "foobar"); } + else if (std::string(test_torrents[i].file) == "slash_path.torrent") + { + TEST_EQUAL(ti->num_files(), 1); + TEST_EQUAL(ti->file_at(0).path, "temp/bar"); + } + else if (std::string(test_torrents[i].file) == "slash_path2.torrent") + { + TEST_EQUAL(ti->num_files(), 1); + TEST_EQUAL(ti->file_at(0).path, "temp/abc....def/bar"); + } + else if (std::string(test_torrents[i].file) == "slash_path3.torrent") + { + TEST_EQUAL(ti->num_files(), 1); + TEST_EQUAL(ti->file_at(0).path, "temp....abc"); + } file_storage const& fs = ti->files(); for (int i = 0; i < fs.num_files(); ++i) diff --git a/test/test_torrents/slash_path2.torrent b/test/test_torrents/slash_path2.torrent new file mode 100644 index 000000000..4a8e6f1e0 --- /dev/null +++ b/test/test_torrents/slash_path2.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl13:abc/../../def1:/3:bareee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee diff --git a/test/test_torrents/slash_path3.torrent b/test/test_torrents/slash_path3.torrent new file mode 100644 index 000000000..f41372506 --- /dev/null +++ b/test/test_torrents/slash_path3.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod6:lengthi12432e4:name14:temp/../../abc12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee