aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/icu
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/icu')
-rw-r--r--src/lib/icu/Collate.cxx151
-rw-r--r--src/lib/icu/Collate.hxx5
-rw-r--r--src/lib/icu/Converter.cxx163
-rw-r--r--src/lib/icu/Converter.hxx97
-rw-r--r--src/lib/icu/Error.cxx2
-rw-r--r--src/lib/icu/Error.hxx2
-rw-r--r--src/lib/icu/Init.cxx2
-rw-r--r--src/lib/icu/Init.hxx2
-rw-r--r--src/lib/icu/Util.cxx74
-rw-r--r--src/lib/icu/Util.hxx45
-rw-r--r--src/lib/icu/Win32.cxx60
-rw-r--r--src/lib/icu/Win32.hxx38
12 files changed, 566 insertions, 75 deletions
diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx
index 17b536b37..dc8598a7a 100644
--- a/src/lib/icu/Collate.cxx
+++ b/src/lib/icu/Collate.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,8 +19,10 @@
#include "config.h"
#include "Collate.hxx"
+#include "util/AllocatedString.hxx"
#ifdef HAVE_ICU
+#include "Util.hxx"
#include "Error.hxx"
#include "util/WritableBuffer.hxx"
#include "util/ConstBuffer.hxx"
@@ -29,13 +31,17 @@
#include <unicode/ucol.h>
#include <unicode/ustring.h>
-#elif defined(HAVE_GLIB)
-#include <glib.h>
#else
#include <algorithm>
#include <ctype.h>
#endif
+#ifdef WIN32
+#include "Win32.hxx"
+#include "util/AllocatedString.hxx"
+#include <windows.h>
+#endif
+
#include <assert.h>
#include <string.h>
#include <strings.h>
@@ -71,50 +77,6 @@ IcuCollateFinish()
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
@@ -150,14 +112,32 @@ IcuCollate(const char *a, const char *b)
return result;
#endif
-#elif defined(HAVE_GLIB)
- return g_utf8_collate(a, b);
+#elif defined(WIN32)
+ const auto wa = MultiByteToWideChar(CP_UTF8, a);
+ const auto wb = MultiByteToWideChar(CP_UTF8, b);
+ if (wa.IsNull())
+ return wb.IsNull() ? 0 : -1;
+ else if (wb.IsNull())
+ return 1;
+
+ auto result = CompareStringEx(LOCALE_NAME_INVARIANT,
+ LINGUISTIC_IGNORECASE,
+ wa.c_str(), -1,
+ wb.c_str(), -1,
+ nullptr, nullptr, 0);
+ if (result != 0)
+ /* "To maintain the C runtime convention of comparing
+ strings, the value 2 can be subtracted from a
+ nonzero return value." */
+ result -= 2;
+
+ return result;
#else
- return strcasecmp(a, b);
+ return strcoll(a, b);
#endif
}
-std::string
+AllocatedString<>
IcuCaseFold(const char *src)
{
#ifdef HAVE_ICU
@@ -169,37 +149,70 @@ IcuCaseFold(const char *src)
const auto u = UCharFromUTF8(src);
if (u.IsNull())
- return std::string(src);
+ return AllocatedString<>::Duplicate(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);
+ 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);
+ return AllocatedString<>::Duplicate(src);
}
- auto result2 = UCharToUTF8({folded, folded_length});
+ auto result = 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);
+ return result;
+
+#elif defined(WIN32)
+ const auto u = MultiByteToWideChar(CP_UTF8, src);
+ if (u.IsNull())
+ return AllocatedString<>::Duplicate(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);
+
+ auto buffer = new wchar_t[size];
+ if (LCMapStringEx(LOCALE_NAME_INVARIANT,
+ LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
+ u.c_str(), -1, buffer, size,
+ nullptr, nullptr, 0) <= 0) {
+ delete[] buffer;
+ return AllocatedString<>::Duplicate(src);
+ }
+
+ auto result = WideCharToMultiByte(CP_UTF8, buffer);
+ delete[] buffer;
+ if (result.IsNull())
+ return AllocatedString<>::Duplicate(src);
+
+ return result;
+
#else
- std::string result(src);
- std::transform(result.begin(), result.end(), result.begin(), tolower);
+ size_t size = strlen(src) + 1;
+ auto buffer = new char[size];
+ size_t nbytes = strxfrm(buffer, src, size);
+ if (nbytes >= size) {
+ /* buffer too small - reallocate and try again */
+ delete[] buffer;
+ size = nbytes + 1;
+ buffer = new char[size];
+ nbytes = strxfrm(buffer, src, size);
+ }
+
+ assert(nbytes < size);
+ assert(buffer[nbytes] == 0);
+
+ return AllocatedString<>::Donate(buffer);
#endif
- return result;
}
diff --git a/src/lib/icu/Collate.hxx b/src/lib/icu/Collate.hxx
index 8ae8de46a..0ad3b24ff 100644
--- a/src/lib/icu/Collate.hxx
+++ b/src/lib/icu/Collate.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include <string>
class Error;
+template<typename T> class AllocatedString;
bool
IcuCollateInit(Error &error);
@@ -38,7 +39,7 @@ int
IcuCollate(const char *a, const char *b);
gcc_pure gcc_nonnull_all
-std::string
+AllocatedString<char>
IcuCaseFold(const char *src);
#endif
diff --git a/src/lib/icu/Converter.cxx b/src/lib/icu/Converter.cxx
new file mode 100644
index 000000000..61c0cbdd5
--- /dev/null
+++ b/src/lib/icu/Converter.cxx
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2003-2015 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 "Converter.hxx"
+#include "Error.hxx"
+#include "util/Error.hxx"
+#include "util/Macros.hxx"
+#include "util/AllocatedString.hxx"
+#include "util/WritableBuffer.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <string.h>
+
+#ifdef HAVE_ICU
+#include "Util.hxx"
+#include <unicode/ucnv.h>
+#elif defined(HAVE_ICONV)
+#include "util/Domain.hxx"
+static constexpr Domain iconv_domain("iconv");
+#endif
+
+#ifdef HAVE_ICU
+
+IcuConverter::~IcuConverter()
+{
+ ucnv_close(converter);
+}
+
+#endif
+
+#ifdef HAVE_ICU_CONVERTER
+
+IcuConverter *
+IcuConverter::Create(const char *charset, Error &error)
+{
+#ifdef HAVE_ICU
+ UErrorCode code = U_ZERO_ERROR;
+ UConverter *converter = ucnv_open(charset, &code);
+ if (converter == nullptr) {
+ error.Format(icu_domain, int(code),
+ "Failed to initialize charset '%s': %s",
+ charset, u_errorName(code));
+ return nullptr;
+ }
+
+ 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);
+#endif
+}
+
+#ifdef HAVE_ICU
+#elif defined(HAVE_ICONV)
+
+static AllocatedString<char>
+DoConvert(iconv_t conv, const char *src)
+{
+ // TODO: dynamic buffer?
+ char buffer[4096];
+ char *in = const_cast<char *>(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<size_t>(-1) || in_left > 0)
+ return nullptr;
+
+ return AllocatedString<>::Duplicate(buffer, sizeof(buffer) - out_left);
+}
+
+#endif
+
+AllocatedString<char>
+IcuConverter::ToUTF8(const char *s) const
+{
+#ifdef HAVE_ICU
+ const ScopeLock protect(mutex);
+
+ ucnv_resetToUnicode(converter);
+
+ // TODO: dynamic buffer?
+ UChar buffer[4096], *target = buffer;
+ const char *source = s;
+
+ UErrorCode code = U_ZERO_ERROR;
+
+ ucnv_toUnicode(converter, &target, buffer + ARRAY_SIZE(buffer),
+ &source, source + strlen(source),
+ nullptr, true, &code);
+ if (code != U_ZERO_ERROR)
+ return nullptr;
+
+ const size_t target_length = target - buffer;
+ return UCharToUTF8({buffer, target_length});
+#elif defined(HAVE_ICONV)
+ return DoConvert(to_utf8, s);
+#endif
+}
+
+AllocatedString<char>
+IcuConverter::FromUTF8(const char *s) const
+{
+#ifdef HAVE_ICU
+ const ScopeLock protect(mutex);
+
+ const auto u = UCharFromUTF8(s);
+ if (u.IsNull())
+ return nullptr;
+
+ ucnv_resetFromUnicode(converter);
+
+ // TODO: dynamic buffer?
+ char buffer[4096], *target = buffer;
+ const UChar *source = u.data;
+ UErrorCode code = U_ZERO_ERROR;
+
+ ucnv_fromUnicode(converter, &target, buffer + ARRAY_SIZE(buffer),
+ &source, u.end(),
+ nullptr, true, &code);
+ delete[] u.data;
+
+ if (code != U_ZERO_ERROR)
+ return nullptr;
+
+ return AllocatedString<>::Duplicate(buffer, target);
+
+#elif defined(HAVE_ICONV)
+ return DoConvert(from_utf8, s);
+#endif
+}
+
+#endif
diff --git a/src/lib/icu/Converter.hxx b/src/lib/icu/Converter.hxx
new file mode 100644
index 000000000..edb092d8f
--- /dev/null
+++ b/src/lib/icu/Converter.hxx
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2003-2015 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_CONVERTER_HXX
+#define MPD_ICU_CONVERTER_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#ifdef HAVE_ICU
+#include "thread/Mutex.hxx"
+#define HAVE_ICU_CONVERTER
+#elif defined(HAVE_ICONV)
+#include <iconv.h>
+#define HAVE_ICU_CONVERTER
+#endif
+
+#ifdef HAVE_ICU_CONVERTER
+
+class Error;
+
+#ifdef HAVE_ICU
+struct UConverter;
+#endif
+
+template<typename T> class AllocatedString;
+
+/**
+ * This class can convert strings with a certain character set to and
+ * from UTF-8.
+ */
+class IcuConverter {
+#ifdef HAVE_ICU
+ /**
+ * ICU's UConverter class is not thread-safe. This mutex
+ * serializes simultaneous calls.
+ */
+ mutable Mutex mutex;
+
+ 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) {}
+#endif
+
+public:
+#ifdef HAVE_ICU
+ ~IcuConverter();
+#elif defined(HAVE_ICONV)
+ ~IcuConverter() {
+ iconv_close(to_utf8);
+ iconv_close(from_utf8);
+ }
+#endif
+
+ static IcuConverter *Create(const char *charset, Error &error);
+
+ /**
+ * Convert the string to UTF-8.
+ *
+ * Returns AllocatedString::Null() on error.
+ */
+ gcc_pure gcc_nonnull_all
+ AllocatedString<char> ToUTF8(const char *s) const;
+
+ /**
+ * Convert the string from UTF-8.
+ *
+ * Returns AllocatedString::Null() on error.
+ */
+ gcc_pure gcc_nonnull_all
+ AllocatedString<char> FromUTF8(const char *s) const;
+};
+
+#endif
+
+#endif
diff --git a/src/lib/icu/Error.cxx b/src/lib/icu/Error.cxx
index 1fef078ac..f49ede352 100644
--- a/src/lib/icu/Error.cxx
+++ b/src/lib/icu/Error.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Error.hxx b/src/lib/icu/Error.hxx
index e96667f57..37cdb12fe 100644
--- a/src/lib/icu/Error.hxx
+++ b/src/lib/icu/Error.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Init.cxx b/src/lib/icu/Init.cxx
index 1d0ad0777..6b70d60ee 100644
--- a/src/lib/icu/Init.cxx
+++ b/src/lib/icu/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Init.hxx b/src/lib/icu/Init.hxx
index 9f585e2bd..402e7b957 100644
--- a/src/lib/icu/Init.hxx
+++ b/src/lib/icu/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Util.cxx b/src/lib/icu/Util.cxx
new file mode 100644
index 000000000..92f1de5aa
--- /dev/null
+++ b/src/lib/icu/Util.cxx
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2003-2015 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 "Util.hxx"
+#include "util/AllocatedString.hxx"
+#include "util/WritableBuffer.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <unicode/ustring.h>
+
+#include <assert.h>
+#include <string.h>
+
+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) };
+}
+
+AllocatedString<>
+UCharToUTF8(ConstBuffer<UChar> src)
+{
+ assert(!src.IsNull());
+
+ /* worst-case estimate */
+ size_t dest_capacity = 4 * src.size;
+
+ char *dest = new char[dest_capacity + 1];
+
+ 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;
+ }
+
+ dest[dest_length] = 0;
+ return AllocatedString<>::Donate(dest);
+}
diff --git a/src/lib/icu/Util.hxx b/src/lib/icu/Util.hxx
new file mode 100644
index 000000000..f2d99d0e6
--- /dev/null
+++ b/src/lib/icu/Util.hxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2015 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_UTIL_HXX
+#define MPD_ICU_UTIL_HXX
+
+#include "check.h"
+
+#include <unicode/utypes.h>
+
+template<typename T> struct WritableBuffer;
+template<typename T> struct ConstBuffer;
+template<typename T> class AllocatedString;
+
+/**
+ * Wrapper for u_strFromUTF8(). The returned pointer must be freed
+ * with delete[].
+ */
+WritableBuffer<UChar>
+UCharFromUTF8(const char *src);
+
+/**
+ * Wrapper for u_strToUTF8(). The returned pointer must be freed with
+ * delete[].
+ */
+AllocatedString<char>
+UCharToUTF8(ConstBuffer<UChar> src);
+
+#endif
diff --git a/src/lib/icu/Win32.cxx b/src/lib/icu/Win32.cxx
new file mode 100644
index 000000000..6f190c924
--- /dev/null
+++ b/src/lib/icu/Win32.cxx
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2003-2015 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 "Win32.hxx"
+#include "util/AllocatedString.hxx"
+
+#include <windows.h>
+
+AllocatedString<char>
+WideCharToMultiByte(unsigned code_page, const wchar_t *src)
+{
+ int length = WideCharToMultiByte(code_page, 0, src, -1, nullptr, 0,
+ nullptr, nullptr);
+ if (length <= 0)
+ return nullptr;
+
+ char *buffer = new char[length];
+ length = WideCharToMultiByte(code_page, 0, src, -1, buffer, length,
+ nullptr, nullptr);
+ if (length <= 0) {
+ delete[] buffer;
+ return nullptr;
+ }
+
+ return AllocatedString<char>::Donate(buffer);
+}
+
+AllocatedString<wchar_t>
+MultiByteToWideChar(unsigned code_page, const char *src)
+{
+ int length = MultiByteToWideChar(code_page, 0, src, -1, nullptr, 0);
+ if (length <= 0)
+ return nullptr;
+
+ wchar_t *buffer = new wchar_t[length];
+ length = MultiByteToWideChar(code_page, 0, src, -1, buffer, length);
+ if (length <= 0) {
+ delete[] buffer;
+ return nullptr;
+ }
+
+ return AllocatedString<wchar_t>::Donate(buffer);
+}
diff --git a/src/lib/icu/Win32.hxx b/src/lib/icu/Win32.hxx
new file mode 100644
index 000000000..253fe169a
--- /dev/null
+++ b/src/lib/icu/Win32.hxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2015 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_WIN32_HXX
+#define MPD_ICU_WIN32_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#include <wchar.h>
+
+template<typename T> class AllocatedString;
+
+gcc_pure gcc_nonnull_all
+AllocatedString<char>
+WideCharToMultiByte(unsigned code_page, const wchar_t *src);
+
+gcc_pure gcc_nonnull_all
+AllocatedString<wchar_t>
+MultiByteToWideChar(unsigned code_page, const char *src);
+
+#endif