diff --git a/Makefile.am b/Makefile.am index 544fddeb6..fa121a8fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -518,6 +518,7 @@ libevent_a_SOURCES = \ # UTF-8 library libicu_a_SOURCES = \ + src/lib/icu/CaseFold.cxx src/lib/icu/CaseFold.hxx \ src/lib/icu/Collate.cxx src/lib/icu/Collate.hxx \ src/lib/icu/Converter.cxx src/lib/icu/Converter.hxx diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index ed556ede0..c761550aa 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -27,7 +27,7 @@ #include "util/ASCII.hxx" #include "util/TimeParser.hxx" #include "util/UriUtil.hxx" -#include "lib/icu/Collate.hxx" +#include "lib/icu/CaseFold.hxx" #include diff --git a/src/lib/icu/CaseFold.cxx b/src/lib/icu/CaseFold.cxx new file mode 100644 index 000000000..ed4552d1c --- /dev/null +++ b/src/lib/icu/CaseFold.cxx @@ -0,0 +1,111 @@ +/* + * Copyright 2003-2017 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "CaseFold.hxx" +#include "util/AllocatedString.hxx" + +#ifdef HAVE_ICU +#include "Util.hxx" +#include "util/AllocatedArray.hxx" +#include "util/ConstBuffer.hxx" + +#include +#include +#else +#include +#include +#endif + +#ifdef WIN32 +#include "Win32.hxx" +#include +#endif + +#include +#include + +#include +#include + +AllocatedString<> +IcuCaseFold(const char *src) +try { +#ifdef HAVE_ICU +#if !CLANG_CHECK_VERSION(3,6) + /* disabled on clang due to -Wtautological-pointer-compare */ + assert(src != nullptr); +#endif + + const auto u = UCharFromUTF8(src); + if (u.IsNull()) + return AllocatedString<>::Duplicate(src); + + AllocatedArray folded(u.size() * 2u); + + UErrorCode error_code = U_ZERO_ERROR; + size_t folded_length = u_strFoldCase(folded.begin(), folded.size(), + u.begin(), u.size(), + U_FOLD_CASE_DEFAULT, + &error_code); + if (folded_length == 0 || error_code != U_ZERO_ERROR) + return AllocatedString<>::Duplicate(src); + + folded.SetSize(folded_length); + return UCharToUTF8({folded.begin(), folded.size()}); + +#elif defined(WIN32) + const auto u = MultiByteToWideChar(CP_UTF8, src); + + const int size = LCMapStringEx(LOCALE_NAME_INVARIANT, + LCMAP_SORTKEY|LINGUISTIC_IGNORECASE, + u.c_str(), -1, nullptr, 0, + nullptr, nullptr, 0); + if (size <= 0) + return AllocatedString<>::Duplicate(src); + + std::unique_ptr buffer(new wchar_t[size]); + if (LCMapStringEx(LOCALE_NAME_INVARIANT, + LCMAP_SORTKEY|LINGUISTIC_IGNORECASE, + u.c_str(), -1, buffer.get(), size, + nullptr, nullptr, 0) <= 0) + return AllocatedString<>::Duplicate(src); + + return WideCharToMultiByte(CP_UTF8, buffer.get()); + +#else + size_t size = strlen(src) + 1; + std::unique_ptr buffer(new char[size]); + size_t nbytes = strxfrm(buffer.get(), src, size); + if (nbytes >= size) { + /* buffer too small - reallocate and try again */ + buffer.reset(); + size = nbytes + 1; + buffer.reset(new char[size]); + nbytes = strxfrm(buffer.get(), src, size); + } + + assert(nbytes < size); + assert(buffer[nbytes] == 0); + + return AllocatedString<>::Donate(buffer.release()); +#endif +} catch (const std::runtime_error &) { + return AllocatedString<>::Duplicate(src); +} diff --git a/src/lib/icu/CaseFold.hxx b/src/lib/icu/CaseFold.hxx new file mode 100644 index 000000000..7d13a6e2a --- /dev/null +++ b/src/lib/icu/CaseFold.hxx @@ -0,0 +1,32 @@ +/* + * Copyright 2003-2017 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_ICU_CASE_FOLD_HXX +#define MPD_ICU_CASE_FOLD_HXX + +#include "check.h" +#include "Compiler.h" + +template class AllocatedString; + +gcc_nonnull_all +AllocatedString +IcuCaseFold(const char *src); + +#endif diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx index 9238e74b0..f16cba597 100644 --- a/src/lib/icu/Collate.cxx +++ b/src/lib/icu/Collate.cxx @@ -23,8 +23,6 @@ #ifdef HAVE_ICU #include "Util.hxx" -#include "util/AllocatedArray.hxx" -#include "util/ConstBuffer.hxx" #include "util/RuntimeError.hxx" #include @@ -141,69 +139,3 @@ IcuCollate(const char *a, const char *b) noexcept return strcoll(a, b); #endif } - -AllocatedString<> -IcuCaseFold(const char *src) -try { -#ifdef HAVE_ICU -#if !CLANG_CHECK_VERSION(3,6) - /* disabled on clang due to -Wtautological-pointer-compare */ - assert(src != nullptr); -#endif - - const auto u = UCharFromUTF8(src); - if (u.IsNull()) - return AllocatedString<>::Duplicate(src); - - AllocatedArray folded(u.size() * 2u); - - UErrorCode error_code = U_ZERO_ERROR; - size_t folded_length = u_strFoldCase(folded.begin(), folded.size(), - u.begin(), u.size(), - U_FOLD_CASE_DEFAULT, - &error_code); - if (folded_length == 0 || error_code != U_ZERO_ERROR) - return AllocatedString<>::Duplicate(src); - - folded.SetSize(folded_length); - return UCharToUTF8({folded.begin(), folded.size()}); - -#elif defined(WIN32) - const auto u = MultiByteToWideChar(CP_UTF8, src); - - const int size = LCMapStringEx(LOCALE_NAME_INVARIANT, - LCMAP_SORTKEY|LINGUISTIC_IGNORECASE, - u.c_str(), -1, nullptr, 0, - nullptr, nullptr, 0); - if (size <= 0) - return AllocatedString<>::Duplicate(src); - - std::unique_ptr buffer(new wchar_t[size]); - if (LCMapStringEx(LOCALE_NAME_INVARIANT, - LCMAP_SORTKEY|LINGUISTIC_IGNORECASE, - u.c_str(), -1, buffer.get(), size, - nullptr, nullptr, 0) <= 0) - return AllocatedString<>::Duplicate(src); - - return WideCharToMultiByte(CP_UTF8, buffer.get()); - -#else - size_t size = strlen(src) + 1; - std::unique_ptr buffer(new char[size]); - size_t nbytes = strxfrm(buffer.get(), src, size); - if (nbytes >= size) { - /* buffer too small - reallocate and try again */ - buffer.reset(); - size = nbytes + 1; - buffer.reset(new char[size]); - nbytes = strxfrm(buffer.get(), src, size); - } - - assert(nbytes < size); - assert(buffer[nbytes] == 0); - - return AllocatedString<>::Donate(buffer.release()); -#endif -} catch (const std::runtime_error &) { - return AllocatedString<>::Duplicate(src); -} diff --git a/src/lib/icu/Collate.hxx b/src/lib/icu/Collate.hxx index d6cfcb764..d22fa6870 100644 --- a/src/lib/icu/Collate.hxx +++ b/src/lib/icu/Collate.hxx @@ -23,8 +23,6 @@ #include "check.h" #include "Compiler.h" -template class AllocatedString; - /** * Throws #std::runtime_error on error. */ @@ -38,8 +36,4 @@ gcc_pure gcc_nonnull_all int IcuCollate(const char *a, const char *b) noexcept; -gcc_nonnull_all -AllocatedString -IcuCaseFold(const char *src); - #endif