diff --git a/configure.ac b/configure.ac index e154ac3a3..c044f53e8 100644 --- a/configure.ac +++ b/configure.ac @@ -472,6 +472,10 @@ fi MPD_DEFINE_CONDITIONAL(enable_icu, HAVE_ICU, [libicu]) +if test x$enable_icu != xyes; then + AC_CHECK_FUNCS(iconv) +fi + AC_ARG_ENABLE(glib, AS_HELP_STRING([--enable-glib], [enable GLib (default: auto)]),, diff --git a/src/CommandLine.cxx b/src/CommandLine.cxx index 7e3871f70..b59a39e40 100644 --- a/src/CommandLine.cxx +++ b/src/CommandLine.cxx @@ -215,6 +215,9 @@ static void version(void) #ifdef USE_EPOLL " epoll" #endif +#ifdef HAVE_ICONV + " iconv" +#endif #ifdef HAVE_ICU " icu" #endif diff --git a/src/fs/Charset.hxx b/src/fs/Charset.hxx index 9d119fea7..6ca5888e5 100644 --- a/src/fs/Charset.hxx +++ b/src/fs/Charset.hxx @@ -24,7 +24,7 @@ #include "Compiler.h" #include "Traits.hxx" -#if (defined(HAVE_ICU) || defined(HAVE_GLIB)) && !defined(WIN32) +#if (defined(HAVE_ICU) || defined(HAVE_ICONV) || defined(HAVE_GLIB)) && !defined(WIN32) #define HAVE_FS_CHARSET #endif diff --git a/src/lib/icu/Converter.cxx b/src/lib/icu/Converter.cxx index 8f20813c4..72028c82e 100644 --- a/src/lib/icu/Converter.cxx +++ b/src/lib/icu/Converter.cxx @@ -31,6 +31,9 @@ #ifdef HAVE_ICU #include "Util.hxx" #include +#elif defined(HAVE_ICONV) +#include "util/Domain.hxx" +static constexpr Domain iconv_domain("iconv"); #elif defined(HAVE_GLIB) #include "util/Domain.hxx" static constexpr Domain g_iconv_domain("g_iconv"); @@ -61,6 +64,20 @@ IcuConverter::Create(const char *charset, Error &error) } return new IcuConverter(converter); +#elif defined(HAVE_ICONV) + iconv_t to = iconv_open("utf-8", charset); + iconv_t from = iconv_open(charset, "utf-8"); + if (to == (iconv_t)-1 || from == (iconv_t)-1) { + error.FormatErrno("Failed to initialize charset '%s'", + charset); + if (to != (iconv_t)-1) + iconv_close(to); + if (from != (iconv_t)-1) + iconv_close(from); + return nullptr; + } + + return new IcuConverter(to, from); #elif defined(HAVE_GLIB) GIConv to = g_iconv_open("utf-8", charset); GIConv from = g_iconv_open(charset, "utf-8"); @@ -79,6 +96,26 @@ IcuConverter::Create(const char *charset, Error &error) } #ifdef HAVE_ICU +#elif defined(HAVE_ICONV) + +static AllocatedString +DoConvert(iconv_t conv, const char *src) +{ + // TODO: dynamic buffer? + char buffer[4096]; + char *in = const_cast(src); + char *out = buffer; + size_t in_left = strlen(src); + size_t out_left = sizeof(buffer); + + size_t n = iconv(conv, &in, &in_left, &out, &out_left); + + if (n == static_cast(-1) || in_left > 0) + return nullptr; + + return AllocatedString<>::Duplicate(buffer, sizeof(buffer) - out_left); +} + #elif defined(HAVE_GLIB) static AllocatedString @@ -123,7 +160,7 @@ IcuConverter::ToUTF8(const char *s) const const size_t target_length = target - buffer; return UCharToUTF8({buffer, target_length}); -#elif defined(HAVE_GLIB) +#elif defined(HAVE_ICONV) || defined(HAVE_GLIB) return DoConvert(to_utf8, s); #endif } @@ -155,7 +192,7 @@ IcuConverter::FromUTF8(const char *s) const return AllocatedString<>::Duplicate(buffer, target); -#elif defined(HAVE_GLIB) +#elif defined(HAVE_ICONV) || defined(HAVE_GLIB) return DoConvert(from_utf8, s); #endif } diff --git a/src/lib/icu/Converter.hxx b/src/lib/icu/Converter.hxx index fd5ea2132..d7a9a2113 100644 --- a/src/lib/icu/Converter.hxx +++ b/src/lib/icu/Converter.hxx @@ -26,6 +26,9 @@ #ifdef HAVE_ICU #include "thread/Mutex.hxx" #define HAVE_ICU_CONVERTER +#elif defined(HAVE_ICONV) +#include +#define HAVE_ICU_CONVERTER #elif defined(HAVE_GLIB) #include #define HAVE_ICU_CONVERTER @@ -56,6 +59,11 @@ class IcuConverter { UConverter *const converter; IcuConverter(UConverter *_converter):converter(_converter) {} +#elif defined(HAVE_ICONV) + const iconv_t to_utf8, from_utf8; + + IcuConverter(iconv_t _to, iconv_t _from) + :to_utf8(_to), from_utf8(_from) {} #elif defined(HAVE_GLIB) const GIConv to_utf8, from_utf8; @@ -66,6 +74,11 @@ class IcuConverter { public: #ifdef HAVE_ICU ~IcuConverter(); +#elif defined(HAVE_ICONV) + ~IcuConverter() { + iconv_close(to_utf8); + iconv_close(from_utf8); + } #elif defined(HAVE_GLIB) ~IcuConverter() { g_iconv_close(to_utf8);