summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qlocale.cpp91
-rw-r--r--src/corelib/tools/qlocale.h1
-rw-r--r--src/corelib/tools/qlocale_icu.cpp205
-rw-r--r--src/corelib/tools/qlocale_p.h25
-rw-r--r--src/corelib/tools/qstring.cpp13
-rw-r--r--src/corelib/tools/tools.pri2
6 files changed, 99 insertions, 238 deletions
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 67e47e56bb..c809b559dd 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -82,12 +82,6 @@ static QLocaleData *system_data = 0;
Q_GLOBAL_STATIC(QLocaleData, globalLocaleData)
#endif
-#ifdef QT_USE_ICU
-extern bool qt_initIcu(const QString &localeName);
-extern bool qt_u_strToUpper(const QString &str, QString *out, const QLocale &locale);
-extern bool qt_u_strToLower(const QString &str, QString *out, const QLocale &locale);
-#endif
-
/******************************************************************************
** Helpers for accessing Qt locale database
*/
@@ -515,12 +509,6 @@ void QLocalePrivate::updateSystemPrivate()
res = sys_locale->query(QSystemLocale::PositiveSign, QVariant());
if (!res.isNull())
system_data->m_plus = res.toString().at(0).unicode();
-
-#ifdef QT_USE_ICU
- if (!default_data)
- qt_initIcu(sys_locale->fallbackUiLocale().bcp47Name());
-#endif
-
}
#endif
@@ -587,7 +575,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1;
-static const QLocaleData *dataPointerHelper(quint16 index)
+const QLocaleData *QLocalePrivate::dataPointerForIndex(quint16 index)
{
#ifndef QT_NO_SYSTEMLOCALE
Q_ASSERT(index <= locale_data_size);
@@ -615,6 +603,14 @@ static quint16 localeDataIndex(const QLocaleData *p)
}
/*!
+ \internal
+*/
+QLocale::QLocale(QLocalePrivate &dd)
+ : d(&dd)
+{}
+
+
+/*!
Constructs a QLocale object with the specified \a name,
which has the format
"language[_script][_country][.codeset][@modifier]" or "C", where:
@@ -644,11 +640,8 @@ static quint16 localeDataIndex(const QLocaleData *p)
*/
QLocale::QLocale(const QString &name)
- : d(new QLocalePrivate())
+ : d(new QLocalePrivate(localeDataIndex(findLocaleData(name))))
{
- d->m_numberOptions = 0;
- d->m_index = localeDataIndex(findLocaleData(name));
- d->m_data = dataPointerHelper(d->m_index);
}
/*!
@@ -660,11 +653,8 @@ QLocale::QLocale(const QString &name)
*/
QLocale::QLocale()
- : d(new QLocalePrivate())
+ : d(new QLocalePrivate(localeDataIndex(defaultData()), default_number_options))
{
- d->m_numberOptions = default_number_options;
- d->m_index = localeDataIndex(defaultData());
- d->m_data = dataPointerHelper(d->m_index);
}
/*!
@@ -687,19 +677,19 @@ QLocale::QLocale()
*/
QLocale::QLocale(Language language, Country country)
- : d(new QLocalePrivate())
{
const QLocaleData *data = QLocaleData::findLocaleData(language, QLocale::AnyScript, country);
+ int index;
+ int numberOptions = 0;
// If not found, should default to system
if (data->m_language_id == QLocale::C && language != QLocale::C) {
- d->m_numberOptions = default_number_options;
- d->m_index = localeDataIndex(defaultData());
+ numberOptions = default_number_options;
+ index = localeDataIndex(defaultData());
} else {
- d->m_numberOptions = 0;
- d->m_index = localeDataIndex(data);
+ index = localeDataIndex(data);
}
- d->m_data = dataPointerHelper(d->m_index);
+ d = new QLocalePrivate(index, numberOptions);
}
\
/*!
@@ -727,19 +717,19 @@ QLocale::QLocale(Language language, Country country)
*/
QLocale::QLocale(Language language, Script script, Country country)
- : d(new QLocalePrivate())
{
const QLocaleData *data = QLocaleData::findLocaleData(language, script, country);
+ int index;
+ int numberOptions = 0;
// If not found, should default to system
if (data->m_language_id == QLocale::C && language != QLocale::C) {
- d->m_numberOptions = default_number_options;
- d->m_index = localeDataIndex(defaultData());
+ numberOptions = default_number_options;
+ index = localeDataIndex(defaultData());
} else {
- d->m_numberOptions = 0;
- d->m_index = localeDataIndex(data);
+ index = localeDataIndex(data);
}
- d->m_data = dataPointerHelper(d->m_index);
+ d = new QLocalePrivate(index, numberOptions);
}
/*!
@@ -897,10 +887,6 @@ void QLocale::setDefault(const QLocale &locale)
{
default_data = locale.d->m_data;
default_number_options = locale.numberOptions();
-
-#ifdef QT_USE_ICU
- qt_initIcu(locale.bcp47Name());
-#endif
}
/*!
@@ -1802,10 +1788,7 @@ QString QLocale::toString(double i, char f, int prec) const
QLocale QLocale::system()
{
- QLocale result(C);
- result.d->m_index = localeDataIndex(systemData());
- result.d->m_data = dataPointerHelper(result.d->m_index);
- return result;
+ return QLocale(*new QLocalePrivate(localeDataIndex(systemData())));
}
@@ -1834,9 +1817,7 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
data += locale_index[language];
while ( (data != locale_data + locale_data_size)
&& (language == QLocale::AnyLanguage || data->m_language_id == uint(language))) {
- QLocale locale(QLocale::C);
- locale.d->m_index = localeDataIndex(data);
- locale.d->m_data = dataPointerHelper(locale.d->m_index);
+ QLocale locale(*new QLocalePrivate(localeDataIndex(data)));
result.append(locale);
++data;
}
@@ -2164,12 +2145,11 @@ Qt::LayoutDirection QLocale::textDirection() const
QString QLocale::toUpper(const QString &str) const
{
#ifdef QT_USE_ICU
- {
- QString result;
- if (qt_u_strToUpper(str, &result, *this))
- return result;
- // else fall through and use Qt's toUpper
- }
+ bool ok = true;
+ QString result = QIcu::toUpper(d->m_localeID, str, &ok);
+ if (ok)
+ return result;
+ // else fall through and use Qt's toUpper
#endif
return str.toUpper();
}
@@ -2182,12 +2162,11 @@ QString QLocale::toUpper(const QString &str) const
QString QLocale::toLower(const QString &str) const
{
#ifdef QT_USE_ICU
- {
- QString result;
- if (qt_u_strToLower(str, &result, *this))
- return result;
- // else fall through and use Qt's toUpper
- }
+ bool ok = true;
+ QString result = QIcu::toLower(d->m_localeID, str, &ok);
+ if (ok)
+ return result;
+ // else fall through and use Qt's toUpper
#endif
return str.toLower();
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index a014b6b7b5..c901211af4 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -703,6 +703,7 @@ public:
QString createSeparatedList(const QStringList &strl) const;
private:
+ QLocale(QLocalePrivate &dd);
friend class QLocalePrivate;
QSharedDataPointer<QLocalePrivate> d;
};
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
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index c2c1488966..1902e4e5af 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -126,6 +126,16 @@ private:
};
#endif
+#ifdef QT_USE_ICU
+namespace QIcu {
+ QString toUpper(const QByteArray &localeId, const QString &str, bool *ok);
+ QString toLower(const QByteArray &localeId, const QString &str, bool *ok);
+
+ bool strcoll(const QByteArray &localeID, const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result);
+}
+#endif
+
+
struct QLocaleData
{
public:
@@ -178,7 +188,17 @@ public:
class Q_CORE_EXPORT QLocalePrivate : public QSharedData
{
public:
- QLocalePrivate() : m_index(0), m_numberOptions(0), m_data(0) {}
+ QLocalePrivate(int index, int numberOptions = 0)
+ : m_index(index), m_numberOptions(numberOptions)
+ {
+ m_data = dataPointerForIndex(index);
+ m_localeID = bcp47Name().toLatin1();
+ m_localeID.replace('-','_');
+ }
+
+ ~QLocalePrivate()
+ {
+ }
QChar decimal() const { return QChar(m_data->m_decimal); }
QChar group() const { return QChar(m_data->m_group); }
@@ -203,6 +223,7 @@ public:
static QLocale::Country codeToCountry(const QString &code);
static void getLangAndCountry(const QString &name, QLocale::Language &lang,
QLocale::Script &script, QLocale::Country &cntry);
+ static const QLocaleData *dataPointerForIndex(quint16 index);
QLocale::MeasurementSystem measurementSystem() const;
@@ -285,11 +306,11 @@ public:
QString dateTimeToString(const QString &format, const QDate *date, const QTime *time,
const QLocale *q) const;
-private:
friend class QLocale;
quint16 m_index;
quint16 m_numberOptions;
const QLocaleData *m_data;
+ QByteArray m_localeID;
};
inline char QLocalePrivate::digitToCLocale(QChar in) const
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index a2d91c561c..4f8d0e5614 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -100,12 +100,6 @@
QT_BEGIN_NAMESPACE
-#ifdef QT_USE_ICU
-// qlocale_icu.cpp
-extern bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result);
-#endif
-
-
// internal
int qFindString(const QChar *haystack, int haystackLen, int from,
const QChar *needle, int needleLen, Qt::CaseSensitivity cs);
@@ -5011,12 +5005,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
return result;
#elif defined(Q_OS_UNIX)
# if defined(QT_USE_ICU)
+ QLocale locale;
int res;
- if (qt_ucol_strcoll(data1, length1, data2, length2, &res)) {
- if (res == 0)
- res = ucstrcmp(data1, length1, data2, length2);
+ if (QIcu::strcoll(locale.d.constData()->m_localeID, data1, length1, data2, length2, &res))
return res;
- } // else fall through
+ // else fall through
# endif
// declared in <string.h>
int delta = strcoll(toLocal8Bit_helper(data1, length1).constData(), toLocal8Bit_helper(data2, length2).constData());
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 386db9665b..9db459ab68 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -112,6 +112,8 @@ else:include($$PWD/../../3rdparty/zlib_dependency.pri)
contains(QT_CONFIG,icu) {
SOURCES += tools/qlocale_icu.cpp
DEFINES += QT_USE_ICU
+ win32:LIBS += -licuin -licuuc
+ else:LIBS += -licui18n -licuuc
}
pcre {