Skip to content

Commit

Permalink
Add QDom internalSubset implementation
Browse files Browse the repository at this point in the history
QDom's internalSubset() always returned empty because nothing
actually set the internal data member it returns. When parsing
the DECLTYPE, extract the internal subset and save it to the
doctype()'s member when present.

Pick-to: 5.15 6.2 6.3 6.4
Fixes: QTBUG-53661
Change-Id: I6e41ff8b914381168246073b3289d82205b1c255
Reviewed-by: Sona Kurazyan <[email protected]>
  • Loading branch information
18202781743 committed Jun 22, 2022
1 parent 5271f50 commit c3b9597
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/xml/dom/qdomhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,35 @@ bool QDomBuilder::startDTD(const QString &name, const QString &publicId, const Q
return true;
}

QString QDomBuilder::dtdInternalSubset(const QString &dtd)
{
// https://www.w3.org/TR/xml/#NT-intSubset
// doctypedecl: '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>'
const QString &name = doc->doctype()->name;
QStringView tmp = QStringView(dtd).sliced(dtd.indexOf(name) + name.size());

const QString &publicId = doc->doctype()->publicId;
if (!publicId.isEmpty())
tmp = tmp.sliced(tmp.indexOf(publicId) + publicId.size());

const QString &systemId = doc->doctype()->systemId;
if (!systemId.isEmpty())
tmp = tmp.sliced(tmp.indexOf(systemId) + systemId.size());

const qsizetype obra = tmp.indexOf(u'[');
const qsizetype cbra = tmp.lastIndexOf(u']');
if (obra >= 0 && cbra >= 0)
return tmp.left(cbra).sliced(obra + 1).toString();

return QString();
}

bool QDomBuilder::parseDTD(const QString &dtd)
{
doc->doctype()->internalSubset = dtdInternalSubset(dtd);
return true;
}

bool QDomBuilder::startElement(const QString &nsURI, const QString &qName,
const QXmlStreamAttributes &atts)
{
Expand Down Expand Up @@ -272,6 +301,8 @@ bool QDomParser::parseProlog()
QDomParser::tr("Error occurred while processing document type declaration"));
return false;
}
if (!domBuilder.parseDTD(reader->text().toString()))
return false;
if (!parseMarkupDecl())
return false;
break;
Expand Down
3 changes: 3 additions & 0 deletions src/xml/dom/qdomhelpers_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class QDomBuilder
bool startEntity(const QString &name);
bool endEntity();
bool startDTD(const QString &name, const QString &publicId, const QString &systemId);
bool parseDTD(const QString &dtd);
bool comment(const QString &characters);
bool externalEntityDecl(const QString &name, const QString &publicId, const QString &systemId);
bool notationDecl(const QString &name, const QString &publicId, const QString &systemId);
Expand All @@ -61,6 +62,8 @@ class QDomBuilder
int errorColumn;

private:
QString dtdInternalSubset(const QString &dtd);

QDomDocumentPrivate *doc;
QDomNodePrivate *node;
QXmlStreamReader *reader;
Expand Down
66 changes: 66 additions & 0 deletions tests/auto/xml/dom/qdom/tst_qdom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ private slots:
void cloneDTD_QTBUG8398() const;
void DTDNotationDecl();
void DTDEntityDecl();
void DTDInternalSubset() const;
void DTDInternalSubset_data() const;
void QTBUG49113_dontCrashWithNegativeIndex() const;

void cleanupTestCase() const;
Expand Down Expand Up @@ -2044,5 +2046,69 @@ void tst_QDom::QTBUG49113_dontCrashWithNegativeIndex() const
QVERIFY(node.isNull());
}

void tst_QDom::DTDInternalSubset() const
{
QFETCH( QString, doc );
QFETCH( QString, internalSubset );
QXmlStreamReader reader(doc);
QDomDocument document;
QVERIFY(document.setContent(&reader, true));

QCOMPARE(document.doctype().internalSubset(), internalSubset);
}

void tst_QDom::DTDInternalSubset_data() const
{
QTest::addColumn<QString>("doc");
QTest::addColumn<QString>("internalSubset");

QTest::newRow("data1") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note SYSTEM '/[abcd].dtd'>\n"
"<note/>\n"
<< "" ;

QTest::newRow("data2") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note PUBLIC '-/freedesktop' 'https://[abcd].dtd'>\n"
"<note/>\n"
<< "" ;

const QString internalSubset0(
"<!-- open brackets comment [ -->\n"
"<!-- colse brackets comment ] -->\n"
);
QTest::newRow("data3") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note ["
+ internalSubset0 +
"]>\n"
"<note/>\n"
<< internalSubset0;

const QString internalSubset1(
"<!ENTITY obra '['>\n"
"<!ENTITY cbra ']'>\n"
);
QTest::newRow("data4") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note ["
+ internalSubset1 +
"]>\n"
"<note/>\n"
<< internalSubset1;

QTest::newRow("data5") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note PUBLIC '-/freedesktop' 'https://[abcd].dtd' ["
+ internalSubset0
+ "]>\n"
"<note/>\n"
<< internalSubset0;

QTest::newRow("data6") << "<?xml version='1.0'?>\n"
"<!DOCTYPE note PUBLIC '-/freedesktop' "
"'2001:db8:130F:0000:0000:09C0:876A:130B://[abcd].dtd' ["
+ internalSubset0
+ "]>\n"
"<note/>\n"
<< internalSubset0;
}

QTEST_MAIN(tst_QDom)
#include "tst_qdom.moc"

0 comments on commit c3b9597

Please sign in to comment.