summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/xml/sax/qxml.cpp14
-rw-r--r--tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp84
2 files changed, 86 insertions, 12 deletions
diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp
index bc7d00483a..717a8c327d 100644
--- a/src/xml/sax/qxml.cpp
+++ b/src/xml/sax/qxml.cpp
@@ -1265,18 +1265,8 @@ void QXmlInputSource::fetchData()
} else if (device->isOpen() || device->open(QIODevice::ReadOnly)) {
rawData.resize(BufferSize);
qint64 size = device->read(rawData.data(), BufferSize);
-
- if (size != -1) {
- // We don't want to give fromRawData() less than four bytes if we can avoid it.
- while (size < 4) {
- if (!device->waitForReadyRead(-1))
- break;
- int ret = device->read(rawData.data() + size, BufferSize - size);
- if (ret <= 0)
- break;
- size += ret;
- }
- }
+ if (size == 0 && device->waitForReadyRead(-1))
+ size = device->read(rawData.data(), BufferSize);
rawData.resize(qMax(qint64(0), size));
}
diff --git a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp
index c5e9a44398..752e39c23f 100644
--- a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp
+++ b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp
@@ -48,6 +48,7 @@ private slots:
void reset() const;
void resetSimplified() const;
void waitForReadyIODevice() const;
+ void inputFromSlowDevice() const;
};
/*!
@@ -207,5 +208,88 @@ void tst_QXmlInputSource::waitForReadyIODevice() const
QVERIFY(sv.success);
}
+// This class is used to emulate a case where less than 4 bytes are sent in
+// a single packet to ensure it is still parsed correctly
+class SlowIODevice : public QIODevice
+{
+public:
+ SlowIODevice(const QString &expectedData, QObject *parent = 0)
+ : QIODevice(parent), currentPos(0), readyToSend(true)
+ {
+ stringData = expectedData.toUtf8();
+ dataTimer = new QTimer(this);
+ connect(dataTimer, &QTimer::timeout, [=]() {
+ readyToSend = true;
+ emit readyRead();
+ dataTimer->stop();
+ });
+ dataTimer->start(1000);
+ }
+ bool open(SlowIODevice::OpenMode) override
+ {
+ setOpenMode(ReadOnly);
+ return true;
+ }
+ bool isSequential() const override
+ {
+ return true;
+ }
+ qint64 bytesAvailable() const override
+ {
+ if (readyToSend && stringData.size() != currentPos)
+ return qMax(3, stringData.size() - currentPos);
+ return 0;
+ }
+ qint64 readData(char *data, qint64 maxSize) override
+ {
+ if (!readyToSend)
+ return 0;
+ const qint64 readSize = qMin(qMin((qint64)3, maxSize), (qint64)(stringData.size() - currentPos));
+ if (readSize > 0)
+ memcpy(data, &stringData.constData()[currentPos], readSize);
+ currentPos += readSize;
+ readyToSend = false;
+ if (currentPos != stringData.size())
+ dataTimer->start(1000);
+ return readSize;
+ }
+ qint64 writeData(const char *, qint64) override { return 0; }
+ bool waitForReadyRead(int msecs) override
+ {
+ // Delibrately wait a maximum of 10 seconds for the sake
+ // of the test, so it doesn't unduly hang
+ const int waitTime = qMax(10000, msecs);
+ QTime t;
+ t.start();
+ while (t.elapsed() < waitTime) {
+ QCoreApplication::processEvents();
+ if (readyToSend)
+ return true;
+ }
+ return false;
+ }
+private:
+ QByteArray stringData;
+ int currentPos;
+ bool readyToSend;
+ QTimer *dataTimer;
+};
+
+void tst_QXmlInputSource::inputFromSlowDevice() const
+{
+ QString expectedData = QStringLiteral("<foo><bar>kake</bar><bar>ja</bar></foo>");
+ SlowIODevice slowDevice(expectedData);
+ QXmlInputSource source(&slowDevice);
+ QString data;
+ while (true) {
+ const QChar nextChar = source.next();
+ if (nextChar == QXmlInputSource::EndOfDocument)
+ break;
+ else if (nextChar != QXmlInputSource::EndOfData)
+ data += nextChar;
+ }
+ QCOMPARE(data, expectedData);
+}
+
QTEST_MAIN(tst_QXmlInputSource)
#include "tst_qxmlinputsource.moc"