mirror of
https://github.com/transmission/transmission
synced 2025-03-04 02:28:03 +00:00
build: remove explicit iconv dependency in libtransmission (#4565)
This commit is contained in:
parent
72b6ae0378
commit
8b1290c895
7 changed files with 23 additions and 132 deletions
|
@ -206,12 +206,6 @@ if(NOT TARGET CURL::libcurl)
|
|||
target_include_directories(CURL::libcurl INTERFACE ${CURL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
find_package(Iconv)
|
||||
else()
|
||||
set(Iconv_FOUND OFF)
|
||||
endif()
|
||||
|
||||
set(CRYPTO_PKG "")
|
||||
if(WITH_CRYPTO STREQUAL "AUTO" OR WITH_CRYPTO STREQUAL "ccrypto")
|
||||
tr_get_required_flag(WITH_CRYPTO CCRYPTO_IS_REQUIRED)
|
||||
|
|
|
@ -3728,7 +3728,6 @@
|
|||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||
"-DHAVE_FLOCK",
|
||||
"-DHAVE_STRLCPY",
|
||||
"-DHAVE_ICONV",
|
||||
);
|
||||
PRODUCT_NAME = transmission;
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
|
@ -3973,7 +3972,6 @@
|
|||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||
"-DHAVE_FLOCK",
|
||||
"-DHAVE_STRLCPY",
|
||||
"-DHAVE_ICONV",
|
||||
);
|
||||
PRODUCT_NAME = transmission;
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
|
@ -4290,7 +4288,6 @@
|
|||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||
"-DHAVE_FLOCK",
|
||||
"-DHAVE_STRLCPY",
|
||||
"-DHAVE_ICONV",
|
||||
);
|
||||
PRODUCT_NAME = transmission;
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
|
|
|
@ -220,7 +220,6 @@ target_compile_definitions(${TR_NAME}
|
|||
$<$<VERSION_LESS:${MINIUPNPC_VERSION},1.7>:MINIUPNPC_API_VERSION=${MINIUPNPC_API_VERSION}> # API version macro was only added in 1.7
|
||||
$<$<BOOL:${USE_SYSTEM_B64}>:USE_SYSTEM_B64>
|
||||
$<$<BOOL:${HAVE_SO_REUSEPORT}>:HAVE_SO_REUSEPORT=1>
|
||||
$<$<BOOL:${Iconv_FOUND}>:HAVE_ICONV>
|
||||
PUBLIC
|
||||
$<$<NOT:$<BOOL:${ENABLE_NLS}>>:DISABLE_GETTEXT>)
|
||||
|
||||
|
@ -285,7 +284,6 @@ target_link_libraries(${TR_NAME}
|
|||
utf8::cpp
|
||||
wildmat
|
||||
WideInteger::WideInteger
|
||||
$<$<BOOL:${ICONV_FOUND}>:Iconv::Iconv>
|
||||
$<$<BOOL:${WIN32}>:crypt32>
|
||||
$<$<BOOL:${WIN32}>:shlwapi>
|
||||
"$<$<BOOL:${APPLE}>:-framework Foundation>"
|
||||
|
|
|
@ -321,11 +321,11 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
}
|
||||
else if (pathIs(CommentKey) || pathIs(CommentUtf8Key))
|
||||
{
|
||||
tm_.comment_ = tr_strvUtf8Clean(value);
|
||||
tm_.comment_ = tr_strv_replace_invalid(value);
|
||||
}
|
||||
else if (pathIs(CreatedByKey) || pathIs(CreatedByUtf8Key))
|
||||
{
|
||||
tm_.creator_ = tr_strvUtf8Clean(value);
|
||||
tm_.creator_ = tr_strv_replace_invalid(value);
|
||||
}
|
||||
else if (pathIs(SourceKey) || pathIs(InfoKey, SourceKey) || pathIs(PublisherKey) || pathIs(InfoKey, PublisherKey))
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
// to have the same use as the 'source' key
|
||||
// http://wiki.bitcomet.com/inside_bitcomet
|
||||
|
||||
tm_.source_ = tr_strvUtf8Clean(value);
|
||||
tm_.source_ = tr_strv_replace_invalid(value);
|
||||
}
|
||||
else if (pathIs(AnnounceKey))
|
||||
{
|
||||
|
@ -349,7 +349,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
}
|
||||
else if (pathIs(InfoKey, NameKey) || pathIs(InfoKey, NameUtf8Key))
|
||||
{
|
||||
tm_.name_ = tr_strvUtf8Clean(value);
|
||||
tm_.name_ = tr_strv_replace_invalid(value);
|
||||
}
|
||||
else if (pathIs(InfoKey, PiecesKey))
|
||||
{
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -33,10 +32,6 @@
|
|||
#include <sys/stat.h> // mode_t
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICONV
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#define UTF_CPP_CPLUSPLUS 201703L
|
||||
#include <utf8.h>
|
||||
|
||||
|
@ -303,106 +298,13 @@ double tr_getRatio(uint64_t numerator, uint64_t denominator)
|
|||
****
|
||||
***/
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace tr_strvUtf8Clean_impl
|
||||
{
|
||||
|
||||
template<std::size_t N, typename F>
|
||||
struct ArgTypeImpl;
|
||||
|
||||
template<std::size_t N, typename R, typename... ArgTs>
|
||||
struct ArgTypeImpl<N, R (*)(ArgTs...)> : std::tuple_element<1, std::tuple<ArgTs...>>
|
||||
{
|
||||
};
|
||||
|
||||
template<std::size_t N, typename F>
|
||||
using ArgType = typename ArgTypeImpl<N, F>::type;
|
||||
|
||||
bool validateUtf8(std::string_view sv, char const** good_end)
|
||||
{
|
||||
auto const* begin = std::data(sv);
|
||||
auto const* const end = begin + std::size(sv);
|
||||
auto const* walk = begin;
|
||||
auto all_good = false;
|
||||
|
||||
try
|
||||
{
|
||||
while (walk < end)
|
||||
{
|
||||
utf8::next(walk, end);
|
||||
}
|
||||
|
||||
all_good = true;
|
||||
}
|
||||
catch (utf8::exception const&)
|
||||
{
|
||||
all_good = false;
|
||||
}
|
||||
|
||||
if (good_end != nullptr)
|
||||
{
|
||||
*good_end = walk;
|
||||
}
|
||||
|
||||
return all_good;
|
||||
}
|
||||
|
||||
std::string strip_non_utf8(std::string_view sv)
|
||||
std::string tr_strv_replace_invalid(std::string_view sv, uint32_t replacement)
|
||||
{
|
||||
auto out = std::string{};
|
||||
utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), '?');
|
||||
utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), replacement);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string to_utf8(std::string_view sv)
|
||||
{
|
||||
#ifdef HAVE_ICONV
|
||||
size_t const buflen = std::size(sv) * 4 + 10;
|
||||
auto buf = std::vector<char>{};
|
||||
buf.resize(buflen);
|
||||
|
||||
auto constexpr Encodings = std::array<char const*, 2>{ "CURRENT", "ISO-8859-15" };
|
||||
for (auto const* test_encoding : Encodings)
|
||||
{
|
||||
iconv_t cd = iconv_open("UTF-8", test_encoding);
|
||||
if (cd == (iconv_t)-1) // NOLINT(performance-no-int-to-ptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const* inbuf = std::data(sv);
|
||||
size_t inbytesleft = std::size(sv);
|
||||
char* out = std::data(buf);
|
||||
size_t outbytesleft = std::size(buf);
|
||||
auto const rv = iconv(cd, const_cast<ArgType<1, decltype(&iconv)>>(&inbuf), &inbytesleft, &out, &outbytesleft);
|
||||
iconv_close(cd);
|
||||
if (rv != size_t(-1))
|
||||
{
|
||||
return std::string{ std::data(buf), buflen - outbytesleft };
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return strip_non_utf8(sv);
|
||||
}
|
||||
|
||||
} // namespace tr_strvUtf8Clean_impl
|
||||
} // namespace
|
||||
|
||||
std::string tr_strvUtf8Clean(std::string_view cleanme)
|
||||
{
|
||||
using namespace tr_strvUtf8Clean_impl;
|
||||
|
||||
if (validateUtf8(cleanme, nullptr))
|
||||
{
|
||||
return std::string{ cleanme };
|
||||
}
|
||||
|
||||
return to_utf8(cleanme);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::string tr_win32_native_to_utf8(std::wstring_view in)
|
||||
|
|
|
@ -204,7 +204,7 @@ constexpr bool tr_strvSep(std::string_view* sv, std::string_view* token, char de
|
|||
|
||||
[[nodiscard]] std::string_view tr_strvStrip(std::string_view str);
|
||||
|
||||
[[nodiscard]] std::string tr_strvUtf8Clean(std::string_view cleanme);
|
||||
[[nodiscard]] std::string tr_strv_replace_invalid(std::string_view cleanme, uint32_t replacement = 0xFFFD /*<2A>*/);
|
||||
|
||||
/**
|
||||
* @brief copies `src` into `buf`.
|
||||
|
|
|
@ -113,53 +113,53 @@ TEST_F(UtilsTest, trStrvStrip)
|
|||
EXPECT_EQ("test"sv, tr_strvStrip("test"sv));
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, trStrvUtf8Clean)
|
||||
TEST_F(UtilsTest, strvReplaceInvalid)
|
||||
{
|
||||
auto in = "hello world"sv;
|
||||
auto out = tr_strvUtf8Clean(in);
|
||||
auto out = tr_strv_replace_invalid(in);
|
||||
EXPECT_EQ(in, out);
|
||||
|
||||
in = "hello world"sv;
|
||||
out = tr_strvUtf8Clean(in.substr(0, 5));
|
||||
out = tr_strv_replace_invalid(in.substr(0, 5));
|
||||
EXPECT_EQ("hello"sv, out);
|
||||
|
||||
// this version is not utf-8 (but cp866)
|
||||
in = "\x92\xE0\xE3\xA4\xAD\xAE \xA1\xEB\xE2\xEC \x81\xAE\xA3\xAE\xAC"sv;
|
||||
out = tr_strvUtf8Clean(in);
|
||||
EXPECT_TRUE(std::size(out) == 17 || std::size(out) == 33);
|
||||
EXPECT_EQ(out, tr_strvUtf8Clean(out));
|
||||
out = tr_strv_replace_invalid(in, '?');
|
||||
EXPECT_EQ(17U, std::size(out));
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
|
||||
// same string, but utf-8 clean
|
||||
in = "Трудно быть Богом"sv;
|
||||
out = tr_strvUtf8Clean(in);
|
||||
out = tr_strv_replace_invalid(in);
|
||||
EXPECT_NE(0U, std::size(out));
|
||||
EXPECT_EQ(out, tr_strvUtf8Clean(out));
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
EXPECT_EQ(in, out);
|
||||
|
||||
// https://trac.transmissionbt.com/ticket/6064
|
||||
// This was a fuzzer-generated string that crashed Transmission.
|
||||
// Even invalid strings shouldn't cause a crash.
|
||||
in = "\xF4\x00\x81\x82"sv;
|
||||
out = tr_strvUtf8Clean(in);
|
||||
out = tr_strv_replace_invalid(in);
|
||||
EXPECT_NE(0U, std::size(out));
|
||||
EXPECT_EQ(out, tr_strvUtf8Clean(out));
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
|
||||
in = "\xF4\x33\x81\x82"sv;
|
||||
out = tr_strvUtf8Clean(in);
|
||||
out = tr_strv_replace_invalid(in, '?');
|
||||
EXPECT_NE(nullptr, out.data());
|
||||
EXPECT_TRUE(out.size() == 4 || out.size() == 7);
|
||||
EXPECT_EQ(out, tr_strvUtf8Clean(out));
|
||||
EXPECT_EQ(4U, std::size(out));
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, trStrvUtf8CleanFuzz)
|
||||
TEST_F(UtilsTest, strvReplaceInvalidFuzz)
|
||||
{
|
||||
auto buf = std::vector<char>{};
|
||||
for (size_t i = 0; i < 1000; ++i)
|
||||
{
|
||||
buf.resize(tr_rand_int(4096U));
|
||||
tr_rand_buffer(std::data(buf), std::size(buf));
|
||||
auto const out = tr_strvUtf8Clean({ std::data(buf), std::size(buf) });
|
||||
EXPECT_EQ(out, tr_strvUtf8Clean(out));
|
||||
auto const out = tr_strv_replace_invalid({ std::data(buf), std::size(buf) });
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue