summaryrefslogtreecommitdiffstats
path: root/src/xml/dom/qdomhelpers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xml/dom/qdomhelpers.cpp')
-rw-r--r--src/xml/dom/qdomhelpers.cpp404
1 files changed, 90 insertions, 314 deletions
diff --git a/src/xml/dom/qdomhelpers.cpp b/src/xml/dom/qdomhelpers.cpp
index 63c2db929a..0649e0c75d 100644
--- a/src/xml/dom/qdomhelpers.cpp
+++ b/src/xml/dom/qdomhelpers.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtXml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtXml/qtxmlglobal.h>
@@ -44,178 +8,14 @@
#include "qdomhelpers_p.h"
#include "qdom_p.h"
#include "qxmlstream.h"
-#include "private/qxml_p.h"
+#include "private/qxmlstream_p.h"
-QT_BEGIN_NAMESPACE
-
-#if QT_DEPRECATED_SINCE(5, 15)
-
-/**************************************************************
- *
- * QDomHandler
- *
- **************************************************************/
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-QDomHandler::QDomHandler(QDomDocumentPrivate *adoc, QXmlSimpleReader *areader,
- bool namespaceProcessing)
- : cdata(false), reader(areader), domBuilder(adoc, &locator, namespaceProcessing)
-{
-}
-
-QDomHandler::~QDomHandler() {}
-
-bool QDomHandler::endDocument()
-{
- return domBuilder.endDocument();
-}
-
-bool QDomHandler::startDTD(const QString &name, const QString &publicId, const QString &systemId)
-{
- return domBuilder.startDTD(name, publicId, systemId);
-}
-
-bool QDomHandler::startElement(const QString &nsURI, const QString &, const QString &qName,
- const QXmlAttributes &atts)
-{
- return domBuilder.startElement(nsURI, qName, atts);
-}
-
-bool QDomHandler::endElement(const QString &, const QString &, const QString &)
-{
- return domBuilder.endElement();
-}
-
-bool QDomHandler::characters(const QString &ch)
-{
- return domBuilder.characters(ch, cdata);
-}
-
-bool QDomHandler::processingInstruction(const QString &target, const QString &data)
-{
- return domBuilder.processingInstruction(target, data);
-}
-
-bool QDomHandler::skippedEntity(const QString &name)
-{
- // we can only handle inserting entity references into content
- if (reader && !reader->d_ptr->skipped_entity_in_content)
- return true;
-
- return domBuilder.skippedEntity(name);
-}
-
-bool QDomHandler::fatalError(const QXmlParseException &exception)
-{
- domBuilder.errorMsg = exception.message();
- domBuilder.errorLine = exception.lineNumber();
- domBuilder.errorColumn = exception.columnNumber();
- return QXmlDefaultHandler::fatalError(exception);
-}
-
-bool QDomHandler::startCDATA()
-{
- cdata = true;
- return true;
-}
-
-bool QDomHandler::endCDATA()
-{
- cdata = false;
- return true;
-}
-
-bool QDomHandler::startEntity(const QString &name)
-{
- return domBuilder.startEntity(name);
-}
-
-bool QDomHandler::endEntity(const QString &)
-{
- return domBuilder.endEntity();
-}
-
-bool QDomHandler::comment(const QString &ch)
-{
- return domBuilder.comment(ch);
-}
-
-bool QDomHandler::unparsedEntityDecl(const QString &name, const QString &publicId,
- const QString &systemId, const QString &notationName)
-{
- return domBuilder.unparsedEntityDecl(name, publicId, systemId, notationName);
-}
-
-bool QDomHandler::externalEntityDecl(const QString &name, const QString &publicId,
- const QString &systemId)
-{
- return unparsedEntityDecl(name, publicId, systemId, QString());
-}
+#include <memory>
+#include <stack>
-bool QDomHandler::notationDecl(const QString &name, const QString &publicId,
- const QString &systemId)
-{
- return domBuilder.notationDecl(name, publicId, systemId);
-}
-
-void QDomHandler::setDocumentLocator(QXmlLocator *locator)
-{
- this->locator.setLocator(locator);
-}
-
-QDomBuilder::ErrorInfo QDomHandler::errorInfo() const
-{
- return domBuilder.error();
-}
-QT_WARNING_POP
-
-#endif // QT_DEPRECATED_SINCE(5, 15)
-
-/**************************************************************
- *
- * QXmlDocumentLocators
- *
- **************************************************************/
-
-int QDomDocumentLocator::column() const
-{
- Q_ASSERT(reader);
- return static_cast<int>(reader->columnNumber());
-}
-
-int QDomDocumentLocator::line() const
-{
- Q_ASSERT(reader);
- return static_cast<int>(reader->lineNumber());
-}
-
-#if QT_DEPRECATED_SINCE(5, 15)
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-void QSAXDocumentLocator::setLocator(QXmlLocator *l)
-{
- locator = l;
-}
-QT_WARNING_POP
-
-int QSAXDocumentLocator::column() const
-{
- if (!locator)
- return 0;
-
- return static_cast<int>(locator->columnNumber());
-}
-
-int QSAXDocumentLocator::line() const
-{
- if (!locator)
- return 0;
-
- return static_cast<int>(locator->lineNumber());
-}
+QT_BEGIN_NAMESPACE
-#endif // QT_DEPRECATED_SINCE(5, 15)
+using namespace Qt::StringLiterals;
/**************************************************************
*
@@ -223,14 +23,12 @@ int QSAXDocumentLocator::line() const
*
**************************************************************/
-QDomBuilder::QDomBuilder(QDomDocumentPrivate *d, QXmlDocumentLocator *l, bool namespaceProcessing)
- : errorLine(0),
- errorColumn(0),
- doc(d),
- node(d),
- locator(l),
- nsProcessing(namespaceProcessing)
+QDomBuilder::QDomBuilder(QDomDocumentPrivate *d, QXmlStreamReader *r,
+ QDomDocument::ParseOptions options)
+ : doc(d), node(d), reader(r), parseOptions(options)
{
+ Q_ASSERT(doc);
+ Q_ASSERT(reader);
}
QDomBuilder::~QDomBuilder() {}
@@ -251,62 +49,46 @@ bool QDomBuilder::startDTD(const QString &name, const QString &publicId, const Q
return true;
}
-#if QT_DEPRECATED_SINCE(5, 15)
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-bool QDomBuilder::startElement(const QString &nsURI, const QString &qName,
- const QXmlAttributes &atts)
+QString QDomBuilder::dtdInternalSubset(const QString &dtd)
{
- // tag name
- QDomNodePrivate *n;
- if (nsProcessing) {
- n = doc->createElementNS(nsURI, qName);
- } else {
- n = doc->createElement(qName);
- }
+ // 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());
- if (!n)
- return false;
+ const QString &publicId = doc->doctype()->publicId;
+ if (!publicId.isEmpty())
+ tmp = tmp.sliced(tmp.indexOf(publicId) + publicId.size());
- n->setLocation(locator->line(), locator->column());
+ const QString &systemId = doc->doctype()->systemId;
+ if (!systemId.isEmpty())
+ tmp = tmp.sliced(tmp.indexOf(systemId) + systemId.size());
- node->appendChild(n);
- node = n;
+ 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();
- // attributes
- for (int i = 0; i < atts.length(); i++) {
- auto domElement = static_cast<QDomElementPrivate *>(node);
- if (nsProcessing)
- domElement->setAttributeNS(atts.uri(i), atts.qName(i), atts.value(i));
- else
- domElement->setAttribute(atts.qName(i), atts.value(i));
- }
-
- return true;
+ return QString();
}
-QT_WARNING_POP
-#endif // QT_DEPRECATED_SINCE(5, 15)
-
-inline QString stringRefToString(const QStringRef &stringRef)
+bool QDomBuilder::parseDTD(const QString &dtd)
{
- // Calling QStringRef::toString() on a NULL QStringRef in some cases returns
- // an empty string (i.e. QString("")) instead of a NULL string (i.e. QString()).
- // QDom implementation differentiates between NULL and empty strings, so
- // we need this as workaround to keep the current behavior unchanged.
- return stringRef.isNull() ? QString() : stringRef.toString();
+ doc->doctype()->internalSubset = dtdInternalSubset(dtd);
+ return true;
}
bool QDomBuilder::startElement(const QString &nsURI, const QString &qName,
const QXmlStreamAttributes &atts)
{
+ const bool nsProcessing =
+ parseOptions.testFlag(QDomDocument::ParseOption::UseNamespaceProcessing);
QDomNodePrivate *n =
nsProcessing ? doc->createElementNS(nsURI, qName) : doc->createElement(qName);
if (!n)
return false;
- n->setLocation(locator->line(), locator->column());
+ n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
node->appendChild(n);
node = n;
@@ -315,12 +97,12 @@ bool QDomBuilder::startElement(const QString &nsURI, const QString &qName,
for (const auto &attr : atts) {
auto domElement = static_cast<QDomElementPrivate *>(node);
if (nsProcessing) {
- domElement->setAttributeNS(stringRefToString(attr.namespaceUri()),
- stringRefToString(attr.qualifiedName()),
- stringRefToString(attr.value()));
+ domElement->setAttributeNS(attr.namespaceUri().toString(),
+ attr.qualifiedName().toString(),
+ attr.value().toString());
} else {
- domElement->setAttribute(stringRefToString(attr.qualifiedName()),
- stringRefToString(attr.value()));
+ domElement->setAttribute(attr.qualifiedName().toString(),
+ attr.value().toString());
}
}
@@ -342,23 +124,23 @@ bool QDomBuilder::characters(const QString &characters, bool cdata)
if (node == doc)
return false;
- QScopedPointer<QDomNodePrivate> n;
+ std::unique_ptr<QDomNodePrivate> n;
if (cdata) {
n.reset(doc->createCDATASection(characters));
} else if (!entityName.isEmpty()) {
- QScopedPointer<QDomEntityPrivate> e(
- new QDomEntityPrivate(doc, nullptr, entityName, QString(), QString(), QString()));
+ auto e = std::make_unique<QDomEntityPrivate>(
+ doc, nullptr, entityName, QString(), QString(), QString());
e->value = characters;
e->ref.deref();
- doc->doctype()->appendChild(e.data());
- e.take();
+ doc->doctype()->appendChild(e.get());
+ Q_UNUSED(e.release());
n.reset(doc->createEntityReference(entityName));
} else {
n.reset(doc->createTextNode(characters));
}
- n->setLocation(locator->line(), locator->column());
- node->appendChild(n.data());
- n.take();
+ n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
+ node->appendChild(n.get());
+ Q_UNUSED(n.release());
return true;
}
@@ -368,7 +150,7 @@ bool QDomBuilder::processingInstruction(const QString &target, const QString &da
QDomNodePrivate *n;
n = doc->createProcessingInstruction(target, data);
if (n) {
- n->setLocation(locator->line(), locator->column());
+ n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
node->appendChild(n);
return true;
} else
@@ -378,21 +160,16 @@ bool QDomBuilder::processingInstruction(const QString &target, const QString &da
bool QDomBuilder::skippedEntity(const QString &name)
{
QDomNodePrivate *n = doc->createEntityReference(name);
- n->setLocation(locator->line(), locator->column());
+ n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
node->appendChild(n);
return true;
}
void QDomBuilder::fatalError(const QString &message)
{
- errorMsg = message;
- errorLine = static_cast<int>(locator->line());
- errorColumn = static_cast<int>(locator->column());
-}
-
-QDomBuilder::ErrorInfo QDomBuilder::error() const
-{
- return ErrorInfo(errorMsg, errorLine, errorColumn);
+ parseResult.errorMessage = message;
+ parseResult.errorLine = reader->lineNumber();
+ parseResult.errorColumn = reader->columnNumber();
}
bool QDomBuilder::startEntity(const QString &name)
@@ -411,7 +188,7 @@ bool QDomBuilder::comment(const QString &characters)
{
QDomNodePrivate *n;
n = doc->createComment(characters);
- n->setLocation(locator->line(), locator->column());
+ n->setLocation(int(reader->lineNumber()), int(reader->columnNumber()));
node->appendChild(n);
return true;
}
@@ -449,8 +226,9 @@ bool QDomBuilder::notationDecl(const QString &name, const QString &publicId,
*
**************************************************************/
-QDomParser::QDomParser(QDomDocumentPrivate *d, QXmlStreamReader *r, bool namespaceProcessing)
- : reader(r), locator(r), domBuilder(d, &locator, namespaceProcessing)
+QDomParser::QDomParser(QDomDocumentPrivate *d, QXmlStreamReader *r,
+ QDomDocument::ParseOptions options)
+ : reader(r), domBuilder(d, r, options)
{
}
@@ -459,11 +237,6 @@ bool QDomParser::parse()
return parseProlog() && parseBody();
}
-QDomBuilder::ErrorInfo QDomParser::errorInfo() const
-{
- return domBuilder.error();
-}
-
bool QDomParser::parseProlog()
{
Q_ASSERT(reader);
@@ -481,23 +254,23 @@ bool QDomParser::parseProlog()
switch (reader->tokenType()) {
case QXmlStreamReader::StartDocument:
if (!reader->documentVersion().isEmpty()) {
- QString value(QLatin1String("version='"));
+ QString value(u"version='"_s);
value += reader->documentVersion();
- value += QLatin1Char('\'');
+ value += u'\'';
if (!reader->documentEncoding().isEmpty()) {
- value += QLatin1String(" encoding='");
+ value += u" encoding='"_s;
value += reader->documentEncoding();
- value += QLatin1Char('\'');
+ value += u'\'';
}
if (reader->isStandaloneDocument()) {
- value += QLatin1String(" standalone='yes'");
+ value += u" standalone='yes'"_s;
} else {
- // TODO: Add standalone='no', if 'standalone' is specified. With the current
- // QXmlStreamReader there is no way to figure out if it was specified or not.
- // QXmlStreamReader needs to be modified for handling that case correctly.
+ // Add the standalone attribute only if it was specified
+ if (reader->hasStandaloneDeclaration())
+ value += u" standalone='no'"_s;
}
- if (!domBuilder.processingInstruction(QLatin1String("xml"), value)) {
+ if (!domBuilder.processingInstruction(u"xml"_s, value)) {
domBuilder.fatalError(
QDomParser::tr("Error occurred while processing XML declaration"));
return false;
@@ -511,13 +284,15 @@ bool QDomParser::parseProlog()
}
foundDtd = true;
- if (!domBuilder.startDTD(stringRefToString(reader->dtdName()),
- stringRefToString(reader->dtdPublicId()),
- stringRefToString(reader->dtdSystemId()))) {
+ if (!domBuilder.startDTD(reader->dtdName().toString(),
+ reader->dtdPublicId().toString(),
+ reader->dtdSystemId().toString())) {
domBuilder.fatalError(
QDomParser::tr("Error occurred while processing document type declaration"));
return false;
}
+ if (!domBuilder.parseDTD(reader->text().toString()))
+ return false;
if (!parseMarkupDecl())
return false;
break;
@@ -548,13 +323,13 @@ bool QDomParser::parseBody()
{
Q_ASSERT(reader);
- std::stack<QStringRef> tagStack;
+ std::stack<QString> tagStack;
while (!reader->atEnd() && !reader->hasError()) {
switch (reader->tokenType()) {
case QXmlStreamReader::StartElement:
- tagStack.push(reader->qualifiedName());
- if (!domBuilder.startElement(stringRefToString(reader->namespaceUri()),
- stringRefToString(reader->qualifiedName()),
+ tagStack.push(reader->qualifiedName().toString());
+ if (!domBuilder.startElement(reader->namespaceUri().toString(),
+ reader->qualifiedName().toString(),
reader->attributes())) {
domBuilder.fatalError(
QDomParser::tr("Error occurred while processing a start element"));
@@ -575,13 +350,14 @@ bool QDomParser::parseBody()
}
break;
case QXmlStreamReader::Characters:
- if (!reader->isWhitespace()) { // Skip the content consisting of only whitespaces
- if (!reader->text().toString().trimmed().isEmpty()) {
- if (!domBuilder.characters(reader->text().toString(), reader->isCDATA())) {
- domBuilder.fatalError(QDomParser::tr(
- "Error occurred while processing the element content"));
- return false;
- }
+ // Skip the content if it contains only spacing characters,
+ // unless it's CDATA or PreserveSpacingOnlyNodes was specified.
+ if (reader->isCDATA() || domBuilder.preserveSpacingOnlyNodes()
+ || !(reader->isWhitespace() || reader->text().trimmed().isEmpty())) {
+ if (!domBuilder.characters(reader->text().toString(), reader->isCDATA())) {
+ domBuilder.fatalError(
+ QDomParser::tr("Error occurred while processing the element content"));
+ return false;
}
}
break;
@@ -634,15 +410,15 @@ bool QDomParser::parseMarkupDecl()
const auto entities = reader->entityDeclarations();
for (const auto &entityDecl : entities) {
- // Entity declarations are created only for Extrenal Entities. Internal Entities
+ // Entity declarations are created only for External Entities. Internal Entities
// are parsed, and QXmlStreamReader handles the parsing itself and returns the
// parsed result. So we don't need to do anything for the Internal Entities.
if (!entityDecl.publicId().isEmpty() || !entityDecl.systemId().isEmpty()) {
// External Entity
- if (!domBuilder.unparsedEntityDecl(stringRefToString(entityDecl.name()),
- stringRefToString(entityDecl.publicId()),
- stringRefToString(entityDecl.systemId()),
- stringRefToString(entityDecl.notationName()))) {
+ if (!domBuilder.unparsedEntityDecl(entityDecl.name().toString(),
+ entityDecl.publicId().toString(),
+ entityDecl.systemId().toString(),
+ entityDecl.notationName().toString())) {
domBuilder.fatalError(
QDomParser::tr("Error occurred while processing entity declaration"));
return false;
@@ -652,9 +428,9 @@ bool QDomParser::parseMarkupDecl()
const auto notations = reader->notationDeclarations();
for (const auto &notationDecl : notations) {
- if (!domBuilder.notationDecl(stringRefToString(notationDecl.name()),
- stringRefToString(notationDecl.publicId()),
- stringRefToString(notationDecl.systemId()))) {
+ if (!domBuilder.notationDecl(notationDecl.name().toString(),
+ notationDecl.publicId().toString(),
+ notationDecl.systemId().toString())) {
domBuilder.fatalError(
QDomParser::tr("Error occurred while processing notation declaration"));
return false;