diff options
-rw-r--r-- | src/corelib/xml/qxmlstream.cpp | 32 | ||||
-rw-r--r-- | tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp | 22 |
2 files changed, 47 insertions, 7 deletions
diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 46c0e5d297..2345cb1881 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -2980,6 +2980,7 @@ public: uint wroteSomething :1; uint hasError :1; uint autoFormatting :1; + uint isCodecASCIICompatible :1; QByteArray autoFormattingIndent; NamespaceDeclaration emptyNamespace; int lastNamespaceDeclaration; @@ -2988,6 +2989,7 @@ public: QTextCodec *codec; QTextEncoder *encoder; #endif + void checkIfASCIICompatibleCodec(); NamespaceDeclaration &findNamespace(const QString &namespaceUri, bool writeDeclaration = false, bool noDefault = false); void writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration); @@ -3009,6 +3011,7 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) codec = QTextCodec::codecForMib(106); // utf8 encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 #endif + checkIfASCIICompatibleCodec(); inStartElement = inEmptyElement = false; wroteSomething = false; hasError = false; @@ -3018,6 +3021,18 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) namespacePrefixCount = 0; } +void QXmlStreamWriterPrivate::checkIfASCIICompatibleCodec() +{ +#ifndef QT_NO_TEXTCODEC + Q_ASSERT(encoder); + // assumes ASCII-compatibility for all 8-bit encodings + const QByteArray bytes = encoder->fromUnicode(QStringLiteral(" ")); + isCodecASCIICompatible = (bytes.count() == 1); +#else + isCodecASCIICompatible = true; +#endif +} + void QXmlStreamWriterPrivate::write(const QStringRef &s) { if (device) { @@ -3086,18 +3101,20 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa write(escaped); } -// ASCII only! +// Converts from ASCII to output encoding void QXmlStreamWriterPrivate::write(const char *s, int len) { if (device) { if (hasError) return; - if (device->write(s, len) != len) - hasError = true; - } else if (stringDevice) { - stringDevice->append(QString::fromLatin1(s, len)); - } else - qWarning("QXmlStreamWriter: No device"); + if (isCodecASCIICompatible) { + if (device->write(s, len) != len) + hasError = true; + return; + } + } + + write(QString::fromLatin1(s, len)); } void QXmlStreamWriterPrivate::writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration) { @@ -3279,6 +3296,7 @@ void QXmlStreamWriter::setCodec(QTextCodec *codec) d->codec = codec; delete d->encoder; d->encoder = codec->makeEncoder(QTextCodec::IgnoreHeader); // no byte order mark for utf8 + d->checkIfASCIICompatibleCodec(); } } diff --git a/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp index ea2cafdbc3..694a2f2952 100644 --- a/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp @@ -558,6 +558,7 @@ private slots: void hasAttribute() const; void writeWithCodec() const; void writeWithUtf8Codec() const; + void writeWithUtf16Codec() const; void writeWithStandalone() const; void entitiesAndWhitespace_1() const; void entitiesAndWhitespace_2() const; @@ -1279,6 +1280,27 @@ void tst_QXmlStream::writeWithUtf8Codec() const QVERIFY(outarray.startsWith(begin)); } +void tst_QXmlStream::writeWithUtf16Codec() const +{ + QByteArray outarray; + QXmlStreamWriter writer(&outarray); + + QTextCodec *codec = QTextCodec::codecForMib(1014); // utf-16LE + QVERIFY(codec); + writer.setCodec(codec); + + writer.writeStartDocument("1.0"); + static const char begin[] = "<?xml version=\"1.0\" encoding=\"UTF-16"; // skip potential "LE" suffix + const int count = sizeof(begin) - 1; // don't include 0 terminator + QByteArray begin_UTF16; + begin_UTF16.reserve(2*(count)); + for (int i = 0; i < count; ++i) { + begin_UTF16.append(begin[i]); + begin_UTF16.append((char)'\0'); + } + QVERIFY(outarray.startsWith(begin_UTF16)); +} + void tst_QXmlStream::writeWithStandalone() const { { |