diff options
author | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2010-12-16 19:32:21 (GMT) |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2010-12-17 17:11:03 (GMT) |
commit | 8789d4bd9eaba3a90fb3a94edb71ad0c1e01dc66 (patch) | |
tree | 4e7a9d94273ec8b09f1e8af00ff7d747f0f77fcf | |
parent | 468328468904d116a5ff70fd4c71c34e453e8593 (diff) | |
download | Qt-8789d4bd9eaba3a90fb3a94edb71ad0c1e01dc66.zip Qt-8789d4bd9eaba3a90fb3a94edb71ad0c1e01dc66.tar.gz Qt-8789d4bd9eaba3a90fb3a94edb71ad0c1e01dc66.tar.bz2 |
add error handling to QXmlStreamWriter
introduce QXmlStreamWriter::hasError(). set the error flag when any
write error occurs. ignore subsequent writes after the first error.
Reviewed-by: denis
-rw-r--r-- | src/corelib/xml/qxmlstream.cpp | 37 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.h | 2 | ||||
-rw-r--r-- | tests/auto/qxmlstream/tst_qxmlstream.cpp | 82 |
3 files changed, 116 insertions, 5 deletions
diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 3d8af9b..64a9857 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -2941,6 +2941,9 @@ QStringRef QXmlStreamReader::documentEncoding() const By default, QXmlStreamWriter encodes XML in UTF-8. Different encodings can be enforced using setCodec(). + If an error occurs while writing to the underlying device, hasError() + starts returning true and subsequent writes are ignored. + The \l{QXmlStream Bookmarks Example} illustrates how to use a stream writer to write an XML bookmark file (XBEL) that was previously read in by a QXmlStreamReader. @@ -2976,6 +2979,7 @@ public: uint inEmptyElement :1; uint lastWasStartElement :1; uint wroteSomething :1; + uint hasError :1; uint autoFormatting :1; QByteArray autoFormattingIndent; NamespaceDeclaration emptyNamespace; @@ -3008,6 +3012,7 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) #endif inStartElement = inEmptyElement = false; wroteSomething = false; + hasError = false; lastWasStartElement = false; lastNamespaceDeclaration = 1; autoFormatting = false; @@ -3017,11 +3022,15 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) void QXmlStreamWriterPrivate::write(const QStringRef &s) { if (device) { + if (hasError) + return; #ifdef QT_NO_TEXTCODEC - device->write(s.toString().toLatin1(), s.size()); + QByteArray bytes = s.toLatin1(); #else - device->write(encoder->fromUnicode(s.constData(), s.size())); + QByteArray bytes = encoder->fromUnicode(s.constData(), s.size()); #endif + if (device->write(bytes) != bytes.size()) + hasError = true; } else if (stringDevice) s.appendTo(stringDevice); @@ -3032,11 +3041,15 @@ void QXmlStreamWriterPrivate::write(const QStringRef &s) void QXmlStreamWriterPrivate::write(const QString &s) { if (device) { + if (hasError) + return; #ifdef QT_NO_TEXTCODEC - device->write(s.toLatin1(), s.size()); + QByteArray bytes = s.toLatin1(); #else - device->write(encoder->fromUnicode(s)); + QByteArray bytes = encoder->fromUnicode(s); #endif + if (device->write(bytes) != bytes.size()) + hasError = true; } else if (stringDevice) stringDevice->append(s); @@ -3078,7 +3091,10 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa void QXmlStreamWriterPrivate::write(const char *s, int len) { if (device) { - device->write(s, len); + if (hasError) + return; + if (device->write(s, len) != len) + hasError = true; } else if (stringDevice) { stringDevice->append(QString::fromLatin1(s, len)); } else @@ -3359,6 +3375,17 @@ int QXmlStreamWriter::autoFormattingIndent() const return d->autoFormattingIndent.count(' ') - d->autoFormattingIndent.count('\t'); } +/*! + Returns \c true if the stream failed to write to the underlying device. + + The error status is never reset. Writes happening after the error + occurred are ignored, even if the error condition is cleared. + */ +bool QXmlStreamWriter::hasError() const +{ + Q_D(const QXmlStreamWriter); + return d->hasError; +} /*! \overload diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index d7143bd..244d3d4 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -474,6 +474,8 @@ public: void writeCurrentToken(const QXmlStreamReader &reader); #endif + bool hasError() const; + private: Q_DISABLE_COPY(QXmlStreamWriter) Q_DECLARE_PRIVATE(QXmlStreamWriter) diff --git a/tests/auto/qxmlstream/tst_qxmlstream.cpp b/tests/auto/qxmlstream/tst_qxmlstream.cpp index 19e4b90..9e4f3ec 100644 --- a/tests/auto/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/qxmlstream/tst_qxmlstream.cpp @@ -574,6 +574,7 @@ private slots: void checkCommentIndentation() const; void checkCommentIndentation_data() const; void qtbug9196_crash() const; + void hasError() const; private: static QByteArray readFile(const QString &filename); @@ -1560,5 +1561,86 @@ void tst_QXmlStream::qtbug9196_crash() const } } +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) + { + qint64 ai = qMin(m_capacity, i); + m_capacity -= ai; + return ai ? QBuffer::writeData(c, ai) : 0; + } +public: + void setCapacity(int capacity) { m_capacity = capacity; } +private: + qint64 m_capacity; +}; + +void tst_QXmlStream::hasError() const +{ + { + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(1000); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + writer.writeEndDocument(); + QVERIFY(!writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")); + } + + { + // Failure caused by write(QString) + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(strlen("<?xml version=\"")); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + QVERIFY(writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml version=\"")); + } + + { + // Failure caused by write(char *) + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(strlen("<?xml version=\"1.0")); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + QVERIFY(writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0")); + } + + { + // Failure caused by write(QStringRef) + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(strlen("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test xmlns:")); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + writer.writeStartElement("test"); + writer.writeNamespace("http://foo.bar", "foo"); + QVERIFY(writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test xmlns:")); + } + + { + // Refusal to write after 1st failure + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(10); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + QVERIFY(writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml vers")); + fb.setCapacity(1000); + writer.writeStartElement("test"); // literal & qstring + writer.writeNamespace("http://foo.bar", "foo"); // literal & qstringref + QVERIFY(writer.hasError()); + QCOMPARE(fb.data(), QByteArray("<?xml vers")); + } + +} + #include "tst_qxmlstream.moc" // vim: et:ts=4:sw=4:sts=4 |