summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qlocale_icu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qlocale_icu.cpp')
-rw-r--r--src/corelib/tools/qlocale_icu.cpp205
1 files changed, 35 insertions, 170 deletions
diff --git a/src/corelib/tools/qlocale_icu.cpp b/src/corelib/tools/qlocale_icu.cpp
index 42651aa745..97ce82108b 100644
--- a/src/corelib/tools/qlocale_icu.cpp
+++ b/src/corelib/tools/qlocale_icu.cpp
@@ -42,199 +42,56 @@
#include "qglobal.h"
#include "qlibrary.h"
#include "qdebug.h"
+#include "qlocale_p.h"
+#include "qmutex.h"
#include "unicode/uversion.h"
#include "unicode/ucol.h"
+#include "unicode/uloc.h"
+#include "unicode/ustring.h"
QT_BEGIN_NAMESPACE
-typedef UCollator *(*Ptr_ucol_open)(const char *loc, UErrorCode *status);
-typedef void (*Ptr_ucol_close)(UCollator *coll);
-typedef UCollationResult (*Ptr_ucol_strcoll)(const UCollator *coll, const UChar *source, int32_t sourceLength, const UChar *target, int32_t targetLength);
typedef int32_t (*Ptr_u_strToCase)(UChar *dest, int32_t destCapacity, const UChar *src, int32_t srcLength, const char *locale, UErrorCode *pErrorCode);
-static Ptr_ucol_open ptr_ucol_open = 0;
-static Ptr_ucol_strcoll ptr_ucol_strcoll = 0;
-static Ptr_ucol_close ptr_ucol_close = 0;
-static Ptr_u_strToCase ptr_u_strToUpper = 0;
-static Ptr_u_strToCase ptr_u_strToLower = 0;
-
-enum LibLoadStatus
-{
- ErrorLoading = -1,
- NotLoaded = 0,
- Loaded = 1
-};
-
-static LibLoadStatus status = NotLoaded;
-
-static UCollator *icuCollator = 0;
-
-namespace {
-struct Libraries {
- QLibrary libicui18n;
- QLibrary libicuuc;
- ~Libraries()
- {
- if (icuCollator) {
- ptr_ucol_close(icuCollator);
- icuCollator = 0;
- }
-
- libicui18n.unload();
- libicuuc.unload();
- }
-};
-}
-Q_GLOBAL_STATIC(Libraries, icuLibraries)
-
-static bool loadIcuLibrary(QLibrary &lib, const QString &name)
-{
-#ifdef Q_OS_WIN
- // QLibrary on Windows does not use the version number, the libraries
- // are named "icuin<version>.dll", though.
- lib.setFileName(name);
-#else
- // on Unix, we can use the version number
- lib.setFileNameAndVersion(name, QStringLiteral(U_ICU_VERSION_SHORT));
-#endif
-
- // the ICU libraries appear to allocate global statics and not free them
- // set the PreventUnloadHint so that we can unload the QLibrary object and
- // delete it, but the libraries themselves remain in memory
- lib.setLoadHints(QLibrary::PreventUnloadHint);
- return lib.load();
-}
-
-// this function is NOT THREAD-SAFE!
-bool qt_initIcu(const QString &localeString)
-{
- if (status == ErrorLoading || !icuLibraries())
- return false;
-
- if (status == NotLoaded) {
-
- // resolve libicui18n
-#ifdef Q_OS_WIN
- // QLibrary on Windows does not use the version number, the libraries
- // are named "icuin<version>.dll", though.
- // QStringLiteral should work here and will work when MSVC fully supports C++11
- // unfortunately, current versions have do not support proper string concatenation
- QString libicui18nName = QLatin1String("icuin" U_ICU_VERSION_SHORT);
- QString libicuucName = QLatin1String("icuuc" U_ICU_VERSION_SHORT);
-#else
- QString libicui18nName = QStringLiteral("icui18n");
- QString libicuucName = QStringLiteral("icuuc");
-#endif
- QLibrary &lib = icuLibraries()->libicui18n;
- if (!loadIcuLibrary(lib, libicui18nName)) {
- qWarning("Unable to load library '%s' version " U_ICU_VERSION_SHORT ": %s",
- qPrintable(libicui18nName),
- qPrintable(lib.errorString()));
- status = ErrorLoading;
- return false;
- }
-
- ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open");
- ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close");
- ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll");
-
- if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) {
- // try again with decorated symbol names
- ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open" QT_STRINGIFY(U_ICU_VERSION_SUFFIX));
- ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close" QT_STRINGIFY(U_ICU_VERSION_SUFFIX));
- ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll" QT_STRINGIFY(U_ICU_VERSION_SUFFIX));
- }
-
- if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) {
- ptr_ucol_open = 0;
- ptr_ucol_close = 0;
- ptr_ucol_strcoll = 0;
-
- qWarning("Unable to find symbols in '%s'.", qPrintable(libicui18nName));
- status = ErrorLoading;
- return false;
- }
-
- // resolve libicuuc
- QLibrary &ucLib = icuLibraries()->libicuuc;
- if (!loadIcuLibrary(ucLib, libicuucName)) {
- qWarning("Unable to load library '%s' version " U_ICU_VERSION_SHORT ": %s",
- qPrintable(libicuucName),
- qPrintable(ucLib.errorString()));
- status = ErrorLoading;
- return false;
- }
-
- ptr_u_strToUpper = (Ptr_u_strToCase)ucLib.resolve("u_strToUpper");
- ptr_u_strToLower = (Ptr_u_strToCase)ucLib.resolve("u_strToLower");
-
- if (!ptr_u_strToUpper || !ptr_u_strToLower) {
- ptr_u_strToUpper = (Ptr_u_strToCase)ucLib.resolve("u_strToUpper" QT_STRINGIFY(U_ICU_VERSION_SUFFIX));
- ptr_u_strToLower = (Ptr_u_strToCase)ucLib.resolve("u_strToLower" QT_STRINGIFY(U_ICU_VERSION_SUFFIX));
- }
-
- if (!ptr_u_strToUpper || !ptr_u_strToLower) {
- ptr_u_strToUpper = 0;
- ptr_u_strToLower = 0;
-
- qWarning("Unable to find symbols in '%s'", qPrintable(libicuucName));
- status = ErrorLoading;
- return false;
- }
-
- // success :)
- status = Loaded;
- }
-
- if (icuCollator) {
- ptr_ucol_close(icuCollator);
- icuCollator = 0;
- }
-
- UErrorCode icuStatus = U_ZERO_ERROR;
- icuCollator = ptr_ucol_open(localeString.toLatin1().constData(), &icuStatus);
-
- if (!icuCollator) {
- qWarning("Unable to open locale %s in ICU, error code %d", qPrintable(localeString), icuStatus);
- return false;
- }
-
- return true;
-}
-
-bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result)
+bool QIcu::strcoll(const QByteArray &localeID,
+ const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result)
{
Q_ASSERT(result);
Q_ASSERT(source);
Q_ASSERT(target);
- if (!icuCollator)
+ UErrorCode icuStatus = U_ZERO_ERROR;
+ UCollator *collator = ucol_open(localeID, &icuStatus);
+
+ if (U_FAILURE((icuStatus)))
return false;
- *result = ptr_ucol_strcoll(icuCollator, reinterpret_cast<const UChar *>(source), int32_t(sourceLength),
- reinterpret_cast<const UChar *>(target), int32_t(targetLength));
+ *result = ucol_strcoll(collator,
+ reinterpret_cast<const UChar *>(source), int32_t(sourceLength),
+ reinterpret_cast<const UChar *>(target), int32_t(targetLength));
+
+ ucol_close(collator);
return true;
}
// caseFunc can either be u_strToUpper or u_strToLower
-static bool qt_u_strToCase(const QString &str, QString *out, const QLocale &locale, Ptr_u_strToCase caseFunc)
+static bool qt_u_strToCase(const QString &str, QString *out, const char *localeID, Ptr_u_strToCase caseFunc)
{
Q_ASSERT(out);
- if (!icuCollator)
- return false;
-
- QString result(str.size(), Qt::Uninitialized);
+ int32_t size = str.size();
+ size += size >> 2; // add 25% for possible expansions
+ QString result(size, Qt::Uninitialized);
UErrorCode status = U_ZERO_ERROR;
- int32_t size = caseFunc(reinterpret_cast<UChar *>(result.data()), result.size(),
+ size = caseFunc(reinterpret_cast<UChar *>(result.data()), result.size(),
reinterpret_cast<const UChar *>(str.constData()), str.size(),
- locale.bcp47Name().toLatin1().constData(), &status);
+ localeID, &status);
- if (U_FAILURE(status))
+ if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
return false;
if (size < result.size()) {
@@ -246,7 +103,7 @@ static bool qt_u_strToCase(const QString &str, QString *out, const QLocale &loca
status = U_ZERO_ERROR;
size = caseFunc(reinterpret_cast<UChar *>(result.data()), result.size(),
reinterpret_cast<const UChar *>(str.constData()), str.size(),
- locale.bcp47Name().toLatin1().constData(), &status);
+ localeID, &status);
if (U_FAILURE(status))
return false;
@@ -260,14 +117,22 @@ static bool qt_u_strToCase(const QString &str, QString *out, const QLocale &loca
return true;
}
-bool qt_u_strToUpper(const QString &str, QString *out, const QLocale &locale)
+QString QIcu::toUpper(const QByteArray &localeID, const QString &str, bool *ok)
{
- return qt_u_strToCase(str, out, locale, ptr_u_strToUpper);
+ QString out;
+ bool err = qt_u_strToCase(str, &out, localeID, u_strToUpper);
+ if (ok)
+ *ok = err;
+ return out;
}
-bool qt_u_strToLower(const QString &str, QString *out, const QLocale &locale)
+QString QIcu::toLower(const QByteArray &localeID, const QString &str, bool *ok)
{
- return qt_u_strToCase(str, out, locale, ptr_u_strToLower);
+ QString out;
+ bool err = qt_u_strToCase(str, &out, localeID, u_strToLower);
+ if (ok)
+ *ok = err;
+ return out;
}
QT_END_NAMESPACE