From 6eb1cdd1c6dc8cabc392942d0e1a1e1e89b6cc61 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 19 May 2020 17:28:42 +0200 Subject: Refactor qxmlstream_p.h Pull the file apart, so that the parts generated from qxmlstream.g are separated from the definition of the private class. This will in the future simplify maintenance and refactoring. Change-Id: I4a9c1bb1e377dee1e6d3b9aa9b0dfa64c5806c45 Reviewed-by: Alex Blasche --- src/corelib/.prev_CMakeLists.txt | 2 + src/corelib/CMakeLists.txt | 2 + src/corelib/serialization/qxmlstream.cpp | 4 +- src/corelib/serialization/qxmlstream.g | 478 ++----- src/corelib/serialization/qxmlstream_p.h | 1539 +---------------------- src/corelib/serialization/qxmlstreamgrammar.cpp | 532 ++++++++ src/corelib/serialization/qxmlstreamgrammar_p.h | 164 +++ src/corelib/serialization/qxmlstreamparser_p.h | 1027 +++++++++++++++ src/corelib/serialization/serialization.pri | 3 + src/tools/bootstrap/.prev_CMakeLists.txt | 1 + src/tools/bootstrap/CMakeLists.txt | 1 + src/tools/bootstrap/bootstrap.pro | 1 + 12 files changed, 1818 insertions(+), 1936 deletions(-) create mode 100644 src/corelib/serialization/qxmlstreamgrammar.cpp create mode 100644 src/corelib/serialization/qxmlstreamgrammar_p.h create mode 100644 src/corelib/serialization/qxmlstreamparser_p.h (limited to 'src') diff --git a/src/corelib/.prev_CMakeLists.txt b/src/corelib/.prev_CMakeLists.txt index abed206491..eb1ca0cc4b 100644 --- a/src/corelib/.prev_CMakeLists.txt +++ b/src/corelib/.prev_CMakeLists.txt @@ -125,6 +125,8 @@ qt_add_module(Core serialization/qjsonwriter.cpp serialization/qjsonwriter_p.h serialization/qtextstream.cpp serialization/qtextstream.h serialization/qtextstream_p.h serialization/qxmlstream.cpp serialization/qxmlstream.h serialization/qxmlstream_p.h + serialization/qxmlstreamgrammar.cpp serialization/qxmlstreamgrammar_p.h + serialization/qxmlstreamparser_p.h serialization/qxmlutils.cpp serialization/qxmlutils_p.h statemachine/qabstractstate.cpp statemachine/qabstractstate.h statemachine/qabstractstate_p.h statemachine/qabstracttransition.cpp statemachine/qabstracttransition.h statemachine/qabstracttransition_p.h diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index b4b65c9dbc..663e501516 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -148,6 +148,8 @@ qt_add_module(Core serialization/qjsonwriter.cpp serialization/qjsonwriter_p.h serialization/qtextstream.cpp serialization/qtextstream.h serialization/qtextstream_p.h serialization/qxmlstream.cpp serialization/qxmlstream.h serialization/qxmlstream_p.h + serialization/qxmlstreamgrammar.cpp serialization/qxmlstreamgrammar_p.h + serialization/qxmlstreamparser_p.h serialization/qxmlutils.cpp serialization/qxmlutils_p.h statemachine/qabstractstate.cpp statemachine/qabstractstate.h statemachine/qabstractstate_p.h statemachine/qabstracttransition.cpp statemachine/qabstracttransition.h statemachine/qabstracttransition_p.h diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 9963fa60ec..18f5b9c396 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -70,11 +70,11 @@ private: #include #include +#include "qxmlstream_p.h" +#include "qxmlstreamparser_p.h" QT_BEGIN_NAMESPACE -#include "qxmlstream_p.h" - enum { StreamEOF = ~0U }; namespace { diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g index 876157a9e6..59c41198c3 100644 --- a/src/corelib/serialization/qxmlstream.g +++ b/src/corelib/serialization/qxmlstream.g @@ -1,6 +1,6 @@ ---------------------------------------------------------------------------- -- --- Copyright (C) 2016 The Qt Company Ltd. +-- Copyright (C) 2020 The Qt Company Ltd. -- Contact: https://www.qt.io/licensing/ -- -- This file is part of the QtCore module of the Qt Toolkit. @@ -37,9 +37,8 @@ -- ---------------------------------------------------------------------------- -%parser QXmlStreamReader_Table - -%merged_output qxmlstream_p.h +%parser QXmlStreamGrammar +%impl qxmlstreamparser_p.h %expect 4 @@ -146,407 +145,81 @@ %start document - - -/. +/./**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml 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$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// W A R N I N G +// ------------- +// +// This file is automatically generated from qxmlstream.g. +// Changes should be made to that file, not here. Any change to this file will +// be lost! +// +// To regenerate this file, run: +// qlalr --no-debug --no-lines --qt qxmlstream.g +// #include +#include +#include "qxmlstream_p.h" +#include "qxmlutils_p.h" #include -template class QXmlStreamSimpleStack { - T *data; - qsizetype tos, cap; -public: - inline QXmlStreamSimpleStack():data(nullptr), tos(-1), cap(0){} - inline ~QXmlStreamSimpleStack(){ if (data) free(data); } - - inline void reserve(qsizetype extraCapacity) { - if (tos + extraCapacity + 1 > cap) { - cap = qMax(tos + extraCapacity + 1, cap << 1 ); - void *ptr = realloc(static_cast(data), cap * sizeof(T)); - data = reinterpret_cast(ptr); - Q_CHECK_PTR(data); - } - } +#include - inline T &push() { reserve(1); return data[++tos]; } - inline T &rawPush() { return data[++tos]; } - inline const T &top() const { return data[tos]; } - inline T &top() { return data[tos]; } - inline T &pop() { return data[tos--]; } - inline T &operator[](qsizetype index) { return data[index]; } - inline const T &at(qsizetype index) const { return data[index]; } - inline qsizetype size() const { return tos + 1; } - inline void resize(qsizetype s) { tos = s - 1; } - inline bool isEmpty() const { return tos < 0; } - inline void clear() { tos = -1; } - - using const_iterator = const T*; - using iterator = T*; - T *begin() { return data; } - const T *begin() const { return data; } - const T *cbegin() const { return begin(); } - T *end() { return data + size(); } - const T *end() const { return data + size(); } - const T *cend() const { return end(); } -}; - - -class QXmlStream -{ - Q_DECLARE_TR_FUNCTIONS(QXmlStream) -}; - -class QXmlStreamPrivateTagStack { -public: - struct NamespaceDeclaration - { - QStringRef prefix; - QStringRef namespaceUri; - }; - - struct Tag - { - QStringRef name; - QStringRef qualifiedName; - NamespaceDeclaration namespaceDeclaration; - int tagStackStringStorageSize; - qsizetype namespaceDeclarationsSize; - }; - - - QXmlStreamPrivateTagStack(); - QXmlStreamSimpleStack namespaceDeclarations; - QString tagStackStringStorage; - int tagStackStringStorageSize; - int initialTagStackStringStorageSize; - bool tagsDone; - - inline QStringRef addToStringStorage(const QStringRef &s) { - return addToStringStorage(qToStringViewIgnoringNull(s)); - } - inline QStringRef addToStringStorage(const QString &s) { - return addToStringStorage(qToStringViewIgnoringNull(s)); - } - QStringRef addToStringStorage(QStringView s) - { - int pos = tagStackStringStorageSize; - int sz = s.size(); - if (pos != tagStackStringStorage.size()) - tagStackStringStorage.resize(pos); - tagStackStringStorage.append(s.data(), sz); - tagStackStringStorageSize += sz; - return QStringRef(&tagStackStringStorage, pos, sz); - } - - QXmlStreamSimpleStack tagStack; - - - inline Tag &tagStack_pop() { - Tag& tag = tagStack.pop(); - tagStackStringStorageSize = tag.tagStackStringStorageSize; - namespaceDeclarations.resize(tag.namespaceDeclarationsSize); - tagsDone = tagStack.isEmpty(); - return tag; - } - inline Tag &tagStack_push() { - Tag &tag = tagStack.push(); - tag.tagStackStringStorageSize = tagStackStringStorageSize; - tag.namespaceDeclarationsSize = namespaceDeclarations.size(); - return tag; - } -}; +#ifndef QXMLSTREAMPARSER_P_H +#define QXMLSTREAMPARSER_P_H - -class QXmlStreamEntityResolver; #ifndef QT_NO_XMLSTREAMREADER -class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{ - QXmlStreamReader *q_ptr; - Q_DECLARE_PUBLIC(QXmlStreamReader) -public: - QXmlStreamReaderPrivate(QXmlStreamReader *q); - ~QXmlStreamReaderPrivate(); - void init(); - - QByteArray rawReadBuffer; - QByteArray dataBuffer; - uchar firstByte; - qint64 nbytesread; - QString readBuffer; - int readBufferPos; - QXmlStreamSimpleStack putStack; - struct Entity { - Entity() = default; - Entity(const QString &name, const QString &value) - : name(name), value(value), external(false), unparsed(false), literal(false), - hasBeenParsed(false), isCurrentlyReferenced(false){} - static inline Entity createLiteral(QLatin1String name, QLatin1String value) - { Entity result(name, value); result.literal = result.hasBeenParsed = true; return result; } - QString name, value; - uint external : 1; - uint unparsed : 1; - uint literal : 1; - uint hasBeenParsed : 1; - uint isCurrentlyReferenced : 1; - }; - // these hash tables use a QStringView as a key to avoid creating QStrings - // just for lookup. The keys are usually views into Entity::name and thus - // are guaranteed to have the same lifetime as the referenced data: - QHash entityHash; - QHash parameterEntityHash; - QXmlStreamSimpleStackentityReferenceStack; - int entityExpansionLimit = 4096; - int entityLength = 0; - inline bool referenceEntity(Entity &entity) { - if (entity.isCurrentlyReferenced) { - raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected.")); - return false; - } - // entityLength represents the amount of additional characters the - // entity expands into (can be negative for e.g. &). It's used to - // avoid DoS attacks through recursive entity expansions - entityLength += entity.value.size() - entity.name.size() - 2; - if (entityLength > entityExpansionLimit) { - raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit.")); - return false; - } - entity.isCurrentlyReferenced = true; - entityReferenceStack.push() = &entity; - injectToken(ENTITY_DONE); - return true; - } - - - QIODevice *device; - bool deleteDevice; - QStringDecoder decoder; - bool atEnd; - - /*! - \sa setType() - */ - QXmlStreamReader::TokenType type; - QXmlStreamReader::Error error; - QString errorString; - QString unresolvedEntity; - - qint64 lineNumber, lastLineStart, characterOffset; - - - void write(const QString &); - void write(const char *); - - - QXmlStreamAttributes attributes; - QStringRef namespaceForPrefix(const QStringRef &prefix); - void resolveTag(); - void resolvePublicNamespaces(); - void resolveDtd(); - uint resolveCharRef(int symbolIndex); - bool checkStartDocument(); - void startDocument(); - void parseError(); - void checkPublicLiteral(const QStringRef &publicId); - - bool scanDtd; - QStringRef lastAttributeValue; - bool lastAttributeIsCData; - struct DtdAttribute { - QStringRef tagName; - QStringRef attributeQualifiedName; - QStringRef attributePrefix; - QStringRef attributeName; - QStringRef defaultValue; - bool isCDATA; - bool isNamespaceAttribute; - }; - QXmlStreamSimpleStack dtdAttributes; - struct NotationDeclaration { - QStringRef name; - QStringRef publicId; - QStringRef systemId; - }; - QXmlStreamSimpleStack notationDeclarations; - QXmlStreamNotationDeclarations publicNotationDeclarations; - QXmlStreamNamespaceDeclarations publicNamespaceDeclarations; - - struct EntityDeclaration { - QStringRef name; - QStringRef notationName; - QStringRef publicId; - QStringRef systemId; - QStringRef value; - bool parameter; - bool external; - inline void clear() { - name.clear(); - notationName.clear(); - publicId.clear(); - systemId.clear(); - value.clear(); - parameter = external = false; - } - }; - QXmlStreamSimpleStack entityDeclarations; - QXmlStreamEntityDeclarations publicEntityDeclarations; - - QStringRef text; - - QStringRef prefix, namespaceUri, qualifiedName, name; - QStringRef processingInstructionTarget, processingInstructionData; - QStringRef dtdName, dtdPublicId, dtdSystemId; - QStringRef documentVersion, documentEncoding; - uint isEmptyElement : 1; - uint isWhitespace : 1; - uint isCDATA : 1; - uint standalone : 1; - uint hasCheckedStartDocument : 1; - uint normalizeLiterals : 1; - uint hasSeenTag : 1; - uint inParseEntity : 1; - uint referenceToUnparsedEntityDetected : 1; - uint referenceToParameterEntityDetected : 1; - uint hasExternalDtdSubset : 1; - uint lockEncoding : 1; - uint namespaceProcessing : 1; - - int resumeReduction; - void resume(int rule); - - inline bool entitiesMustBeDeclared() const { - return (!inParseEntity - && (standalone - || (!referenceToUnparsedEntityDetected - && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25 - && !hasExternalDtdSubset))); - } - - // qlalr parser - int tos; - int stack_size; - struct Value { - int pos; - int len; - int prefix; - ushort c; - }; - - Value *sym_stack; - int *state_stack; - inline void reallocateStack(); - inline Value &sym(int index) const - { return sym_stack[tos + index - 1]; } - QString textBuffer; - inline void clearTextBuffer() { - if (!scanDtd) { - textBuffer.resize(0); - textBuffer.reserve(256); - } - } - struct Attribute { - Value key; - Value value; - }; - QXmlStreamSimpleStack attributeStack; - - inline QStringRef symString(int index) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); - } - QStringView symView(int index) const - { - const Value &symbol = sym(index); - return QStringView(textBuffer.data() + symbol.pos, symbol.len).mid(symbol.prefix); - } - inline QStringRef symName(int index) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos, symbol.len); - } - inline QStringRef symString(int index, int offset) { - const Value &symbol = sym(index); - return QStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset); - } - inline QStringRef symPrefix(int index) { - const Value &symbol = sym(index); - if (symbol.prefix) - return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); - return QStringRef(); - } - inline QStringRef symString(const Value &symbol) { - return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); - } - inline QStringRef symName(const Value &symbol) { - return QStringRef(&textBuffer, symbol.pos, symbol.len); - } - inline QStringRef symPrefix(const Value &symbol) { - if (symbol.prefix) - return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); - return QStringRef(); - } - - inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; } - - - short token; - uint token_char; - - uint filterCarriageReturn(); - inline uint getChar(); - inline uint peekChar(); - inline void putChar(uint c) { putStack.push() = c; } - inline void putChar(QChar c) { putStack.push() = c.unicode(); } - void putString(QStringView s, qsizetype from = 0); - void putStringLiteral(QStringView s); - void putReplacement(QStringView s); - void putReplacementInAttributeValue(QStringView s); - uint getChar_helper(); - - bool scanUntil(const char *str, short tokenToInject = -1); - bool scanString(const char *str, short tokenToInject, bool requireSpace = true); - inline void injectToken(ushort tokenToInject) { - putChar(int(tokenToInject) << 16); - } - - QString resolveUndeclaredEntity(const QString &name); - void parseEntity(const QString &value); - std::unique_ptr entityParser; - - bool scanAfterLangleBang(); - bool scanPublicOrSystem(); - bool scanNData(); - bool scanAfterDefaultDecl(); - bool scanAttType(); - - - // scan optimization functions. Not strictly necessary but LALR is - // not very well suited for scanning fast - int fastScanLiteralContent(); - int fastScanSpace(); - int fastScanContentCharList(); - int fastScanName(int *prefix = nullptr); - inline int fastScanNMTOKEN(); - - - bool parse(); - inline void consumeRule(int); - - void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); - void raiseWellFormedError(const QString &message); - - QXmlStreamEntityResolver *entityResolver; - -private: - /*! \internal - Never assign to variable type directly. Instead use this function. - - This prevents errors from being ignored. - */ - inline void setType(const QXmlStreamReader::TokenType t) - { - if(type != QXmlStreamReader::Invalid) - type = t; - } -}; bool QXmlStreamReaderPrivate::parse() { @@ -1512,8 +1185,8 @@ attribute ::= qname space_opt EQ space_opt attribute_value; namespaceDeclaration.prefix.clear(); const QStringRef ns(symString(5)); - if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || - ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) + if (ns == QLatin1String("http://www.w3.org/2000/xmlns/") || + ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); else namespaceDeclaration.namespaceUri = addToStringStorage(ns); @@ -1868,6 +1541,9 @@ nmtoken ::= COLON; } return false; } -#endif //QT_NO_XMLSTREAMREADER.xml + +#endif + +#endif ./ diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index c9239eb410..2c9cdfc9d3 100644 --- a/src/corelib/serialization/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h @@ -50,597 +50,13 @@ #include #include +#include +#include "qxmlstreamgrammar_p.h" -// This file was generated by qlalr - DO NOT EDIT! #ifndef QXMLSTREAM_P_H #define QXMLSTREAM_P_H -#if defined(ERROR) -# undef ERROR -#endif - -class QXmlStreamReader_Table -{ -public: - enum VariousConstants { - EOF_SYMBOL = 0, - AMPERSAND = 5, - ANY = 41, - ATTLIST = 31, - BANG = 25, - CDATA = 47, - CDATA_START = 28, - COLON = 17, - COMMA = 19, - DASH = 20, - DBLQUOTE = 8, - DIGIT = 27, - DOCTYPE = 29, - DOT = 23, - ELEMENT = 30, - EMPTY = 40, - ENTITIES = 51, - ENTITY = 32, - ENTITY_DONE = 45, - EQ = 14, - ERROR = 43, - FIXED = 39, - HASH = 6, - ID = 48, - IDREF = 49, - IDREFS = 50, - IMPLIED = 38, - LANGLE = 3, - LBRACK = 9, - LETTER = 26, - LPAREN = 11, - NDATA = 36, - NMTOKEN = 52, - NMTOKENS = 53, - NOTATION = 33, - NOTOKEN = 1, - PARSE_ENTITY = 44, - PCDATA = 42, - PERCENT = 15, - PIPE = 13, - PLUS = 21, - PUBLIC = 35, - QUESTIONMARK = 24, - QUOTE = 7, - RANGLE = 4, - RBRACK = 10, - REQUIRED = 37, - RPAREN = 12, - SEMICOLON = 18, - SHIFT_THERE = 56, - SLASH = 16, - SPACE = 2, - STAR = 22, - SYSTEM = 34, - UNRESOLVED_ENTITY = 46, - VERSION = 55, - XML = 54, - - ACCEPT_STATE = 416, - RULE_COUNT = 270, - STATE_COUNT = 427, - TERMINAL_COUNT = 57, - NON_TERMINAL_COUNT = 84, - - GOTO_INDEX_OFFSET = 427, - GOTO_INFO_OFFSET = 1017, - GOTO_CHECK_OFFSET = 1017 - }; - - static const char *const spell []; - static const short lhs []; - static const short rhs []; - static const short goto_default []; - static const short action_default []; - static const short action_index []; - static const short action_info []; - static const short action_check []; - - static inline int nt_action (int state, int nt) - { - const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; - if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) - return goto_default [nt]; - - return action_info [GOTO_INFO_OFFSET + yyn]; - } - - static inline int t_action (int state, int token) - { - const int yyn = action_index [state] + token; - - if (yyn < 0 || action_check [yyn] != token) - return - action_default [state]; - - return action_info [yyn]; - } -}; - - -const char *const QXmlStreamReader_Table::spell [] = { - "end of file", nullptr, " ", "<", ">", "&", "#", "\'", "\"", "[", - "]", "(", ")", "|", "=", "%", "/", ":", ";", ",", - "-", "+", "*", ".", "?", "!", "[a-zA-Z]", "[0-9]", "[CDATA[", "DOCTYPE", - "ELEMENT", "ATTLIST", "ENTITY", "NOTATION", "SYSTEM", "PUBLIC", "NDATA", "REQUIRED", "IMPLIED", "FIXED", - "EMPTY", "ANY", "PCDATA", nullptr, nullptr, nullptr, nullptr, "CDATA", "ID", "IDREF", - "IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", " class QXmlStreamSimpleStack { T *data; @@ -748,8 +164,8 @@ public: class QXmlStreamEntityResolver; -#ifndef QT_NO_XMLSTREAMREADER -class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{ +class QXmlStreamReaderPrivate : public QXmlStreamGrammar, public QXmlStreamPrivateTagStack +{ QXmlStreamReader *q_ptr; Q_DECLARE_PUBLIC(QXmlStreamReader) public: @@ -1037,950 +453,7 @@ private: } }; -bool QXmlStreamReaderPrivate::parse() -{ - // cleanup currently reported token - - switch (type) { - case QXmlStreamReader::StartElement: - name.clear(); - prefix.clear(); - qualifiedName.clear(); - namespaceUri.clear(); - publicNamespaceDeclarations.clear(); - attributes.clear(); - if (isEmptyElement) { - setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); - namespaceUri = tag.namespaceDeclaration.namespaceUri; - name = tag.name; - qualifiedName = tag.qualifiedName; - isEmptyElement = false; - return true; - } - clearTextBuffer(); - break; - case QXmlStreamReader::EndElement: - name.clear(); - prefix.clear(); - qualifiedName.clear(); - namespaceUri.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::DTD: - publicNotationDeclarations.clear(); - publicEntityDeclarations.clear(); - dtdName.clear(); - dtdPublicId.clear(); - dtdSystemId.clear(); - Q_FALLTHROUGH(); - case QXmlStreamReader::Comment: - case QXmlStreamReader::Characters: - isCDATA = false; - isWhitespace = true; - text.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::EntityReference: - text.clear(); - name.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::ProcessingInstruction: - processingInstructionTarget.clear(); - processingInstructionData.clear(); - clearTextBuffer(); - break; - case QXmlStreamReader::NoToken: - case QXmlStreamReader::Invalid: - break; - case QXmlStreamReader::StartDocument: - lockEncoding = true; - documentVersion.clear(); - documentEncoding.clear(); - if (decoder.isValid() && decoder.hasError()) { - raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); - readBuffer.clear(); - return false; - } - Q_FALLTHROUGH(); - default: - clearTextBuffer(); - ; - } - - setType(QXmlStreamReader::NoToken); - - - // the main parse loop - int act, r; - - if (resumeReduction) { - act = state_stack[tos-1]; - r = resumeReduction; - resumeReduction = 0; - goto ResumeReduction; - } - - act = state_stack[tos]; - - forever { - if (token == -1 && - TERMINAL_COUNT != action_index[act]) { - uint cu = getChar(); - token = NOTOKEN; - token_char = cu == ~0U ? cu : ushort(cu); - if ((cu != ~0U) && (cu & 0xff0000)) { - token = cu >> 16; - } else switch (token_char) { - case 0xfffe: - case 0xffff: - token = ERROR; - break; - case '\r': - token = SPACE; - if (cu == '\r') { - if ((token_char = filterCarriageReturn())) { - ++lineNumber; - lastLineStart = characterOffset + readBufferPos; - break; - } - } else { - break; - } - Q_FALLTHROUGH(); - case ~0U: { - token = EOF_SYMBOL; - if (!tagsDone && !inParseEntity) { - int a = t_action(act, token); - if (a < 0) { - raiseError(QXmlStreamReader::PrematureEndOfDocumentError); - return false; - } - } - - } break; - case '\n': - ++lineNumber; - lastLineStart = characterOffset + readBufferPos; - Q_FALLTHROUGH(); - case ' ': - case '\t': - token = SPACE; - break; - case '&': - token = AMPERSAND; - break; - case '#': - token = HASH; - break; - case '\'': - token = QUOTE; - break; - case '\"': - token = DBLQUOTE; - break; - case '<': - token = LANGLE; - break; - case '>': - token = RANGLE; - break; - case '[': - token = LBRACK; - break; - case ']': - token = RBRACK; - break; - case '(': - token = LPAREN; - break; - case ')': - token = RPAREN; - break; - case '|': - token = PIPE; - break; - case '=': - token = EQ; - break; - case '%': - token = PERCENT; - break; - case '/': - token = SLASH; - break; - case ':': - token = COLON; - break; - case ';': - token = SEMICOLON; - break; - case ',': - token = COMMA; - break; - case '-': - token = DASH; - break; - case '+': - token = PLUS; - break; - case '*': - token = STAR; - break; - case '.': - token = DOT; - break; - case '?': - token = QUESTIONMARK; - break; - case '!': - token = BANG; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token = DIGIT; - break; - default: - if (cu < 0x20) - token = NOTOKEN; - else - token = LETTER; - break; - } - } - - act = t_action (act, token); - if (act == ACCEPT_STATE) { - // reset the parser in case someone resumes (process instructions can follow a valid document) - tos = 0; - state_stack[tos++] = 0; - state_stack[tos] = 0; - return true; - } else if (act > 0) { - if (++tos >= stack_size-1) - reallocateStack(); - - Value &val = sym_stack[tos]; - val.c = token_char; - val.pos = textBuffer.size(); - val.prefix = 0; - val.len = 1; - if (token_char) - textBuffer += QChar(token_char); - - state_stack[tos] = act; - token = -1; - - - } else if (act < 0) { - r = - act - 1; - -#if defined (QLALR_DEBUG) - int ridx = rule_index[r]; - printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]); - ++ridx; - for (int i = ridx; i < ridx + rhs[r]; ++i) { - int symbol = rule_info[i]; - if (const char *name = spell[symbol]) - printf (" %s", name); - else - printf (" #%d", symbol); - } - printf ("\n"); -#endif - - tos -= rhs[r]; - act = state_stack[tos++]; - ResumeReduction: - switch (r) { - - case 0: - setType(QXmlStreamReader::EndDocument); - break; - - case 1: - if (type != QXmlStreamReader::Invalid) { - if (hasSeenTag || inParseEntity) { - setType(QXmlStreamReader::EndDocument); - } else { - raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected.")); - // reset the parser - tos = 0; - state_stack[tos++] = 0; - state_stack[tos] = 0; - return false; - } - } - break; - - case 10: - entityReferenceStack.pop()->isCurrentlyReferenced = false; - if (entityReferenceStack.isEmpty()) - entityLength = 0; - clearSym(); - break; - - case 11: - if (!scanString(spell[VERSION], VERSION, false) && atEnd) { - resume(11); - return false; - } - break; - - case 12: - setType(QXmlStreamReader::StartDocument); - documentVersion = symString(6); - startDocument(); - break; - - case 13: - hasExternalDtdSubset = true; - dtdSystemId = symString(2); - break; - - case 14: - checkPublicLiteral(symString(2)); - dtdPublicId = symString(2); - dtdSystemId = symString(4); - hasExternalDtdSubset = true; - break; - - case 16: - if (!scanPublicOrSystem() && atEnd) { - resume(16); - return false; - } - dtdName = symString(3); - break; - - case 17: - case 18: - dtdName = symString(3); - Q_FALLTHROUGH(); - - case 19: - case 20: - setType(QXmlStreamReader::DTD); - text = &textBuffer; - break; - - case 21: - scanDtd = true; - break; - - case 22: - scanDtd = false; - break; - - case 37: - if (!scanString(spell[EMPTY], EMPTY, false) - && !scanString(spell[ANY], ANY, false) - && atEnd) { - resume(37); - return false; - } - break; - - case 43: - if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { - resume(43); - return false; - } - break; - - case 68: { - lastAttributeIsCData = true; - } break; - - case 78: - if (!scanAfterDefaultDecl() && atEnd) { - resume(78); - return false; - } - break; - - case 83: - sym(1) = sym(2); - lastAttributeValue.clear(); - lastAttributeIsCData = false; - if (!scanAttType() && atEnd) { - resume(83); - return false; - } - break; - - case 84: { - DtdAttribute &dtdAttribute = dtdAttributes.push(); - dtdAttribute.tagName.clear(); - dtdAttribute.isCDATA = lastAttributeIsCData; - dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1)); - dtdAttribute.attributeName = addToStringStorage(symString(1)); - dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1)); - dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns") - || (dtdAttribute.attributePrefix.isEmpty() - && dtdAttribute.attributeName == QLatin1String("xmlns"))); - if (lastAttributeValue.isNull()) { - dtdAttribute.defaultValue.clear(); - } else { - if (dtdAttribute.isCDATA) - dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue); - else - dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified()); - - } - } break; - - case 88: { - if (referenceToUnparsedEntityDetected && !standalone) - break; - int n = dtdAttributes.size(); - QStringRef tagName = addToStringStorage(symName(3)); - while (n--) { - DtdAttribute &dtdAttribute = dtdAttributes[n]; - if (!dtdAttribute.tagName.isNull()) - break; - dtdAttribute.tagName = tagName; - for (int i = 0; i < n; ++i) { - if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName) - && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) { - dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it - break; - } - } - } - } break; - - case 89: { - if (!scanPublicOrSystem() && atEnd) { - resume(89); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.push(); - entityDeclaration.clear(); - entityDeclaration.name = symString(3); - } break; - - case 90: { - if (!scanPublicOrSystem() && atEnd) { - resume(90); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.push(); - entityDeclaration.clear(); - entityDeclaration.name = symString(5); - entityDeclaration.parameter = true; - } break; - - case 91: { - if (!scanNData() && atEnd) { - resume(91); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - entityDeclaration.systemId = symString(3); - entityDeclaration.external = true; - } break; - - case 92: { - if (!scanNData() && atEnd) { - resume(92); - return false; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - checkPublicLiteral((entityDeclaration.publicId = symString(3))); - entityDeclaration.systemId = symString(5); - entityDeclaration.external = true; - } break; - - case 93: { - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - entityDeclaration.notationName = symString(3); - if (entityDeclaration.parameter) - raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); - } - Q_FALLTHROUGH(); - - case 94: - case 95: { - if (referenceToUnparsedEntityDetected && !standalone) { - entityDeclarations.pop(); - break; - } - EntityDeclaration &entityDeclaration = entityDeclarations.top(); - if (!entityDeclaration.external) - entityDeclaration.value = symString(2); - auto &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash; - if (!hash.contains(qToStringViewIgnoringNull(entityDeclaration.name))) { - Entity entity(entityDeclaration.name.toString(), - entityDeclaration.value.toString()); - entity.unparsed = (!entityDeclaration.notationName.isNull()); - entity.external = entityDeclaration.external; - hash.insert(qToStringViewIgnoringNull(entity.name), entity); - } - } break; - - case 96: { - setType(QXmlStreamReader::ProcessingInstruction); - int pos = sym(4).pos + sym(4).len; - processingInstructionTarget = symString(3); - if (scanUntil("?>")) { - processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); - if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) { - raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document.")); - } - else if (!QXmlUtils::isNCName(processingInstructionTarget)) - raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.") - .arg(processingInstructionTarget)); - } else if (type != QXmlStreamReader::Invalid){ - resume(96); - return false; - } - } break; - - case 97: - setType(QXmlStreamReader::ProcessingInstruction); - processingInstructionTarget = symString(3); - if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) - raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); - break; - - case 98: - if (!scanAfterLangleBang() && atEnd) { - resume(98); - return false; - } - break; - - case 99: - if (!scanUntil("--")) { - resume(99); - return false; - } - break; - - case 100: { - setType(QXmlStreamReader::Comment); - int pos = sym(1).pos + 4; - text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); - } break; - - case 101: { - setType(QXmlStreamReader::Characters); - isCDATA = true; - isWhitespace = false; - int pos = sym(2).pos; - if (scanUntil("]]>", -1)) { - text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); - } else { - resume(101); - return false; - } - } break; - - case 102: { - if (!scanPublicOrSystem() && atEnd) { - resume(102); - return false; - } - NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); - notationDeclaration.name = symString(3); - } break; - - case 103: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - notationDeclaration.systemId = symString(3); - notationDeclaration.publicId.clear(); - } break; - - case 104: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - notationDeclaration.systemId.clear(); - checkPublicLiteral((notationDeclaration.publicId = symString(3))); - } break; - - case 105: { - NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); - checkPublicLiteral((notationDeclaration.publicId = symString(3))); - notationDeclaration.systemId = symString(5); - } break; - - case 129: - isWhitespace = false; - Q_FALLTHROUGH(); - - case 130: - sym(1).len += fastScanContentCharList(); - if (atEnd && !inParseEntity) { - resume(130); - return false; - } - break; - - case 139: - if (!textBuffer.isEmpty()) { - setType(QXmlStreamReader::Characters); - text = &textBuffer; - } - break; - - case 140: - case 141: - clearSym(); - break; - - case 142: - case 143: - sym(1) = sym(2); - break; - - case 144: - case 145: - case 146: - case 147: - sym(1).len += sym(2).len; - break; - - case 173: - if (normalizeLiterals) - textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); - break; - - case 174: - sym(1).len += fastScanLiteralContent(); - if (atEnd) { - resume(174); - return false; - } - break; - - case 175: { - if (!QXmlUtils::isPublicID(symString(1))) { - raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1))); - resume(175); - return false; - } - } break; - - case 176: - case 177: - clearSym(); - break; - - case 178: - case 179: - sym(1) = sym(2); - break; - - case 180: - case 181: - case 182: - case 183: - sym(1).len += sym(2).len; - break; - - case 213: - case 214: - clearSym(); - break; - - case 215: - case 216: - sym(1) = sym(2); - lastAttributeValue = symString(1); - break; - - case 217: - case 218: - case 219: - case 220: - sym(1).len += sym(2).len; - break; - - case 229: { - QStringRef prefix = symPrefix(1); - if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { - NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); - namespaceDeclaration.prefix.clear(); - - const QStringRef ns(symString(5)); - if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || - ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) - raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); - else - namespaceDeclaration.namespaceUri = addToStringStorage(ns); - } else { - Attribute &attribute = attributeStack.push(); - attribute.key = sym(1); - attribute.value = sym(5); - - QStringRef attributeQualifiedName = symName(1); - bool normalize = false; - for (int a = 0; a < dtdAttributes.size(); ++a) { - DtdAttribute &dtdAttribute = dtdAttributes[a]; - if (!dtdAttribute.isCDATA - && dtdAttribute.tagName == qualifiedName - && dtdAttribute.attributeQualifiedName == attributeQualifiedName - ) { - normalize = true; - break; - } - } - if (normalize) { - // normalize attribute value (simplify and trim) - int pos = textBuffer.size(); - int n = 0; - bool wasSpace = true; - for (int i = 0; i < attribute.value.len; ++i) { - QChar c = textBuffer.at(attribute.value.pos + i); - if (c.unicode() == ' ') { - if (wasSpace) - continue; - wasSpace = true; - } else { - wasSpace = false; - } - textBuffer += textBuffer.at(attribute.value.pos + i); - ++n; - } - if (wasSpace) - while (n && textBuffer.at(pos + n - 1).unicode() == ' ') - --n; - attribute.value.pos = pos; - attribute.value.len = n; - } - if (prefix == QLatin1String("xmlns") && namespaceProcessing) { - NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); - QStringRef namespacePrefix = symString(attribute.key); - QStringRef namespaceUri = symString(attribute.value); - attributeStack.pop(); - if (((namespacePrefix == QLatin1String("xml")) - ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))) - || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") - || namespaceUri.isEmpty() - || namespacePrefix == QLatin1String("xmlns")) - raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); - - namespaceDeclaration.prefix = addToStringStorage(namespacePrefix); - namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); - } - } - } break; - - case 235: { - normalizeLiterals = true; - Tag &tag = tagStack_push(); - prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2)); - name = tag.name = addToStringStorage(symString(2)); - qualifiedName = tag.qualifiedName = addToStringStorage(symName(2)); - if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name)) - raiseWellFormedError(QXmlStream::tr("Invalid XML name.")); - } break; - - case 236: - isEmptyElement = true; - Q_FALLTHROUGH(); - - case 237: - setType(QXmlStreamReader::StartElement); - resolveTag(); - if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) - raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); - hasSeenTag = true; - break; - - case 238: { - setType(QXmlStreamReader::EndElement); - Tag &tag = tagStack_pop(); - - namespaceUri = tag.namespaceDeclaration.namespaceUri; - name = tag.name; - qualifiedName = tag.qualifiedName; - if (qualifiedName != symName(3)) - raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); - } break; - - case 239: - if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); - break; - } - setType(QXmlStreamReader::EntityReference); - name = &unresolvedEntity; - break; - - case 240: { - sym(1).len += sym(2).len + 1; - QStringView reference = symView(2); - if (const auto it = entityHash.find(reference); it != entityHash.end()) { - Entity &entity = *it; - if (entity.unparsed) { - raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference)); - } else { - if (!entity.hasBeenParsed) { - parseEntity(entity.value); - entity.hasBeenParsed = true; - } - if (entity.literal) - putStringLiteral(entity.value); - else if (referenceEntity(entity)) - putReplacement(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - } - break; - } - - if (entityResolver) { - QString replacementText = resolveUndeclaredEntity(reference.toString()); - if (!replacementText.isNull()) { - putReplacement(replacementText); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - } - - injectToken(UNRESOLVED_ENTITY); - unresolvedEntity = symString(2).toString(); - textBuffer.chop(2 + sym(2).len); - clearSym(); - - } break; - - case 241: { - sym(1).len += sym(2).len + 1; - QStringView reference = symView(2); - if (const auto it = parameterEntityHash.find(reference); it != parameterEntityHash.end()) { - referenceToParameterEntityDetected = true; - Entity &entity = *it; - if (entity.unparsed || entity.external) { - referenceToUnparsedEntityDetected = true; - } else { - if (referenceEntity(entity)) - putString(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - } - } else if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2))); - } - } break; - - case 242: - sym(1).len += sym(2).len + 1; - break; - - case 243: { - sym(1).len += sym(2).len + 1; - QStringView reference = symView(2); - if (const auto it = entityHash.find(reference); it != entityHash.end()) { - Entity &entity = *it; - if (entity.unparsed || entity.value.isNull()) { - raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference)); - break; - } - if (!entity.hasBeenParsed) { - parseEntity(entity.value); - entity.hasBeenParsed = true; - } - if (entity.literal) - putStringLiteral(entity.value); - else if (referenceEntity(entity)) - putReplacementInAttributeValue(entity.value); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - - if (entityResolver) { - QString replacementText = resolveUndeclaredEntity(reference.toString()); - if (!replacementText.isNull()) { - putReplacement(replacementText); - textBuffer.chop(2 + sym(2).len); - clearSym(); - break; - } - } - if (entitiesMustBeDeclared()) { - raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference)); - } - } break; - - case 244: { - if (char32_t s = resolveCharRef(3)) { - putStringLiteral(QChar::fromUcs4(s)); - textBuffer.chop(3 + sym(3).len); - clearSym(); - } else { - raiseWellFormedError(QXmlStream::tr("Invalid character reference.")); - } - } break; - - case 247: - case 248: - sym(1).len += sym(2).len; - break; - - case 259: - sym(1).len += fastScanSpace(); - if (atEnd) { - resume(259); - return false; - } - break; - - case 262: { - sym(1).len += fastScanName(&sym(1).prefix); - if (atEnd) { - resume(262); - return false; - } - } break; - - case 263: - sym(1).len += fastScanName(); - if (atEnd) { - resume(263); - return false; - } - break; - - case 264: - case 265: - case 266: - case 267: - case 268: - sym(1).len += fastScanNMTOKEN(); - if (atEnd) { - resume(268); - return false; - } - - break; - - default: - ; - } // switch - act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT); - if (type != QXmlStreamReader::NoToken) - return true; - } else { - parseError(); - break; - } - } - return false; -} -#endif //QT_NO_XMLSTREAMREADER.xml - +QT_END_NAMESPACE #endif // QXMLSTREAM_P_H diff --git a/src/corelib/serialization/qxmlstreamgrammar.cpp b/src/corelib/serialization/qxmlstreamgrammar.cpp new file mode 100644 index 0000000000..d709515249 --- /dev/null +++ b/src/corelib/serialization/qxmlstreamgrammar.cpp @@ -0,0 +1,532 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore 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$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! +#include "qxmlstreamgrammar_p.h" + +QT_BEGIN_NAMESPACE + +const char *const QXmlStreamGrammar::spell [] = { + "end of file", 0, " ", "<", ">", "&", "#", "\'", "\"", "[", + "]", "(", ")", "|", "=", "%", "/", ":", ";", ",", + "-", "+", "*", ".", "?", "!", "[a-zA-Z]", "[0-9]", "[CDATA[", "DOCTYPE", + "ELEMENT", "ATTLIST", "ENTITY", "NOTATION", "SYSTEM", "PUBLIC", "NDATA", "REQUIRED", "IMPLIED", "FIXED", + "EMPTY", "ANY", "PCDATA", 0, 0, 0, 0, "CDATA", "ID", "IDREF", + "IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", " + +QT_BEGIN_NAMESPACE + +class QXmlStreamGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + AMPERSAND = 5, + ANY = 41, + ATTLIST = 31, + BANG = 25, + CDATA = 47, + CDATA_START = 28, + COLON = 17, + COMMA = 19, + DASH = 20, + DBLQUOTE = 8, + DIGIT = 27, + DOCTYPE = 29, + DOT = 23, + ELEMENT = 30, + EMPTY = 40, + ENTITIES = 51, + ENTITY = 32, + ENTITY_DONE = 45, + EQ = 14, + ERROR = 43, + FIXED = 39, + HASH = 6, + ID = 48, + IDREF = 49, + IDREFS = 50, + IMPLIED = 38, + LANGLE = 3, + LBRACK = 9, + LETTER = 26, + LPAREN = 11, + NDATA = 36, + NMTOKEN = 52, + NMTOKENS = 53, + NOTATION = 33, + NOTOKEN = 1, + PARSE_ENTITY = 44, + PCDATA = 42, + PERCENT = 15, + PIPE = 13, + PLUS = 21, + PUBLIC = 35, + QUESTIONMARK = 24, + QUOTE = 7, + RANGLE = 4, + RBRACK = 10, + REQUIRED = 37, + RPAREN = 12, + SEMICOLON = 18, + SHIFT_THERE = 56, + SLASH = 16, + SPACE = 2, + STAR = 22, + SYSTEM = 34, + UNRESOLVED_ENTITY = 46, + VERSION = 55, + XML = 54, + + ACCEPT_STATE = 416, + RULE_COUNT = 270, + STATE_COUNT = 427, + TERMINAL_COUNT = 57, + NON_TERMINAL_COUNT = 84, + + GOTO_INDEX_OFFSET = 427, + GOTO_INFO_OFFSET = 1030, + GOTO_CHECK_OFFSET = 1030 + }; + + static const char *const spell[]; + static const short lhs[]; + static const short rhs[]; + static const short goto_default[]; + static const short action_default[]; + static const short action_index[]; + static const short action_info[]; + static const short action_check[]; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +QT_END_NAMESPACE +#endif // QXMLSTREAMGRAMMAR_P_H + diff --git a/src/corelib/serialization/qxmlstreamparser_p.h b/src/corelib/serialization/qxmlstreamparser_p.h new file mode 100644 index 0000000000..1d28923a11 --- /dev/null +++ b/src/corelib/serialization/qxmlstreamparser_p.h @@ -0,0 +1,1027 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml 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$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// W A R N I N G +// ------------- +// +// This file is automatically generated from qxmlstream.g. +// Changes should be made to that file, not here. Any change to this file will +// be lost! +// +// To regenerate this file, run: +// qlalr --no-debug --no-lines --qt qxmlstream.g +// + +#include +#include +#include "qxmlstream_p.h" +#include "qxmlutils_p.h" +#include + +#include + +#ifndef QXMLSTREAMPARSER_P_H +#define QXMLSTREAMPARSER_P_H + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_XMLSTREAMREADER + +bool QXmlStreamReaderPrivate::parse() +{ + // cleanup currently reported token + + switch (type) { + case QXmlStreamReader::StartElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + publicNamespaceDeclarations.clear(); + attributes.clear(); + if (isEmptyElement) { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + isEmptyElement = false; + return true; + } + clearTextBuffer(); + break; + case QXmlStreamReader::EndElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::DTD: + publicNotationDeclarations.clear(); + publicEntityDeclarations.clear(); + dtdName.clear(); + dtdPublicId.clear(); + dtdSystemId.clear(); + Q_FALLTHROUGH(); + case QXmlStreamReader::Comment: + case QXmlStreamReader::Characters: + isCDATA = false; + isWhitespace = true; + text.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::EntityReference: + text.clear(); + name.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::ProcessingInstruction: + processingInstructionTarget.clear(); + processingInstructionData.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + break; + case QXmlStreamReader::StartDocument: + lockEncoding = true; + documentVersion.clear(); + documentEncoding.clear(); + if (decoder.isValid() && decoder.hasError()) { + raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); + readBuffer.clear(); + return false; + } + Q_FALLTHROUGH(); + default: + clearTextBuffer(); + ; + } + + setType(QXmlStreamReader::NoToken); + + + // the main parse loop + int act, r; + + if (resumeReduction) { + act = state_stack[tos-1]; + r = resumeReduction; + resumeReduction = 0; + goto ResumeReduction; + } + + act = state_stack[tos]; + + forever { + if (token == -1 && - TERMINAL_COUNT != action_index[act]) { + uint cu = getChar(); + token = NOTOKEN; + token_char = cu == ~0U ? cu : ushort(cu); + if ((cu != ~0U) && (cu & 0xff0000)) { + token = cu >> 16; + } else switch (token_char) { + case 0xfffe: + case 0xffff: + token = ERROR; + break; + case '\r': + token = SPACE; + if (cu == '\r') { + if ((token_char = filterCarriageReturn())) { + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + break; + } + } else { + break; + } + Q_FALLTHROUGH(); + case ~0U: { + token = EOF_SYMBOL; + if (!tagsDone && !inParseEntity) { + int a = t_action(act, token); + if (a < 0) { + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); + return false; + } + } + + } break; + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + Q_FALLTHROUGH(); + case ' ': + case '\t': + token = SPACE; + break; + case '&': + token = AMPERSAND; + break; + case '#': + token = HASH; + break; + case '\'': + token = QUOTE; + break; + case '\"': + token = DBLQUOTE; + break; + case '<': + token = LANGLE; + break; + case '>': + token = RANGLE; + break; + case '[': + token = LBRACK; + break; + case ']': + token = RBRACK; + break; + case '(': + token = LPAREN; + break; + case ')': + token = RPAREN; + break; + case '|': + token = PIPE; + break; + case '=': + token = EQ; + break; + case '%': + token = PERCENT; + break; + case '/': + token = SLASH; + break; + case ':': + token = COLON; + break; + case ';': + token = SEMICOLON; + break; + case ',': + token = COMMA; + break; + case '-': + token = DASH; + break; + case '+': + token = PLUS; + break; + case '*': + token = STAR; + break; + case '.': + token = DOT; + break; + case '?': + token = QUESTIONMARK; + break; + case '!': + token = BANG; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token = DIGIT; + break; + default: + if (cu < 0x20) + token = NOTOKEN; + else + token = LETTER; + break; + } + } + + act = t_action (act, token); + if (act == ACCEPT_STATE) { + // reset the parser in case someone resumes (process instructions can follow a valid document) + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return true; + } else if (act > 0) { + if (++tos >= stack_size-1) + reallocateStack(); + + Value &val = sym_stack[tos]; + val.c = token_char; + val.pos = textBuffer.size(); + val.prefix = 0; + val.len = 1; + if (token_char) + textBuffer += QChar(token_char); + + state_stack[tos] = act; + token = -1; + + + } else if (act < 0) { + r = - act - 1; + +#if defined (QLALR_DEBUG) + int ridx = rule_index[r]; + printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]); + ++ridx; + for (int i = ridx; i < ridx + rhs[r]; ++i) { + int symbol = rule_info[i]; + if (const char *name = spell[symbol]) + printf (" %s", name); + else + printf (" #%d", symbol); + } + printf ("\n"); +#endif + + tos -= rhs[r]; + act = state_stack[tos++]; + ResumeReduction: + switch (r) { + + case 0: + setType(QXmlStreamReader::EndDocument); + break; + + case 1: + if (type != QXmlStreamReader::Invalid) { + if (hasSeenTag || inParseEntity) { + setType(QXmlStreamReader::EndDocument); + } else { + raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected.")); + // reset the parser + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return false; + } + } + break; + + case 10: + entityReferenceStack.pop()->isCurrentlyReferenced = false; + if (entityReferenceStack.isEmpty()) + entityLength = 0; + clearSym(); + break; + + case 11: + if (!scanString(spell[VERSION], VERSION, false) && atEnd) { + resume(11); + return false; + } + break; + + case 12: + setType(QXmlStreamReader::StartDocument); + documentVersion = symString(6); + startDocument(); + break; + + case 13: + hasExternalDtdSubset = true; + dtdSystemId = symString(2); + break; + + case 14: + checkPublicLiteral(symString(2)); + dtdPublicId = symString(2); + dtdSystemId = symString(4); + hasExternalDtdSubset = true; + break; + + case 16: + if (!scanPublicOrSystem() && atEnd) { + resume(16); + return false; + } + dtdName = symString(3); + break; + + case 17: + case 18: + dtdName = symString(3); + Q_FALLTHROUGH(); + + case 19: + case 20: + setType(QXmlStreamReader::DTD); + text = &textBuffer; + break; + + case 21: + scanDtd = true; + break; + + case 22: + scanDtd = false; + break; + + case 37: + if (!scanString(spell[EMPTY], EMPTY, false) + && !scanString(spell[ANY], ANY, false) + && atEnd) { + resume(37); + return false; + } + break; + + case 43: + if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { + resume(43); + return false; + } + break; + + case 68: { + lastAttributeIsCData = true; + } break; + + case 78: + if (!scanAfterDefaultDecl() && atEnd) { + resume(78); + return false; + } + break; + + case 83: + sym(1) = sym(2); + lastAttributeValue.clear(); + lastAttributeIsCData = false; + if (!scanAttType() && atEnd) { + resume(83); + return false; + } + break; + + case 84: { + DtdAttribute &dtdAttribute = dtdAttributes.push(); + dtdAttribute.tagName.clear(); + dtdAttribute.isCDATA = lastAttributeIsCData; + dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1)); + dtdAttribute.attributeName = addToStringStorage(symString(1)); + dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1)); + dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns") + || (dtdAttribute.attributePrefix.isEmpty() + && dtdAttribute.attributeName == QLatin1String("xmlns"))); + if (lastAttributeValue.isNull()) { + dtdAttribute.defaultValue.clear(); + } else { + if (dtdAttribute.isCDATA) + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue); + else + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified()); + + } + } break; + + case 88: { + if (referenceToUnparsedEntityDetected && !standalone) + break; + int n = dtdAttributes.size(); + QStringRef tagName = addToStringStorage(symName(3)); + while (n--) { + DtdAttribute &dtdAttribute = dtdAttributes[n]; + if (!dtdAttribute.tagName.isNull()) + break; + dtdAttribute.tagName = tagName; + for (int i = 0; i < n; ++i) { + if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName) + && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) { + dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it + break; + } + } + } + } break; + + case 89: { + if (!scanPublicOrSystem() && atEnd) { + resume(89); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(3); + } break; + + case 90: { + if (!scanPublicOrSystem() && atEnd) { + resume(90); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(5); + entityDeclaration.parameter = true; + } break; + + case 91: { + if (!scanNData() && atEnd) { + resume(91); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.systemId = symString(3); + entityDeclaration.external = true; + } break; + + case 92: { + if (!scanNData() && atEnd) { + resume(92); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + checkPublicLiteral((entityDeclaration.publicId = symString(3))); + entityDeclaration.systemId = symString(5); + entityDeclaration.external = true; + } break; + + case 93: { + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.notationName = symString(3); + if (entityDeclaration.parameter) + raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); + } + Q_FALLTHROUGH(); + + case 94: + case 95: { + if (referenceToUnparsedEntityDetected && !standalone) { + entityDeclarations.pop(); + break; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + if (!entityDeclaration.external) + entityDeclaration.value = symString(2); + auto &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash; + if (!hash.contains(qToStringViewIgnoringNull(entityDeclaration.name))) { + Entity entity(entityDeclaration.name.toString(), + entityDeclaration.value.toString()); + entity.unparsed = (!entityDeclaration.notationName.isNull()); + entity.external = entityDeclaration.external; + hash.insert(qToStringViewIgnoringNull(entity.name), entity); + } + } break; + + case 96: { + setType(QXmlStreamReader::ProcessingInstruction); + int pos = sym(4).pos + sym(4).len; + processingInstructionTarget = symString(3); + if (scanUntil("?>")) { + processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); + if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) { + raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document.")); + } + else if (!QXmlUtils::isNCName(processingInstructionTarget)) + raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.") + .arg(processingInstructionTarget)); + } else if (type != QXmlStreamReader::Invalid){ + resume(96); + return false; + } + } break; + + case 97: + setType(QXmlStreamReader::ProcessingInstruction); + processingInstructionTarget = symString(3); + if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) + raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); + break; + + case 98: + if (!scanAfterLangleBang() && atEnd) { + resume(98); + return false; + } + break; + + case 99: + if (!scanUntil("--")) { + resume(99); + return false; + } + break; + + case 100: { + setType(QXmlStreamReader::Comment); + int pos = sym(1).pos + 4; + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } break; + + case 101: { + setType(QXmlStreamReader::Characters); + isCDATA = true; + isWhitespace = false; + int pos = sym(2).pos; + if (scanUntil("]]>", -1)) { + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } else { + resume(101); + return false; + } + } break; + + case 102: { + if (!scanPublicOrSystem() && atEnd) { + resume(102); + return false; + } + NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); + notationDeclaration.name = symString(3); + } break; + + case 103: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId = symString(3); + notationDeclaration.publicId.clear(); + } break; + + case 104: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId.clear(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + } break; + + case 105: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + notationDeclaration.systemId = symString(5); + } break; + + case 129: + isWhitespace = false; + Q_FALLTHROUGH(); + + case 130: + sym(1).len += fastScanContentCharList(); + if (atEnd && !inParseEntity) { + resume(130); + return false; + } + break; + + case 139: + if (!textBuffer.isEmpty()) { + setType(QXmlStreamReader::Characters); + text = &textBuffer; + } + break; + + case 140: + case 141: + clearSym(); + break; + + case 142: + case 143: + sym(1) = sym(2); + break; + + case 144: + case 145: + case 146: + case 147: + sym(1).len += sym(2).len; + break; + + case 173: + if (normalizeLiterals) + textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); + break; + + case 174: + sym(1).len += fastScanLiteralContent(); + if (atEnd) { + resume(174); + return false; + } + break; + + case 175: { + if (!QXmlUtils::isPublicID(symString(1))) { + raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1))); + resume(175); + return false; + } + } break; + + case 176: + case 177: + clearSym(); + break; + + case 178: + case 179: + sym(1) = sym(2); + break; + + case 180: + case 181: + case 182: + case 183: + sym(1).len += sym(2).len; + break; + + case 213: + case 214: + clearSym(); + break; + + case 215: + case 216: + sym(1) = sym(2); + lastAttributeValue = symString(1); + break; + + case 217: + case 218: + case 219: + case 220: + sym(1).len += sym(2).len; + break; + + case 229: { + QStringRef prefix = symPrefix(1); + if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + namespaceDeclaration.prefix.clear(); + + const QStringRef ns(symString(5)); + if (ns == QLatin1String("http://www.w3.org/2000/xmlns/") || + ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + else + namespaceDeclaration.namespaceUri = addToStringStorage(ns); + } else { + Attribute &attribute = attributeStack.push(); + attribute.key = sym(1); + attribute.value = sym(5); + + QStringRef attributeQualifiedName = symName(1); + bool normalize = false; + for (int a = 0; a < dtdAttributes.size(); ++a) { + DtdAttribute &dtdAttribute = dtdAttributes[a]; + if (!dtdAttribute.isCDATA + && dtdAttribute.tagName == qualifiedName + && dtdAttribute.attributeQualifiedName == attributeQualifiedName + ) { + normalize = true; + break; + } + } + if (normalize) { + // normalize attribute value (simplify and trim) + int pos = textBuffer.size(); + int n = 0; + bool wasSpace = true; + for (int i = 0; i < attribute.value.len; ++i) { + QChar c = textBuffer.at(attribute.value.pos + i); + if (c.unicode() == ' ') { + if (wasSpace) + continue; + wasSpace = true; + } else { + wasSpace = false; + } + textBuffer += textBuffer.at(attribute.value.pos + i); + ++n; + } + if (wasSpace) + while (n && textBuffer.at(pos + n - 1).unicode() == ' ') + --n; + attribute.value.pos = pos; + attribute.value.len = n; + } + if (prefix == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + QStringRef namespacePrefix = symString(attribute.key); + QStringRef namespaceUri = symString(attribute.value); + attributeStack.pop(); + if (((namespacePrefix == QLatin1String("xml")) + ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))) + || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") + || namespaceUri.isEmpty() + || namespacePrefix == QLatin1String("xmlns")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + + namespaceDeclaration.prefix = addToStringStorage(namespacePrefix); + namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); + } + } + } break; + + case 235: { + normalizeLiterals = true; + Tag &tag = tagStack_push(); + prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2)); + name = tag.name = addToStringStorage(symString(2)); + qualifiedName = tag.qualifiedName = addToStringStorage(symName(2)); + if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name)) + raiseWellFormedError(QXmlStream::tr("Invalid XML name.")); + } break; + + case 236: + isEmptyElement = true; + Q_FALLTHROUGH(); + + case 237: + setType(QXmlStreamReader::StartElement); + resolveTag(); + if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) + raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); + hasSeenTag = true; + break; + + case 238: { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + if (qualifiedName != symName(3)) + raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); + } break; + + case 239: + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); + break; + } + setType(QXmlStreamReader::EntityReference); + name = &unresolvedEntity; + break; + + case 240: { + sym(1).len += sym(2).len + 1; + QStringView reference = symView(2); + if (const auto it = entityHash.find(reference); it != entityHash.end()) { + Entity &entity = *it; + if (entity.unparsed) { + raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference)); + } else { + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacement(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference.toString()); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + + injectToken(UNRESOLVED_ENTITY); + unresolvedEntity = symString(2).toString(); + textBuffer.chop(2 + sym(2).len); + clearSym(); + + } break; + + case 241: { + sym(1).len += sym(2).len + 1; + QStringView reference = symView(2); + if (const auto it = parameterEntityHash.find(reference); it != parameterEntityHash.end()) { + referenceToParameterEntityDetected = true; + Entity &entity = *it; + if (entity.unparsed || entity.external) { + referenceToUnparsedEntityDetected = true; + } else { + if (referenceEntity(entity)) + putString(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + } else if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2))); + } + } break; + + case 242: + sym(1).len += sym(2).len + 1; + break; + + case 243: { + sym(1).len += sym(2).len + 1; + QStringView reference = symView(2); + if (const auto it = entityHash.find(reference); it != entityHash.end()) { + Entity &entity = *it; + if (entity.unparsed || entity.value.isNull()) { + raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference)); + break; + } + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacementInAttributeValue(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference.toString()); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference)); + } + } break; + + case 244: { + if (char32_t s = resolveCharRef(3)) { + putStringLiteral(QChar::fromUcs4(s)); + textBuffer.chop(3 + sym(3).len); + clearSym(); + } else { + raiseWellFormedError(QXmlStream::tr("Invalid character reference.")); + } + } break; + + case 247: + case 248: + sym(1).len += sym(2).len; + break; + + case 259: + sym(1).len += fastScanSpace(); + if (atEnd) { + resume(259); + return false; + } + break; + + case 262: { + sym(1).len += fastScanName(&sym(1).prefix); + if (atEnd) { + resume(262); + return false; + } + } break; + + case 263: + sym(1).len += fastScanName(); + if (atEnd) { + resume(263); + return false; + } + break; + + case 264: + case 265: + case 266: + case 267: + case 268: + sym(1).len += fastScanNMTOKEN(); + if (atEnd) { + resume(268); + return false; + } + + break; + + default: + ; + } // switch + act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT); + if (type != QXmlStreamReader::NoToken) + return true; + } else { + parseError(); + break; + } + } + return false; +} + +#endif + +QT_END_NAMESPACE + +#endif + diff --git a/src/corelib/serialization/serialization.pri b/src/corelib/serialization/serialization.pri index 2421903ba7..5e52d82ed6 100644 --- a/src/corelib/serialization/serialization.pri +++ b/src/corelib/serialization/serialization.pri @@ -21,6 +21,8 @@ HEADERS += \ serialization/qtextstream_p.h \ serialization/qxmlstream.h \ serialization/qxmlstream_p.h \ + serialization/qxmlstreamgrammar_p.h \ + serialization/qxmlstreamparser_p.h \ serialization/qxmlutils_p.h SOURCES += \ @@ -37,6 +39,7 @@ SOURCES += \ serialization/qjsonparser.cpp \ serialization/qtextstream.cpp \ serialization/qxmlstream.cpp \ + serialization/qxmlstreamgrammar.cpp \ serialization/qxmlutils.cpp qtConfig(cborstreamreader): { diff --git a/src/tools/bootstrap/.prev_CMakeLists.txt b/src/tools/bootstrap/.prev_CMakeLists.txt index 55d6b53de8..a69351a167 100644 --- a/src/tools/bootstrap/.prev_CMakeLists.txt +++ b/src/tools/bootstrap/.prev_CMakeLists.txt @@ -94,6 +94,7 @@ qt_add_module(Bootstrap ../../corelib/serialization/qjsonwriter.cpp ../../corelib/serialization/qtextstream.cpp ../../corelib/serialization/qxmlstream.cpp + ../../corelib/serialization/qxmlstreamgrammar.cpp ../../corelib/serialization/qxmlutils.cpp ../../corelib/text/qbytearray.cpp ../../corelib/text/qbytearraylist.cpp diff --git a/src/tools/bootstrap/CMakeLists.txt b/src/tools/bootstrap/CMakeLists.txt index 3510c130cc..56b1bcbbcf 100644 --- a/src/tools/bootstrap/CMakeLists.txt +++ b/src/tools/bootstrap/CMakeLists.txt @@ -95,6 +95,7 @@ qt_extend_target(Bootstrap ../../corelib/serialization/qjsonwriter.cpp ../../corelib/serialization/qtextstream.cpp ../../corelib/serialization/qxmlstream.cpp + ../../corelib/serialization/qxmlstreamgrammar.cpp ../../corelib/serialization/qxmlutils.cpp ../../corelib/text/qbytearray.cpp ../../corelib/text/qbytearraylist.cpp diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 11eb659f68..999ceea840 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -82,6 +82,7 @@ SOURCES += \ ../../corelib/serialization/qtextstream.cpp \ ../../corelib/serialization/qxmlutils.cpp \ ../../corelib/serialization/qxmlstream.cpp \ + ../../corelib/serialization/qxmlstreamgrammar.cpp \ ../../corelib/text/qbytearray.cpp \ ../../corelib/text/qbytearraylist.cpp \ ../../corelib/text/qbytearraymatcher.cpp \ -- cgit v1.2.3