summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2012-07-21 00:31:37 +0200
committerQt by Nokia <qt-info@nokia.com>2012-07-31 11:12:28 +0200
commit88d2e92b39ffd4a6ea9446498ad5a1cb208022a6 (patch)
treed64944f988a79bc8cbc556f6191e15bbe59b9cfc /src/corelib
parent865a9465f36edaf773b7836ee005ca96502dfca9 (diff)
ICU code page conversion support
Use ICU to do code page conversion instead of the builtin text codecs. With this QTextCodec simply becomes a wrapper around ICU's ucnv_* methods. We only keep our own codecs for UTF-*, ISO-8859-1, ISO-8859-15 for performance reasons, and for TSCII and iscii-* because they aren't supported by ICU. Change-Id: I4fc49eba55cf772b9772c6dac606a47a44346a60 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/codecs/codecs.pri45
-rw-r--r--src/corelib/codecs/qicucodec.cpp625
-rw-r--r--src/corelib/codecs/qicucodec_p.h91
-rw-r--r--src/corelib/codecs/qtextcodec.cpp53
-rw-r--r--src/corelib/kernel/qcoreglobaldata_p.h1
5 files changed, 791 insertions, 24 deletions
diff --git a/src/corelib/codecs/codecs.pri b/src/corelib/codecs/codecs.pri
index b08d412452..d049e52275 100644
--- a/src/corelib/codecs/codecs.pri
+++ b/src/corelib/codecs/codecs.pri
@@ -3,32 +3,43 @@
HEADERS += \
codecs/qisciicodec_p.h \
codecs/qlatincodec_p.h \
- codecs/qsimplecodec_p.h \
codecs/qtextcodec_p.h \
codecs/qtextcodec.h \
codecs/qtsciicodec_p.h \
- codecs/qutfcodec_p.h \
- codecs/qgb18030codec_p.h \
- codecs/qeucjpcodec_p.h \
- codecs/qjiscodec_p.h \
- codecs/qsjiscodec_p.h \
- codecs/qeuckrcodec_p.h \
- codecs/qbig5codec_p.h
+ codecs/qutfcodec_p.h
SOURCES += \
codecs/qisciicodec.cpp \
codecs/qlatincodec.cpp \
- codecs/qsimplecodec.cpp \
codecs/qtextcodec.cpp \
codecs/qtsciicodec.cpp \
- codecs/qutfcodec.cpp \
- codecs/qgb18030codec.cpp \
- codecs/qjpunicode.cpp \
- codecs/qeucjpcodec.cpp \
- codecs/qjiscodec.cpp \
- codecs/qsjiscodec.cpp \
- codecs/qeuckrcodec.cpp \
- codecs/qbig5codec.cpp
+ codecs/qutfcodec.cpp
+
+contains(QT_CONFIG,icu) {
+ HEADERS += \
+ codecs/qicucodec_p.h
+ SOURCES += \
+ codecs/qicucodec.cpp
+} else {
+ HEADERS += \
+ codecs/qsimplecodec_p.h \
+ codecs/qgb18030codec_p.h \
+ codecs/qeucjpcodec_p.h \
+ codecs/qjiscodec_p.h \
+ codecs/qsjiscodec_p.h \
+ codecs/qeuckrcodec_p.h \
+ codecs/qbig5codec_p.h
+
+ SOURCES += \
+ codecs/qsimplecodec.cpp \
+ codecs/qgb18030codec.cpp \
+ codecs/qjpunicode.cpp \
+ codecs/qeucjpcodec.cpp \
+ codecs/qjiscodec.cpp \
+ codecs/qsjiscodec.cpp \
+ codecs/qeuckrcodec.cpp \
+ codecs/qbig5codec.cpp
+}
unix:!qnx:!mac:!ios:!linux-android-* {
contains(QT_CONFIG,iconv) {
diff --git a/src/corelib/codecs/qicucodec.cpp b/src/corelib/codecs/qicucodec.cpp
new file mode 100644
index 0000000000..c91115b3b5
--- /dev/null
+++ b/src/corelib/codecs/qicucodec.cpp
@@ -0,0 +1,625 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qicucodec_p.h"
+#include "qtextcodec_p.h"
+#include "private/qcoreglobaldata_p.h"
+#include "qdebug.h"
+
+#include "unicode/ucnv.h"
+
+QT_BEGIN_NAMESPACE
+
+extern QMutex *qTextCodecsMutex();
+
+static void qIcuCodecStateFree(QTextCodec::ConverterState *state)
+{
+ ucnv_close(static_cast<UConverter *>(state->d));
+}
+
+/* The list below is generated from http://www.iana.org/assignments/character-sets/
+ using the snippet of code below:
+
+#include <QtCore>
+#include <unicode/ucnv.h>
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QFile file("character-sets.txt");
+ file.open(QFile::ReadOnly);
+ QByteArray name;
+ int mib = -1;
+ QByteArray nameList;
+ int pos = 0;
+ while (!file.atEnd()) {
+ QByteArray s = file.readLine().trimmed();
+ if (s.isEmpty()) {
+ if (mib != -1) {
+ UErrorCode error = U_ZERO_ERROR;
+ const char *standard_name = ucnv_getStandardName(name, "MIME", &error);
+ if (U_FAILURE(error) || !standard_name) {
+ error = U_ZERO_ERROR;
+ standard_name = ucnv_getStandardName(name, "IANA", &error);
+ }
+ UConverter *conv = ucnv_open(standard_name, &error);
+ if (!U_FAILURE(error) && conv && standard_name) {
+ ucnv_close(conv);
+ printf(" { %d, %d },\n", mib, pos);
+ nameList += "\"";
+ nameList += standard_name;
+ nameList += "\\0\"\n";
+ pos += strlen(standard_name) + 1;
+ }
+ }
+ name = QByteArray();
+ mib = -1;
+ }
+ if (s.startsWith("Name: ")) {
+ name = s.mid(5).trimmed();
+ if (name.indexOf(' ') > 0)
+ name = name.left(name.indexOf(' '));
+ }
+ if (s.startsWith("MIBenum:"))
+ mib = s.mid(8).trimmed().toInt();
+ if (s.startsWith("Alias:") && s.contains("MIME")) {
+ name = s.mid(6).trimmed();
+ name = name.left(name.indexOf(' ')).trimmed();
+ }
+ }
+ qDebug() << nameList;
+}
+*/
+
+struct MibToName {
+ short mib;
+ short index;
+};
+
+static MibToName mibToName[] = {
+ { 3, 0 },
+ { 4, 9 },
+ { 5, 20 },
+ { 6, 31 },
+ { 7, 42 },
+ { 8, 53 },
+ { 9, 64 },
+ { 10, 75 },
+ { 11, 86 },
+ { 12, 97 },
+ { 13, 108 },
+ { 16, 120 },
+ { 17, 134 },
+ { 18, 144 },
+ { 30, 151 },
+ { 36, 160 },
+ { 37, 167 },
+ { 38, 179 },
+ { 39, 186 },
+ { 40, 198 },
+ { 57, 212 },
+ { 81, 223 },
+ { 82, 234 },
+ { 84, 245 },
+ { 85, 256 },
+ { 104, 267 },
+ { 105, 279 },
+ { 106, 295 },
+ { 109, 301 },
+ { 110, 313 },
+ { 111, 325 },
+ { 113, 337 },
+ { 114, 341 },
+ { 1000, 349 },
+ { 1001, 356 },
+ { 1011, 363 },
+ { 1012, 368 },
+ { 1013, 374 },
+ { 1014, 383 },
+ { 1015, 392 },
+ { 1016, 399 },
+ { 1017, 406 },
+ { 1018, 413 },
+ { 1019, 422 },
+ { 1020, 431 },
+ { 2004, 438 },
+ { 2005, 448 },
+ { 2009, 472 },
+ { 2013, 479 },
+ { 2016, 486 },
+ { 2024, 495 },
+ { 2025, 505 },
+ { 2026, 512 },
+ { 2027, 517 },
+ { 2028, 527 },
+ { 2030, 534 },
+ { 2033, 541 },
+ { 2034, 548 },
+ { 2035, 555 },
+ { 2037, 562 },
+ { 2038, 569 },
+ { 2039, 576 },
+ { 2040, 583 },
+ { 2041, 590 },
+ { 2043, 597 },
+ { 2011, 604 },
+ { 2044, 611 },
+ { 2045, 618 },
+ { 2010, 624 },
+ { 2046, 631 },
+ { 2047, 638 },
+ { 2048, 645 },
+ { 2049, 652 },
+ { 2050, 659 },
+ { 2051, 666 },
+ { 2052, 673 },
+ { 2053, 680 },
+ { 2054, 687 },
+ { 2055, 694 },
+ { 2056, 701 },
+ { 2062, 708 },
+ { 2063, 715 },
+ { 2084, 723 },
+ { 2085, 730 },
+ { 2086, 741 },
+ { 2087, 748 },
+ { 2088, 755 },
+ { 2089, 762 },
+ { 2091, 771 },
+ { 2092, 780 },
+ { 2093, 789 },
+ { 2094, 798 },
+ { 2095, 807 },
+ { 2096, 816 },
+ { 2097, 825 },
+ { 2098, 834 },
+ { 2099, 843 },
+ { 2100, 852 },
+ { 2101, 861 },
+ { 2102, 872 },
+ { 2250, 880 },
+ { 2251, 893 },
+ { 2252, 906 },
+ { 2253, 919 },
+ { 2254, 932 },
+ { 2255, 945 },
+ { 2256, 958 },
+ { 2257, 971 },
+ { 2258, 984 },
+ { 2259, 997 },
+};
+int mibToNameSize = sizeof(mibToName)/sizeof(MibToName);
+
+static const char mibToNameTable[] =
+ "US-ASCII\0"
+ "ISO-8859-1\0"
+ "ISO-8859-2\0"
+ "ISO-8859-3\0"
+ "ISO-8859-4\0"
+ "ISO-8859-5\0"
+ "ISO-8859-6\0"
+ "ISO-8859-7\0"
+ "ISO-8859-8\0"
+ "ISO-8859-9\0"
+ "ISO-8859-10\0"
+ "ISO-2022-JP-1\0"
+ "Shift_JIS\0"
+ "EUC-JP\0"
+ "US-ASCII\0"
+ "EUC-KR\0"
+ "ISO-2022-KR\0"
+ "EUC-KR\0"
+ "ISO-2022-JP\0"
+ "ISO-2022-JP-2\0"
+ "GB_2312-80\0"
+ "ISO-8859-6\0"
+ "ISO-8859-6\0"
+ "ISO-8859-8\0"
+ "ISO-8859-8\0"
+ "ISO-2022-CN\0"
+ "ISO-2022-CN-EXT\0"
+ "UTF-8\0"
+ "ISO-8859-13\0"
+ "ISO-8859-14\0"
+ "ISO-8859-15\0"
+ "GBK\0"
+ "GB18030\0"
+ "UTF-16\0"
+ "UTF-32\0"
+ "SCSU\0"
+ "UTF-7\0"
+ "UTF-16BE\0"
+ "UTF-16LE\0"
+ "UTF-16\0"
+ "CESU-8\0"
+ "UTF-32\0"
+ "UTF-32BE\0"
+ "UTF-32LE\0"
+ "BOCU-1\0"
+ "hp-roman8\0"
+ "Adobe-Standard-Encoding\0"
+ "IBM850\0"
+ "IBM862\0"
+ "IBM-Thai\0"
+ "Shift_JIS\0"
+ "GB2312\0"
+ "Big5\0"
+ "macintosh\0"
+ "IBM037\0"
+ "IBM273\0"
+ "IBM277\0"
+ "IBM278\0"
+ "IBM280\0"
+ "IBM284\0"
+ "IBM285\0"
+ "IBM290\0"
+ "IBM297\0"
+ "IBM420\0"
+ "IBM424\0"
+ "IBM437\0"
+ "IBM500\0"
+ "cp851\0"
+ "IBM852\0"
+ "IBM855\0"
+ "IBM857\0"
+ "IBM860\0"
+ "IBM861\0"
+ "IBM863\0"
+ "IBM864\0"
+ "IBM865\0"
+ "IBM868\0"
+ "IBM869\0"
+ "IBM870\0"
+ "IBM871\0"
+ "IBM918\0"
+ "IBM1026\0"
+ "KOI8-R\0"
+ "HZ-GB-2312\0"
+ "IBM866\0"
+ "IBM775\0"
+ "KOI8-U\0"
+ "IBM00858\0"
+ "IBM01140\0"
+ "IBM01141\0"
+ "IBM01142\0"
+ "IBM01143\0"
+ "IBM01144\0"
+ "IBM01145\0"
+ "IBM01146\0"
+ "IBM01147\0"
+ "IBM01148\0"
+ "IBM01149\0"
+ "Big5-HKSCS\0"
+ "IBM1047\0"
+ "windows-1250\0"
+ "windows-1251\0"
+ "windows-1252\0"
+ "windows-1253\0"
+ "windows-1254\0"
+ "windows-1255\0"
+ "windows-1256\0"
+ "windows-1257\0"
+ "windows-1258\0"
+ "TIS-620\0";
+
+QList<QByteArray> QIcuCodec::availableCodecs()
+{
+ QList<QByteArray> codecs;
+ int n = ucnv_countAvailable();
+ for (int i = 0; i < n; ++i) {
+ const char *name = ucnv_getAvailableName(i);
+
+ UErrorCode error = U_ZERO_ERROR;
+ const char *standardName = ucnv_getStandardName(name, "MIME", &error);
+ if (U_FAILURE(error) || !standardName) {
+ error = U_ZERO_ERROR;
+ standardName = ucnv_getStandardName(name, "IANA", &error);
+ }
+ if (U_FAILURE(error))
+ continue;
+
+ error = U_ZERO_ERROR;
+ int ac = ucnv_countAliases(standardName, &error);
+ if (U_FAILURE(error))
+ continue;
+ for (int j = 0; j < ac; ++j) {
+ error = U_ZERO_ERROR;
+ const char *alias = ucnv_getAlias(standardName, j, &error);
+ if (!U_SUCCESS(error))
+ continue;
+ codecs += alias;
+ }
+ }
+
+ // handled by Qt and not in ICU:
+ codecs += "TSCII";
+ codecs += "System";
+
+ return codecs;
+}
+
+QList<int> QIcuCodec::availableMibs()
+{
+ QList<int> mibs;
+ for (int i = 0; i < mibToNameSize; ++i)
+ mibs += mibToName[i].mib;
+
+ // handled by Qt and not in ICU:
+ mibs += 2107; // TSCII
+
+ return mibs;
+}
+
+static inline bool nameMatch(const QByteArray &a, const char *b)
+{ return a == b; }
+
+QTextCodec *QIcuCodec::codecForName(const char *name)
+{
+ // backwards compatibility with Qt 4.x
+ if (!qstrcmp(name, "CP949"))
+ name = "windows-949";
+ // this one is broken data in ICU 4.4, and can't be resolved even though it's an alias to tis-620
+ if (!qstrcmp(name, "windows-874-2000"))
+ name = "TIS-620";
+
+ UErrorCode error = U_ZERO_ERROR;
+ // MIME gives better default names
+ const char *standardName = ucnv_getStandardName(name, "MIME", &error);
+ if (U_FAILURE(error) || !standardName) {
+ error = U_ZERO_ERROR;
+ standardName = ucnv_getStandardName(name, "IANA", &error);
+ }
+ bool qt_only = false;
+ if (U_FAILURE(error) || !standardName) {
+ standardName = name;
+ qt_only = true;
+ } else {
+ // correct some issues where the ICU data set contains duplicated entries.
+ // Where this happens it's because one data set is a subset of another. We
+ // always use the larger data set.
+
+ if (qstrcmp(standardName, "GB2312") == 0 || qstrcmp(standardName, "GB_2312-80") == 0)
+ standardName = "GBK";
+ else if (qstrcmp(standardName, "KSC_5601") == 0 || qstrcmp(standardName, "EUC-KR") == 0 || qstrcmp(standardName, "cp1363") == 0)
+ standardName = "windows-949";
+ }
+
+ QCoreGlobalData *globalData = QCoreGlobalData::instance();
+ QTextCodecCache *cache = &globalData->codecCache;
+
+ QTextCodec *codec;
+ if (cache) {
+ codec = cache->value(standardName);
+ if (codec)
+ return codec;
+ }
+
+ for (int i = 0; i < globalData->allCodecs.size(); ++i) {
+ QTextCodec *cursor = globalData->allCodecs.at(i);
+ if (nameMatch(cursor->name(), standardName)) {
+ if (cache)
+ cache->insert(standardName, cursor);
+ return cursor;
+ }
+ QList<QByteArray> aliases = cursor->aliases();
+ for (int y = 0; y < aliases.size(); ++y)
+ if (nameMatch(aliases.at(y), standardName)) {
+ if (cache)
+ cache->insert(standardName, cursor);
+ return cursor;
+ }
+ }
+
+ if (qt_only)
+ return 0;
+
+ // check whether there is really a converter for the name available.
+ UConverter *conv = ucnv_open(standardName, &error);
+ if (!conv) {
+ qDebug() << "codecForName: ucnv_open failed" << standardName << u_errorName(error);
+ return 0;
+ }
+ //qDebug() << "QIcuCodec: Standard name for " << name << "is" << standardName;
+ ucnv_close(conv);
+
+
+ QTextCodec *c = new QIcuCodec(standardName);
+ if (cache)
+ cache->insert(standardName, c);
+ return c;
+}
+
+
+QTextCodec *QIcuCodec::codecForMib(int mib)
+{
+ for (int i = 0; i < mibToNameSize; ++i) {
+ if (mibToName[i].mib == mib)
+ return codecForName(mibToNameTable + mibToName[i].index);
+ }
+ return 0;
+}
+
+
+QIcuCodec::QIcuCodec(const char *name)
+ : m_name(name)
+{
+}
+
+QIcuCodec::~QIcuCodec()
+{
+}
+
+UConverter *QIcuCodec::getConverter(QTextCodec::ConverterState *state) const
+{
+ UConverter *conv = 0;
+ if (state) {
+ if (!state->d) {
+ // first time
+ state->flags |= QTextCodec::FreeFunction;
+ QTextCodecUnalignedPointer::encode(state->state_data, qIcuCodecStateFree);
+ UErrorCode error = U_ZERO_ERROR;
+ state->d = ucnv_open(m_name, &error);
+ ucnv_setSubstChars(static_cast<UConverter *>(state->d),
+ state->flags & QTextCodec::ConvertInvalidToNull ? "\0" : "?", 1, &error);
+ if (U_FAILURE(error))
+ qDebug() << "getConverter(state) ucnv_open failed" << m_name << u_errorName(error);
+ }
+ conv = static_cast<UConverter *>(state->d);
+ }
+ if (!conv) {
+ // stateless conversion
+ UErrorCode error = U_ZERO_ERROR;
+ conv = ucnv_open(m_name, &error);
+ ucnv_setSubstChars(conv, "?", 1, &error);
+ if (U_FAILURE(error))
+ qDebug() << "getConverter(no state) ucnv_open failed" << m_name << u_errorName(error);
+ }
+ return conv;
+}
+
+QString QIcuCodec::convertToUnicode(const char *chars, int length, QTextCodec::ConverterState *state) const
+{
+ UConverter *conv = getConverter(state);
+
+ QString string(length + 2, Qt::Uninitialized);
+
+ const char *end = chars + length;
+ int convertedChars = 0;
+ while (1) {
+ UChar *uc = (UChar *)string.data();
+ UChar *ucEnd = uc + string.length();
+ uc += convertedChars;
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_toUnicode(conv,
+ &uc, ucEnd,
+ &chars, end,
+ 0, false, &error);
+ if (!U_SUCCESS(error) && error != U_BUFFER_OVERFLOW_ERROR) {
+ qDebug() << "convertToUnicode failed:" << u_errorName(error);
+ break;
+ }
+
+ convertedChars = uc - (UChar *)string.data();
+ if (chars >= end)
+ break;
+ string.resize(string.length()*2);
+ }
+ string.resize(convertedChars);
+
+ if (!state)
+ ucnv_close(conv);
+ return string;
+}
+
+
+QByteArray QIcuCodec::convertFromUnicode(const QChar *unicode, int length, QTextCodec::ConverterState *state) const
+{
+ UConverter *conv = getConverter(state);
+
+ int requiredLength = UCNV_GET_MAX_BYTES_FOR_STRING(length, ucnv_getMaxCharSize(conv));
+ QByteArray string(requiredLength, Qt::Uninitialized);
+
+ const UChar *uc = (const UChar *)unicode;
+ const UChar *end = uc + length;
+ int convertedChars = 0;
+ while (1) {
+ char *ch = (char *)string.data();
+ char *chEnd = ch + string.length();
+ ch += convertedChars;
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_fromUnicode(conv,
+ &ch, chEnd,
+ &uc, end,
+ 0, false, &error);
+ if (!U_SUCCESS(error))
+ qDebug() << "convertFromUnicode failed:" << u_errorName(error);
+ convertedChars = ch - string.data();
+ if (uc >= end)
+ break;
+ string.resize(string.length()*2);
+ }
+ string.resize(convertedChars);
+
+ if (!state)
+ ucnv_close(conv);
+
+ return string;
+}
+
+
+QByteArray QIcuCodec::name() const
+{
+ return m_name;
+}
+
+
+QList<QByteArray> QIcuCodec::aliases() const
+{
+ UErrorCode error = U_ZERO_ERROR;
+
+ int n = ucnv_countAliases(m_name, &error);
+
+ QList<QByteArray> aliases;
+ for (int i = 0; i < n; ++i) {
+ const char *a = ucnv_getAlias(m_name, i, &error);
+ // skip the canonical name
+ if (!a || !qstrcmp(a, m_name))
+ continue;
+ aliases += a;
+ }
+
+ return aliases;
+}
+
+
+int QIcuCodec::mibEnum() const
+{
+ for (int i = 0; i < mibToNameSize; ++i) {
+ if (m_name == (mibToNameTable + mibToName[i].index))
+ return mibToName[i].mib;
+ }
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/corelib/codecs/qicucodec_p.h b/src/corelib/codecs/qicucodec_p.h
new file mode 100644
index 0000000000..5f30eac3cc
--- /dev/null
+++ b/src/corelib/codecs/qicucodec_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QICUCODEC_P_H
+#define QICUCODEC_P_H
+
+#include "QtCore/qtextcodec.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+extern "C" {
+ typedef struct UConverter UConverter;
+}
+
+QT_BEGIN_NAMESPACE
+
+class QIcuCodec : public QTextCodec
+{
+public:
+ static QList<QByteArray> availableCodecs();
+ static QList<int> availableMibs();
+
+ static QTextCodec *codecForName(const char *name);
+ static QTextCodec *codecForMib(int mib);
+
+ QString convertToUnicode(const char *, int, ConverterState *) const;
+ QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const;
+
+ QByteArray name() const;
+ QList<QByteArray> aliases() const;
+ int mibEnum() const;
+
+private:
+ QIcuCodec(const char *name);
+ ~QIcuCodec();
+
+ UConverter *getConverter(QTextCodec::ConverterState *state) const;
+
+ const char *m_name;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp
index b379b2b111..b3607d421f 100644
--- a/src/corelib/codecs/qtextcodec.cpp
+++ b/src/corelib/codecs/qtextcodec.cpp
@@ -65,12 +65,15 @@
#include "qutfcodec_p.h"
#include "qlatincodec_p.h"
+
#if !defined(QT_BOOTSTRAPPED)
-# include "qsimplecodec_p.h"
-#endif
-#if !defined(QT_BOOTSTRAPPED) && !defined(QT_NO_BIG_CODECS)
# include "qtsciicodec_p.h"
# include "qisciicodec_p.h"
+#if defined(QT_USE_ICU)
+#include "qicucodec_p.h"
+#else
+# include "qsimplecodec_p.h"
+#if !defined(QT_NO_BIG_CODECS)
# ifndef Q_OS_INTEGRITY
# include "qgb18030codec_p.h"
# include "qeucjpcodec_p.h"
@@ -79,7 +82,11 @@
# include "qeuckrcodec_p.h"
# include "qbig5codec_p.h"
# endif // !Q_OS_INTEGRITY
-#endif // !QT_BOOTSTRAPPED && !QT_NO_BIG_CODECS
+#endif // !QT_NO_BIG_CODECS
+
+#endif // QT_USE_ICU
+#endif // QT_BOOTSTRAPPED
+
#include "qmutex.h"
#include <stdlib.h>
@@ -140,6 +147,9 @@ static QTextCodec *checkForCodec(const QByteArray &name) {
#endif
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, textCodecsMutex, (QMutex::Recursive));
+QMutex *qTextCodecsMutex() { return textCodecsMutex(); }
+
+static void setup();
// this returns the codec the method sets up as locale codec to
// avoid a race condition in codecForLocale() when
@@ -147,10 +157,12 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, textCodecsMutex, (QMutex::Recursive));
static QTextCodec *setupLocaleMapper()
{
QCoreGlobalData *globalData = QCoreGlobalData::instance();
+
QMutexLocker locker(textCodecsMutex());
if (globalData->codecForLocale)
// already setup
return globalData->codecForLocale;
+ setup();
#if !defined(QT_BOOTSTRAPPED)
QCoreApplicationPrivate::initLocale();
@@ -250,6 +262,10 @@ static QTextCodec *setupLocaleMapper()
static void setup()
{
#if !defined(QT_NO_CODECS) && !defined(QT_BOOTSTRAPPED)
+ (void)new QTsciiCodec;
+ for (int i = 0; i < 9; ++i)
+ (void)new QIsciiCodec(i);
+#if !defined(QT_USE_ICU)
for (int i = 0; i < QSimpleTextCodec::numSimpleCodecs; ++i)
(void)new QSimpleTextCodec(i);
@@ -268,13 +284,14 @@ static void setup()
(void)new QBig5hkscsCodec;
# endif // !Q_OS_INTEGRITY
- (void)new QTsciiCodec;
- for (int i = 0; i < 9; ++i)
- (void)new QIsciiCodec(i);
# endif // !QT_NO_BIG_CODECS
#endif // !QT_NO_CODECS && !QT_BOOTSTRAPPED
+#endif
#if !defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_ICONV)
+ (void) new QIconvCodec;
+#endif
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
(void) new QWindowsLocalCodec;
#endif // Q_OS_WIN32
@@ -493,9 +510,12 @@ QTextCodec *QTextCodec::codecForName(const QByteArray &name)
QMutexLocker locker(textCodecsMutex());
QCoreGlobalData *globalData = QCoreGlobalData::instance();
+ if (!globalData)
+ return 0;
if (globalData->allCodecs.isEmpty())
setup();
+#ifndef QT_USE_ICU
QTextCodecCache *cache = &globalData->codecCache;
QTextCodec *codec;
if (cache) {
@@ -521,6 +541,9 @@ QTextCodec *QTextCodec::codecForName(const QByteArray &name)
}
return 0;
+#else
+ return QIcuCodec::codecForName(name);
+#endif
}
@@ -533,6 +556,8 @@ QTextCodec* QTextCodec::codecForMib(int mib)
QMutexLocker locker(textCodecsMutex());
QCoreGlobalData *globalData = QCoreGlobalData::instance();
+ if (!globalData)
+ return 0;
if (globalData->allCodecs.isEmpty())
setup();
@@ -556,6 +581,10 @@ QTextCodec* QTextCodec::codecForMib(int mib)
}
}
+#ifdef QT_USE_ICU
+ return QIcuCodec::codecForMib(mib);
+#endif
+
return 0;
}
@@ -570,6 +599,9 @@ QTextCodec* QTextCodec::codecForMib(int mib)
*/
QList<QByteArray> QTextCodec::availableCodecs()
{
+#ifdef QT_USE_ICU
+ return QIcuCodec::availableCodecs();
+#else
QMutexLocker locker(textCodecsMutex());
QCoreGlobalData *globalData = QCoreGlobalData::instance();
@@ -584,6 +616,7 @@ QList<QByteArray> QTextCodec::availableCodecs()
}
return codecs;
+#endif
}
/*!
@@ -594,6 +627,9 @@ QList<QByteArray> QTextCodec::availableCodecs()
*/
QList<int> QTextCodec::availableMibs()
{
+#ifdef QT_USE_ICU
+ return QIcuCodec::availableMibs();
+#else
QMutexLocker locker(textCodecsMutex());
QCoreGlobalData *globalData = QCoreGlobalData::instance();
@@ -606,6 +642,7 @@ QList<int> QTextCodec::availableMibs()
codecs += globalData->allCodecs.at(i)->mibEnum();
return codecs;
+#endif
}
/*!
@@ -638,6 +675,8 @@ void QTextCodec::setCodecForLocale(QTextCodec *c)
QTextCodec* QTextCodec::codecForLocale()
{
QCoreGlobalData *globalData = QCoreGlobalData::instance();
+ if (!globalData)
+ return 0;
QTextCodec *codec = globalData->codecForLocale;
if (!globalData->codecForLocale)
diff --git a/src/corelib/kernel/qcoreglobaldata_p.h b/src/corelib/kernel/qcoreglobaldata_p.h
index 39281aa6e8..1ff7d17019 100644
--- a/src/corelib/kernel/qcoreglobaldata_p.h
+++ b/src/corelib/kernel/qcoreglobaldata_p.h
@@ -59,6 +59,7 @@
#include "QtCore/qhash.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qtextcodec.h"
+#include "QtCore/qmutex.h"
QT_BEGIN_NAMESPACE