diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/icu/Collate.cxx | 205 | ||||
-rw-r--r-- | src/lib/icu/Collate.hxx | 44 | ||||
-rw-r--r-- | src/lib/icu/Error.cxx | 24 | ||||
-rw-r--r-- | src/lib/icu/Error.hxx | 29 | ||||
-rw-r--r-- | src/lib/icu/Init.cxx | 48 | ||||
-rw-r--r-- | src/lib/icu/Init.hxx | 42 |
6 files changed, 392 insertions, 0 deletions
diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx new file mode 100644 index 000000000..17b536b37 --- /dev/null +++ b/src/lib/icu/Collate.cxx @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2003-2014 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 "Collate.hxx" + +#ifdef HAVE_ICU +#include "Error.hxx" +#include "util/WritableBuffer.hxx" +#include "util/ConstBuffer.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" + +#include <unicode/ucol.h> +#include <unicode/ustring.h> +#elif defined(HAVE_GLIB) +#include <glib.h> +#else +#include <algorithm> +#include <ctype.h> +#endif + +#include <assert.h> +#include <string.h> +#include <strings.h> + +#ifdef HAVE_ICU +static UCollator *collator; +#endif + +#ifdef HAVE_ICU + +bool +IcuCollateInit(Error &error) +{ + assert(collator == nullptr); + assert(!error.IsDefined()); + + UErrorCode code = U_ZERO_ERROR; + collator = ucol_open("", &code); + if (collator == nullptr) { + error.Format(icu_domain, int(code), + "ucol_open() failed: %s", u_errorName(code)); + return false; + } + + return true; +} + +void +IcuCollateFinish() +{ + assert(collator != nullptr); + + ucol_close(collator); +} + +static WritableBuffer<UChar> +UCharFromUTF8(const char *src) +{ + assert(src != nullptr); + + const size_t src_length = strlen(src); + const size_t dest_capacity = src_length; + UChar *dest = new UChar[dest_capacity]; + + UErrorCode error_code = U_ZERO_ERROR; + int32_t dest_length; + u_strFromUTF8(dest, dest_capacity, &dest_length, + src, src_length, + &error_code); + if (U_FAILURE(error_code)) { + delete[] dest; + return nullptr; + } + + return { dest, size_t(dest_length) }; +} + +static WritableBuffer<char> +UCharToUTF8(ConstBuffer<UChar> src) +{ + assert(!src.IsNull()); + + /* worst-case estimate */ + size_t dest_capacity = 4 * src.size; + + char *dest = new char[dest_capacity]; + + UErrorCode error_code = U_ZERO_ERROR; + int32_t dest_length; + u_strToUTF8(dest, dest_capacity, &dest_length, src.data, src.size, + &error_code); + if (U_FAILURE(error_code)) { + delete[] dest; + return nullptr; + } + + return { dest, size_t(dest_length) }; +} + +#endif + +gcc_pure +int +IcuCollate(const char *a, const char *b) +{ +#if !CLANG_CHECK_VERSION(3,6) + /* disabled on clang due to -Wtautological-pointer-compare */ + assert(a != nullptr); + assert(b != nullptr); +#endif + +#ifdef HAVE_ICU + assert(collator != nullptr); + +#if U_ICU_VERSION_MAJOR_NUM >= 50 + UErrorCode code = U_ZERO_ERROR; + return (int)ucol_strcollUTF8(collator, a, -1, b, -1, &code); +#else + /* fall back to ucol_strcoll() */ + + const auto au = UCharFromUTF8(a); + const auto bu = UCharFromUTF8(b); + + int result = !au.IsNull() && !bu.IsNull() + ? (int)ucol_strcoll(collator, au.data, au.size, + bu.data, bu.size) + : strcasecmp(a, b); + + delete[] au.data; + delete[] bu.data; + + return result; +#endif + +#elif defined(HAVE_GLIB) + return g_utf8_collate(a, b); +#else + return strcasecmp(a, b); +#endif +} + +std::string +IcuCaseFold(const char *src) +{ +#ifdef HAVE_ICU + assert(collator != nullptr); +#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 std::string(src); + + size_t folded_capacity = u.size * 2u; + UChar *folded = new UChar[folded_capacity]; + + UErrorCode error_code = U_ZERO_ERROR; + size_t folded_length = u_strFoldCase(folded, folded_capacity, + u.data, u.size, + U_FOLD_CASE_DEFAULT, + &error_code); + delete[] u.data; + if (folded_length == 0 || error_code != U_ZERO_ERROR) { + delete[] folded; + return std::string(src); + } + + auto result2 = UCharToUTF8({folded, folded_length}); + delete[] folded; + if (result2.IsNull()) + return std::string(src); + + std::string result(result2.data, result2.size); + delete[] result2.data; +#elif defined(HAVE_GLIB) + char *tmp = g_utf8_casefold(src, -1); + std::string result(tmp); + g_free(tmp); +#else + std::string result(src); + std::transform(result.begin(), result.end(), result.begin(), tolower); +#endif + return result; +} + diff --git a/src/lib/icu/Collate.hxx b/src/lib/icu/Collate.hxx new file mode 100644 index 000000000..8ae8de46a --- /dev/null +++ b/src/lib/icu/Collate.hxx @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2003-2014 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_COLLATE_HXX +#define MPD_ICU_COLLATE_HXX + +#include "check.h" +#include "Compiler.h" + +#include <string> + +class Error; + +bool +IcuCollateInit(Error &error); + +void +IcuCollateFinish(); + +gcc_pure gcc_nonnull_all +int +IcuCollate(const char *a, const char *b); + +gcc_pure gcc_nonnull_all +std::string +IcuCaseFold(const char *src); + +#endif diff --git a/src/lib/icu/Error.cxx b/src/lib/icu/Error.cxx new file mode 100644 index 000000000..1fef078ac --- /dev/null +++ b/src/lib/icu/Error.cxx @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2003-2014 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 "Error.hxx" +#include "util/Domain.hxx" + +const Domain icu_domain("icu"); diff --git a/src/lib/icu/Error.hxx b/src/lib/icu/Error.hxx new file mode 100644 index 000000000..e96667f57 --- /dev/null +++ b/src/lib/icu/Error.hxx @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2003-2014 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_ERROR_HXX +#define MPD_ICU_ERROR_HXX + +#include "check.h" + +class Domain; + +extern const Domain icu_domain; + +#endif diff --git a/src/lib/icu/Init.cxx b/src/lib/icu/Init.cxx new file mode 100644 index 000000000..1d0ad0777 --- /dev/null +++ b/src/lib/icu/Init.cxx @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003-2014 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 "Init.hxx" +#include "Error.hxx" +#include "Collate.hxx" +#include "util/Error.hxx" + +#include <unicode/uclean.h> + +bool +IcuInit(Error &error) +{ + UErrorCode code = U_ZERO_ERROR; + u_init(&code); + if (U_FAILURE(code)) { + error.Format(icu_domain, int(code), + "u_init() failed: %s", u_errorName(code)); + return false; + } + + return IcuCollateInit(error); +} + +void +IcuFinish() +{ + IcuCollateFinish(); + + u_cleanup(); +} diff --git a/src/lib/icu/Init.hxx b/src/lib/icu/Init.hxx new file mode 100644 index 000000000..9f585e2bd --- /dev/null +++ b/src/lib/icu/Init.hxx @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2003-2014 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_INIT_HXX +#define MPD_ICU_INIT_HXX + +#include "check.h" + +class Error; + +#ifdef HAVE_ICU + +bool +IcuInit(Error &error); + +void +IcuFinish(); + +#else + +static inline bool IcuInit(Error &) { return true; } +static inline void IcuFinish() {} + +#endif + +#endif |