diff options
Diffstat (limited to 'src/xml/dom/qdomhelpers.cpp')
-rw-r--r-- | src/xml/dom/qdomhelpers.cpp | 404 |
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 ¬ationName) -{ - 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 ¬ationDecl : 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; |