From 33fc3af775ca35ae343a4e50de36e8853cabb86d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 23 Feb 2014 19:27:08 +0100 Subject: SongSort, ...: use libicu instead of GLib's g_utf8_*() --- src/lib/icu/Collate.cxx | 170 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/icu/Collate.hxx | 44 +++++++++++++ src/lib/icu/Error.cxx | 24 +++++++ src/lib/icu/Error.hxx | 29 +++++++++ 4 files changed, 267 insertions(+) create mode 100644 src/lib/icu/Collate.cxx create mode 100644 src/lib/icu/Collate.hxx create mode 100644 src/lib/icu/Error.cxx create mode 100644 src/lib/icu/Error.hxx (limited to 'src/lib/icu') diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx new file mode 100644 index 000000000..8dd757fb0 --- /dev/null +++ b/src/lib/icu/Collate.cxx @@ -0,0 +1,170 @@ +/* + * 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/Error.hxx" +#include "util/Domain.hxx" + +#include +#include +#elif defined(HAVE_GLIB) +#include +#else +#include +#include +#endif + +#include +#include + +#ifdef HAVE_ICU +static UCollator *collator; +#endif + +bool +IcuCollateInit(Error &error) +{ +#ifdef HAVE_ICU + assert(collator == nullptr); + assert(!error.IsDefined()); + + UErrorCode code; + collator = ucol_open("", &code); + if (collator == nullptr) { + error.Format(icu_domain, int(code), + "ucol_open() failed: %s", u_errorName(code)); + return false; + } +#else + (void)error; +#endif + + return true; +} + +void +IcuCollateFinish() +{ +#ifdef HAVE_ICU + assert(collator != nullptr); + + ucol_close(collator); +#endif +} + +#ifdef HAVE_ICU + +static UChar * +UCharFromUTF8(const char *src, int32_t *dest_length) +{ + assert(src != nullptr); + + const size_t src_length = strlen(src); + size_t dest_capacity = src_length + 1; + UChar *dest = new UChar[dest_capacity]; + + UErrorCode error_code; + u_strFromUTF8(dest, dest_capacity, + dest_length, + src, src_length, + &error_code); + if (U_FAILURE(error_code)) { + delete[] dest; + return nullptr; + } + + return dest; +} + +#endif + +gcc_pure +int +IcuCollate(const char *a, const char *b) +{ + assert(a != nullptr); + assert(b != nullptr); + +#ifdef HAVE_ICU + assert(collator != nullptr); + +#if U_ICU_VERSION_MAJOR_NUM >= 50 + return (int)ucol_strcollUTF8(collator, a, -1, b, -1, nullptr); +#else + /* fall back to ucol_strcoll() */ + + UChar *au = UCharFromUTF8(a, nullptr); + UChar *bu = UCharFromUTF8(b, nullptr); + + int result = au != nullptr && bu != nullptr + ? (int)ucol_strcoll(collator, au, -1, bu, -1) + : strcasecmp(a, b); + + delete[] au; + delete[] bu; + + 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); + assert(src != nullptr); + + int32_t u_length; + UChar *u = UCharFromUTF8(src, &u_length); + if (u == nullptr) + return std::string(src); + + size_t dest_length = ucol_getSortKey(collator, u, u_length, + nullptr, 0); + if (dest_length == 0) { + delete[] u; + return std::string(src); + } + + uint8_t *dest = new uint8_t[dest_length]; + ucol_getSortKey(collator, u, u_length, + dest, dest_length); + std::string result((const char *)dest); + delete[] dest; +#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 + +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 -- cgit v1.2.3