QXmlStreamReader: fix parsing of non-wellformed inputs

The tst_QXmlStream::runTestSuite() had two issues which resulted
in non-wellformed files not being checked in the incremental
parsing mode.

The first issue is that the TestSuiteHandler::endElement()
function calls isWellformed() twice with two different modes,
passing a pointer to a previously opened QFile to both calls.
As a result, the first call uses ParseSinglePass mode, which reads
the entire file at once. After that, the second call with
ParseIncrementally mode already uses a file which has
atEnd() == true. So, the call to readAll() simply returns an empty
QByteArray. So, the ParseIncrementally test was effectively a no-op.

This commit fixes it by explicitly calling seek(0) at the beginning
of the isWellformed() function and also changing the type of the
input parameter to be a QFile pointer instead of QIODevice pointer,
to make sure that seek(0) actually makes sense.

After that issue was solved, I noticed that in the incremental mode
the algorithm that was feeding the data to QXmlStreamReader
byte-by-byte was always skipping the first character (and also
reading past the end of the buffer). As a result, all the XML files
parsed in this mode were malformed.

This was fixed by moving the increment of the index after the
addData() call.

Finally, after these two things were fixed, six test cases from the
XML test suite started to fail, because the non-wellformed files
were incorrectly reported as well-formed.

Fix it by using StreamEOF instead of 0 in
QXmlStreamReaderPrivate::fastScanContentCharList().

The test case fixes amend the beginning of the public history.

The parser fix amends 817800ad39df10ca78e2c965a61d4d2025df622b
which introduced StreamEOF instead of 0.

Fixes: QTBUG-135471
Pick-to: 6.8 6.5 5.15
Change-Id: I885166252d40819a4460ec246db10bf448e4a8e2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 633278fe1c9991237e02233b32f825b2506187c3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2025-04-01 17:16:15 +02:00 committed by Qt Cherry-pick Bot
parent ecae579d03
commit a0ed54cb0b
2 changed files with 6 additions and 4 deletions

View File

@ -1292,7 +1292,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
textBuffer += QChar(ushort(c));
++n;
}
if (c == 0) {
if (c == StreamEOF) {
putString(textBuffer, pos);
textBuffer.resize(pos);
} else if (c == '>' && textBuffer.at(textBuffer.size() - 2) == u']') {

View File

@ -479,14 +479,16 @@ public:
ParseSinglePass
};
static bool isWellformed(QIODevice *const inputFile, const ParseMode mode)
static bool isWellformed(QFile *const inputFile, const ParseMode mode)
{
if (!inputFile)
qFatal("%s: inputFile must be a valid QIODevice pointer", Q_FUNC_INFO);
qFatal("%s: inputFile must be a valid QFile pointer", Q_FUNC_INFO);
if (!inputFile->isOpen())
qFatal("%s: inputFile must be opened by the caller", Q_FUNC_INFO);
if (mode != ParseIncrementally && mode != ParseSinglePass)
qFatal("%s: mode must be either ParseIncrementally or ParseSinglePass", Q_FUNC_INFO);
if (!inputFile->seek(0))
qFatal("%s: could not seek to the beginning of the file", Q_FUNC_INFO);
if(mode == ParseIncrementally)
{
@ -503,8 +505,8 @@ public:
if(bufferPos < buffer.size())
{
++bufferPos;
reader.addData(QByteArray(buffer.data() + bufferPos, 1));
++bufferPos;
}
else
break;