merged changes from RC_1_0

This commit is contained in:
Arvid Norberg 2014-11-17 03:41:01 +00:00
parent 0b711f1280
commit edfa38cd30
13 changed files with 316 additions and 117 deletions

View File

@ -173,6 +173,8 @@ if (build_tests)
add_definitions(-DTORRENT_EXPORT_EXTRA) add_definitions(-DTORRENT_EXPORT_EXTRA)
endif (build_tests) endif (build_tests)
include_directories(${includes})
if (encryption) if (encryption)
list(APPEND sources pe_crypto asio_ssl) list(APPEND sources pe_crypto asio_ssl)
if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES) if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES)
@ -313,8 +315,6 @@ if (tcmalloc)
target_link_libraries(torrent-rasterbar tcmalloc) target_link_libraries(torrent-rasterbar tcmalloc)
endif() endif()
include_directories(${includes})
set_target_properties(torrent-rasterbar PROPERTIES set_target_properties(torrent-rasterbar PROPERTIES
SOVERSION ${SOVERSION}) SOVERSION ${SOVERSION})
@ -326,9 +326,7 @@ foreach (s ${COMPILETIME_OPTIONS_LIST})
set (COMPILETIME_OPTIONS "${COMPILETIME_OPTIONS} -D${s}") set (COMPILETIME_OPTIONS "${COMPILETIME_OPTIONS} -D${s}")
endforeach (s) endforeach (s)
if (MSVC) configure_file(libtorrent-rasterbar-cmake.pc.in libtorrent-rasterbar.pc)
configure_file(libtorrent-rasterbar-cmake.pc.in libtorrent-rasterbar.pc)
endif()
string (COMPARE EQUAL "${CMAKE_SIZEOF_VOID_P}" "8" IS64BITS) 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 === # === build examples ===
if(build_examples) if(build_examples)
FILE(GLOB examples RELATIVE "${PROJECT_SOURCE_DIR}" "examples/*.cpp") # this will make some internal functions available in the
foreach(s ${examples}) # DLL interface, for the examples to access
get_filename_component (sn ${s} NAME_WE) add_definitions(-DTORRENT_EXPORT_EXTRA)
add_executable(${sn} ${s})
target_link_libraries(${sn} torrent-rasterbar)
endforeach(s)
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() endif()
# === build tests === # === build tests ===

View File

@ -35,6 +35,7 @@
1.0.3 release 1.0.3 release
* handle overlong utf-8 sequences
* fix link order bug in makefile for python binding * fix link order bug in makefile for python binding
* fix bug in interest calculation, causing premature disconnects * fix bug in interest calculation, causing premature disconnects
* tweak flag_override_resume_data semantics to make more sense (breaks * tweak flag_override_resume_data semantics to make more sense (breaks

29
examples/CMakeLists.txt Normal file
View File

@ -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)

View File

@ -13,7 +13,7 @@ bin_PROGRAMS = $(example_programs)
endif endif
EXTRA_PROGRAMS = $(example_programs) 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_SOURCES = client_test.cpp print.cpp session_view.cpp torrent_view.cpp
#client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la #client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la

View File

@ -242,6 +242,41 @@ int load_file(std::string const& filename, std::vector<char>& v
return 0; 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) bool is_hex(char const *in, int len)
{ {
for (char const* end = in + len; in < end; ++in) 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; if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
lazy_entry resume_data; lazy_entry resume_data;
// TODO: implement combine_path in here, since it's internal to libtorrent std::string filename = path_append(save_path, path_append(".resume"
std::string filename = combine_path(save_path, combine_path(".resume"
, libtorrent::filename(torrent) + ".resume")); , libtorrent::filename(torrent) + ".resume"));
error_code ec; error_code ec;
@ -595,6 +629,67 @@ void add_torrent(libtorrent::session& ses
files.insert(std::pair<const std::string, torrent_handle>(torrent, torrent_handle())); files.insert(std::pair<const std::string, torrent_handle>(torrent, torrent_handle()));
} }
std::vector<std::string> list_dir(std::string path
, bool (*filter_fun)(std::string const&))
{
std::vector<std::string> 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 void scan_dir(std::string const& dir_path
, libtorrent::session& ses , libtorrent::session& ses
, handles_t& files , handles_t& files
@ -609,20 +704,12 @@ void scan_dir(std::string const& dir_path
using namespace libtorrent; using namespace libtorrent;
error_code ec; error_code ec;
std::vector<std::pair<boost::uint64_t, std::string> > ents; std::vector<std::string> ents = list_dir(dir_path, filter_fun);
// 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::sort(ents.begin(), ents.end()); for (std::vector<std::string>::iterator i = ents.begin()
for (std::vector<std::pair<boost::uint64_t, std::string> >::iterator i = ents.begin()
, end(ents.end()); i != end; ++i) , 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); handles_t::iterator k = files.find(file);
if (k != files.end()) if (k != files.end())
@ -737,7 +824,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
torrent_handle h = p->handle; torrent_handle h = p->handle;
error_code ec; error_code ec;
file_status st; 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 cert = base_name + ".pem";
std::string priv = base_name + "_key.pem"; std::string priv = base_name + "_key.pem";
stat_file(cert, &st, ec); stat_file(cert, &st, ec);
@ -781,7 +868,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
bencode(std::back_inserter(buffer), te); bencode(std::back_inserter(buffer), te);
sha1_hash hash = ti->info_hash(); sha1_hash hash = ti->info_hash();
std::string filename = ti->name() + "." + to_hex(hash.to_string()) + ".torrent"; 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); save_file(filename, buffer);
files.insert(std::pair<std::string, libtorrent::torrent_handle>(filename, h)); files.insert(std::pair<std::string, libtorrent::torrent_handle>(filename, h));
@ -871,7 +958,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
std::vector<char> out; std::vector<char> out;
bencode(std::back_inserter(out), *p->resume_data); bencode(std::back_inserter(out), *p->resume_data);
torrent_status st = h.status(torrent_handle::query_save_path); 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); hash_to_filename[st.info_hash]) + ".resume")), out);
if (h.is_valid() if (h.is_valid()
&& non_files.find(h) == non_files.end() && non_files.find(h) == non_files.end()
@ -1321,10 +1408,10 @@ int main(int argc, char* argv[])
} }
// create directory for resume files // create directory for resume files
// TODO: don't use internal create_directory function int ret = mkdir(path_append(save_path, ".resume").c_str(), 0777);
create_directory(combine_path(save_path, ".resume"), ec); if (ret < 0)
if (ec) fprintf(stderr, "failed to create resume file directory: (%d) %s\n"
fprintf(stderr, "failed to create resume file directory: %s\n", ec.message().c_str()); , errno, strerror(errno));
if (bind_to_interface.empty()) bind_to_interface = "0.0.0.0"; 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); 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; 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")); , to_hex(tmp.info_hash.to_string()) + ".resume"));
load_file(filename.c_str(), p.resume_data, ec); load_file(filename.c_str(), p.resume_data, ec);
@ -1522,7 +1609,7 @@ int main(int argc, char* argv[])
if (ec) continue; 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")); , to_hex(tmp.info_hash.to_string()) + ".resume"));
load_file(filename.c_str(), p.resume_data, ec); load_file(filename.c_str(), p.resume_data, ec);
@ -1550,10 +1637,10 @@ int main(int argc, char* argv[])
{ {
error_code ec; error_code ec;
std::string path; std::string path;
if (is_complete(i->first)) path = i->first; if (is_absolute_path(i->first)) path = i->first;
else path = combine_path(monitor_dir, i->first); else path = path_append(monitor_dir, i->first);
remove(path, ec); if (::remove(path.c_str()) < 0)
if (ec) printf("failed to delete .torrent file: %s\n", ec.message().c_str()); printf("failed to delete .torrent file: %s\n", ec.message().c_str());
files.erase(i); files.erase(i);
} }
if (st.handle.is_valid()) 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); torrent_status st = h.status(torrent_handle::query_save_path);
std::vector<char> out; std::vector<char> out;
bencode(std::back_inserter(out), *rd->resume_data); bencode(std::back_inserter(out), *rd->resume_data);
save_file(combine_path(st.save_path, combine_path(".resume", libtorrent::filename( save_file(path_append(st.save_path, path_append(".resume"
hash_to_filename[st.info_hash]) + ".resume")), out); , libtorrent::filename(hash_to_filename[st.info_hash]) + ".resume")), out);
} }
} }

View File

@ -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)

View File

@ -320,7 +320,13 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_USE_READV 0 #define TORRENT_USE_READV 0
#else #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 #define TORRENT_BSD
#endif #endif
@ -359,7 +365,12 @@ POSSIBILITY OF SUCH DAMAGE.
// this is the maximum number of characters in a // this is the maximum number of characters in a
// path element / filename on windows // path element / filename on windows
#define TORRENT_MAX_PATH 255 #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 #endif

View File

@ -643,7 +643,13 @@ namespace libtorrent
} }
#else #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 // make a best guess of the interface we're using and its IP
udp::resolver r(ios); udp::resolver r(ios);
udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec); udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec);

View File

@ -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); BOOST_STATIC_ASSERT((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0);
#endif #endif
#ifdef TORRENT_WINDOWS #if defined TORRENT_WINDOWS && defined UNICODE && !TORRENT_USE_WSTRING
#if defined UNICODE && !TORRENT_USE_WSTRING
#warning wide character support not available. Files will be saved using narrow string names #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
#endif // TORRENT_WINDOWS #endif // TORRENT_WINDOWS
namespace libtorrent namespace libtorrent

View File

@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <iterator> #include <iterator>
#include <algorithm> #include <algorithm>
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/ConvertUTF.h"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/escape_string.hpp" // is_space #include "libtorrent/escape_string.hpp" // is_space
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
@ -95,85 +96,65 @@ namespace libtorrent
std::string tmp_path; std::string tmp_path;
tmp_path.reserve(target.size()+5); tmp_path.reserve(target.size()+5);
bool valid_encoding = true; 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 UTF32 codepoint;
if ((*i & 0x80) == 0) 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 (cp == &codepoint)
if (!fix_paths || valid_path_character(*i))
{ {
tmp_path += *i; if (res == sourceExhausted)
} ptr = end;
else else
{ ++ptr;
tmp_path += '_';
codepoint = '_';
valid_encoding = false; valid_encoding = false;
} }
continue;
} }
else if ((res != conversionOK && res != targetExhausted)
if (end - i < 2) || 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; valid_encoding = false;
break;
} }
// valid 2-byte utf-8 character // if fix paths is true, also replace characters that are invalid
if ((i[0] & 0xe0) == 0xc0 // in filenames
&& (i[1] & 0xc0) == 0x80) if (fix_paths && codepoint < 0x7f && !valid_path_character(codepoint))
{ {
tmp_path += i[0]; codepoint = '_';
tmp_path += i[1];
i += 1;
continue;
}
if (end - i < 3)
{
tmp_path += "_";
valid_encoding = false; valid_encoding = false;
break;
} }
// valid 3-byte utf-8 character // encode codepoint into utf-8
if ((i[0] & 0xf0) == 0xe0 cp = &codepoint;
&& (i[1] & 0xc0) == 0x80 UTF8 sequence[5];
&& (i[2] & 0xc0) == 0x80) UTF8* start = sequence;
{ res = ConvertUTF32toUTF8((const UTF32**)&cp, cp + 1, &start, start + 5, lenientConversion);
tmp_path += i[0]; TORRENT_ASSERT(res == conversionOK);
tmp_path += i[1];
tmp_path += i[2];
i += 2;
continue;
}
if (end - i < 4) for (int i = 0; i < start - sequence; ++i)
{ tmp_path += (char)sequence[i];
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;
} }
// the encoding was not valid utf-8 // the encoding was not valid utf-8
// save the original encoding and replace the // save the original encoding and replace the
// commonly used path with the correctly // commonly used path with the correctly
@ -1229,7 +1210,7 @@ namespace libtorrent
} }
m_multifile = true; m_multifile = true;
} }
files.set_name(name); TORRENT_ASSERT(!files.name().empty());
// extract sha-1 hashes for all pieces // extract sha-1 hashes for all pieces
// we want this division to round upwards, that's why we have the // we want this division to round upwards, that's why we have the

View File

@ -54,6 +54,8 @@ test_torrent_t test_torrents[] =
{ "hidden_parent_path.torrent" }, { "hidden_parent_path.torrent" },
{ "single_multi_file.torrent" }, { "single_multi_file.torrent" },
{ "slash_path.torrent" }, { "slash_path.torrent" },
{ "slash_path2.torrent" },
{ "slash_path3.torrent" },
{ "backslash_path.torrent" }, { "backslash_path.torrent" },
{ "url_list.torrent" }, { "url_list.torrent" },
{ "url_list2.torrent" }, { "url_list2.torrent" },
@ -259,11 +261,7 @@ int test_main()
bencode(std::back_inserter(buf), torrent); bencode(std::back_inserter(buf), torrent);
torrent_info ti2(&buf[0], buf.size(), ec); torrent_info ti2(&buf[0], buf.size(), ec);
std::cerr << ti2.name() << std::endl; std::cerr << ti2.name() << std::endl;
#ifdef TORRENT_WINDOWS TEST_EQUAL(ti2.name(), "test1test2test3");
TEST_CHECK(ti2.name() == "ctest1test2test3");
#else
TEST_CHECK(ti2.name() == "test1test2test3");
#endif
info["name.utf-8"] = "test2/../test3/.././../../test4"; info["name.utf-8"] = "test2/../test3/.././../../test4";
torrent["info"] = info; torrent["info"] = info;
@ -271,7 +269,7 @@ int test_main()
bencode(std::back_inserter(buf), torrent); bencode(std::back_inserter(buf), torrent);
torrent_info ti3(&buf[0], buf.size(), ec); torrent_info ti3(&buf[0], buf.size(), ec);
std::cerr << ti3.name() << std::endl; std::cerr << ti3.name() << std::endl;
TEST_CHECK(ti3.name() == "test2..test3.......test4"); TEST_EQUAL(ti3.name(), "test2..test3.......test4");
// verify_encoding // verify_encoding
std::string test = "\b?filename=4"; std::string test = "\b?filename=4";
@ -334,6 +332,27 @@ int test_main()
fprintf(stderr, "%s\n", test.c_str()); fprintf(stderr, "%s\n", test.c_str());
TEST_CHECK(test == "filename_____foobar"); 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()); std::string root_dir = parent_path(current_working_directory());
for (int i = 0; i < sizeof(test_torrents)/sizeof(test_torrents[0]); ++i) 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"); 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(); file_storage const& fs = ti->files();
for (int i = 0; i < fs.num_files(); ++i) for (int i = 0; i < fs.num_files(); ++i)

View File

@ -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

View File

@ -0,0 +1 @@
d10:created by10:libtorrent13:creation datei1359599503e4:infod6:lengthi12432e4:name14:temp/../../abc12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW}ÜA4u,·¼‡ee