---------------------------------------------------------------------------- -- -- 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$ -- ---------------------------------------------------------------------------- %parser QXmlStreamGrammar %impl qxmlstreamparser_p.h %expect 4 %token NOTOKEN %token SPACE " " %token LANGLE "<" %token RANGLE ">" %token AMPERSAND "&" %token HASH "#" %token QUOTE "\'" %token DBLQUOTE "\"" %token LBRACK "[" %token RBRACK "]" %token LPAREN "(" %token RPAREN ")" %token PIPE "|" %token EQ "=" %token PERCENT "%" %token SLASH "/" %token COLON ":" %token SEMICOLON ";" %token COMMA "," %token DASH "-" %token PLUS "+" %token STAR "*" %token DOT "." %token QUESTIONMARK "?" %token BANG "!" %token LETTER "[a-zA-Z]" %token DIGIT "[0-9]" -- after langle_bang %token CDATA_START "[CDATA[" %token DOCTYPE "DOCTYPE" %token ELEMENT "ELEMENT" %token ATTLIST "ATTLIST" %token ENTITY "ENTITY" %token NOTATION "NOTATION" -- entity decl %token SYSTEM "SYSTEM" %token PUBLIC "PUBLIC" %token NDATA "NDATA" -- default decl %token REQUIRED "REQUIRED" %token IMPLIED "IMPLIED" %token FIXED "FIXED" -- conent spec %token EMPTY "EMPTY" %token ANY "ANY" %token PCDATA "PCDATA" -- error %token ERROR -- entities %token PARSE_ENTITY %token ENTITY_DONE %token UNRESOLVED_ENTITY -- att type %token CDATA "CDATA" %token ID "ID" %token IDREF "IDREF" %token IDREFS "IDREFS" %token ENTITY "ENTITY" %token ENTITIES "ENTITIES" %token NMTOKEN "NMTOKEN" %token NMTOKENS "NMTOKENS" -- xml declaration %token XML " #include #include "qxmlstream_p.h" #include "qxmlutils_p.h" #include #include #ifndef QXMLSTREAMPARSER_P_H #define QXMLSTREAMPARSER_P_H #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) { ./ document ::= PARSE_ENTITY content; /. case $rule_number: setType(QXmlStreamReader::EndDocument); break; ./ document ::= prolog; /. case $rule_number: 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; ./ prolog ::= prolog stag content etag; prolog ::= prolog empty_element_tag; prolog ::= prolog comment; prolog ::= prolog xml_decl; prolog ::= prolog processing_instruction; prolog ::= prolog doctype_decl; prolog ::= prolog SPACE; prolog ::=; entity_done ::= ENTITY_DONE; /. case $rule_number: entityReferenceStack.pop()->isCurrentlyReferenced = false; if (entityReferenceStack.isEmpty()) entityLength = 0; clearSym(); break; ./ xml_decl_start ::= XML; /. case $rule_number: if (!scanString(spell[VERSION], VERSION, false) && atEnd) { resume($rule_number); return false; } break; ./ xml_decl ::= xml_decl_start VERSION space_opt EQ space_opt literal attribute_list_opt QUESTIONMARK RANGLE; /. case $rule_number: setType(QXmlStreamReader::StartDocument); documentVersion = symString(6); startDocument(); break; ./ external_id ::= SYSTEM literal; /. case $rule_number: hasExternalDtdSubset = true; dtdSystemId = symString(2); break; ./ external_id ::= PUBLIC public_literal space literal; /. case $rule_number: checkPublicLiteral(symString(2)); dtdPublicId = symString(2); dtdSystemId = symString(4); hasExternalDtdSubset = true; break; ./ external_id ::=; doctype_decl_start ::= langle_bang DOCTYPE qname space; /. case $rule_number: if (!scanPublicOrSystem() && atEnd) { resume($rule_number); return false; } dtdName = symString(3); break; ./ doctype_decl ::= langle_bang DOCTYPE qname RANGLE; /. case $rule_number:./ doctype_decl ::= langle_bang DOCTYPE qname markup space_opt RANGLE; /. case $rule_number: dtdName = symString(3); Q_FALLTHROUGH(); ./ doctype_decl ::= doctype_decl_start external_id space_opt markup space_opt RANGLE; /. case $rule_number:./ doctype_decl ::= doctype_decl_start external_id space_opt RANGLE; /. case $rule_number: setType(QXmlStreamReader::DTD); text = &textBuffer; break; ./ markup_start ::= LBRACK; /. case $rule_number: scanDtd = true; break; ./ markup ::= markup_start markup_list RBRACK; /. case $rule_number: scanDtd = false; break; ./ markup_list ::= markup_decl | space | pereference; markup_list ::= markup_list markup_decl | markup_list space | markup_list pereference; markup_list ::=; markup_decl ::= element_decl | attlist_decl | entity_decl | entity_done | notation_decl | processing_instruction | comment; element_decl_start ::= langle_bang ELEMENT qname space; /. case $rule_number: if (!scanString(spell[EMPTY], EMPTY, false) && !scanString(spell[ANY], ANY, false) && atEnd) { resume($rule_number); return false; } break; ./ element_decl ::= element_decl_start content_spec space_opt RANGLE; content_spec ::= EMPTY | ANY | mixed | children; pcdata_start ::= HASH; /. case $rule_number: if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { resume($rule_number); return false; } break; ./ pcdata ::= pcdata_start PCDATA; questionmark_or_star_or_plus_opt ::= QUESTIONMARK | STAR | PLUS; questionmark_or_star_or_plus_opt ::=; cp ::= qname questionmark_or_star_or_plus_opt | choice_or_seq questionmark_or_star_or_plus_opt; cp_pipe_or_comma_list ::= cp space_opt; cp_pipe_or_comma_list ::= cp space_opt PIPE space_opt cp_pipe_list space_opt; cp_pipe_or_comma_list ::= cp space_opt COMMA space_opt cp_comma_list space_opt; cp_pipe_list ::= cp | cp_pipe_list space_opt PIPE space_opt cp; cp_comma_list ::= cp | cp_comma_list space_opt COMMA space_opt cp; name_pipe_list ::= PIPE space_opt qname; name_pipe_list ::= name_pipe_list space_opt PIPE space_opt qname; star_opt ::= | STAR; mixed ::= LPAREN space_opt pcdata space_opt RPAREN star_opt; mixed ::= LPAREN space_opt pcdata space_opt name_pipe_list space_opt RPAREN STAR; choice_or_seq ::= LPAREN space_opt cp_pipe_or_comma_list RPAREN; children ::= choice_or_seq questionmark_or_star_or_plus_opt; nmtoken_pipe_list ::= nmtoken; nmtoken_pipe_list ::= nmtoken_pipe_list space_opt PIPE space_opt nmtoken; att_type ::= CDATA; /. case $rule_number: { lastAttributeIsCData = true; } break; ./ att_type ::= ID | IDREF | IDREFS | ENTITY | ENTITIES | NMTOKEN | NMTOKENS; att_type ::= LPAREN space_opt nmtoken_pipe_list space_opt RPAREN space; att_type ::= NOTATION LPAREN space_opt nmtoken_pipe_list space_opt RPAREN space; default_declhash ::= HASH; /. case $rule_number: if (!scanAfterDefaultDecl() && atEnd) { resume($rule_number); return false; } break; ./ default_decl ::= default_declhash REQUIRED; default_decl ::= default_declhash IMPLIED; default_decl ::= attribute_value; default_decl ::= default_declhash FIXED space attribute_value; attdef_start ::= space qname space; /. case $rule_number: sym(1) = sym(2); lastAttributeValue.clear(); lastAttributeIsCData = false; if (!scanAttType() && atEnd) { resume($rule_number); return false; } break; ./ attdef ::= attdef_start att_type default_decl; /. case $rule_number: { 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; ./ attdef_list ::= attdef; attdef_list ::= attdef_list attdef; attlist_decl ::= langle_bang ATTLIST qname space_opt RANGLE; attlist_decl ::= langle_bang ATTLIST qname attdef_list space_opt RANGLE; /. case $rule_number: { if (referenceToUnparsedEntityDetected && !standalone) break; int n = dtdAttributes.size(); XmlStringRef 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; ./ entity_decl_start ::= langle_bang ENTITY name space; /. case $rule_number: { if (!scanPublicOrSystem() && atEnd) { resume($rule_number); return false; } EntityDeclaration &entityDeclaration = entityDeclarations.push(); entityDeclaration.clear(); entityDeclaration.name = symString(3); } break; ./ entity_decl_start ::= langle_bang ENTITY PERCENT space name space; /. case $rule_number: { if (!scanPublicOrSystem() && atEnd) { resume($rule_number); return false; } EntityDeclaration &entityDeclaration = entityDeclarations.push(); entityDeclaration.clear(); entityDeclaration.name = symString(5); entityDeclaration.parameter = true; } break; ./ entity_decl_external ::= entity_decl_start SYSTEM literal; /. case $rule_number: { if (!scanNData() && atEnd) { resume($rule_number); return false; } EntityDeclaration &entityDeclaration = entityDeclarations.top(); entityDeclaration.systemId = symString(3); entityDeclaration.external = true; } break; ./ entity_decl_external ::= entity_decl_start PUBLIC public_literal space literal; /. case $rule_number: { if (!scanNData() && atEnd) { resume($rule_number); return false; } EntityDeclaration &entityDeclaration = entityDeclarations.top(); checkPublicLiteral((entityDeclaration.publicId = symString(3))); entityDeclaration.systemId = symString(5); entityDeclaration.external = true; } break; ./ entity_decl ::= entity_decl_external NDATA name space_opt RANGLE; /. case $rule_number: { EntityDeclaration &entityDeclaration = entityDeclarations.top(); entityDeclaration.notationName = symString(3); if (entityDeclaration.parameter) raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); } Q_FALLTHROUGH(); ./ entity_decl ::= entity_decl_external space_opt RANGLE; /. case $rule_number:./ entity_decl ::= entity_decl_start entity_value space_opt RANGLE; /. case $rule_number: { 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(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; ./ processing_instruction ::= LANGLE QUESTIONMARK name space; /. case $rule_number: { setType(QXmlStreamReader::ProcessingInstruction); int pos = sym(4).pos + sym(4).len; processingInstructionTarget = symString(3); if (scanUntil("?>")) { processingInstructionData = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); if (!processingInstructionTarget.view().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($rule_number); return false; } } break; ./ processing_instruction ::= LANGLE QUESTIONMARK name QUESTIONMARK RANGLE; /. case $rule_number: setType(QXmlStreamReader::ProcessingInstruction); processingInstructionTarget = symString(3); if (!processingInstructionTarget.view().compare(QLatin1String("xml"), Qt::CaseInsensitive)) raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); break; ./ langle_bang ::= LANGLE BANG; /. case $rule_number: if (!scanAfterLangleBang() && atEnd) { resume($rule_number); return false; } break; ./ comment_start ::= langle_bang DASH DASH; /. case $rule_number: if (!scanUntil("--")) { resume($rule_number); return false; } break; ./ comment ::= comment_start RANGLE; /. case $rule_number: { setType(QXmlStreamReader::Comment); int pos = sym(1).pos + 4; text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); } break; ./ cdata ::= langle_bang CDATA_START; /. case $rule_number: { setType(QXmlStreamReader::Characters); isCDATA = true; isWhitespace = false; int pos = sym(2).pos; if (scanUntil("]]>", -1)) { text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); } else { resume($rule_number); return false; } } break; ./ notation_decl_start ::= langle_bang NOTATION name space; /. case $rule_number: { if (!scanPublicOrSystem() && atEnd) { resume($rule_number); return false; } NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); notationDeclaration.name = symString(3); } break; ./ notation_decl ::= notation_decl_start SYSTEM literal space_opt RANGLE; /. case $rule_number: { NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); notationDeclaration.systemId = symString(3); notationDeclaration.publicId.clear(); } break; ./ notation_decl ::= notation_decl_start PUBLIC public_literal space_opt RANGLE; /. case $rule_number: { NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); notationDeclaration.systemId.clear(); checkPublicLiteral((notationDeclaration.publicId = symString(3))); } break; ./ notation_decl ::= notation_decl_start PUBLIC public_literal space literal space_opt RANGLE; /. case $rule_number: { NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); checkPublicLiteral((notationDeclaration.publicId = symString(3))); notationDeclaration.systemId = symString(5); } break; ./ content_char ::= RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | PERCENT | SLASH | COLON | SEMICOLON | COMMA | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG | QUOTE | DBLQUOTE | LETTER | DIGIT; scan_content_char ::= content_char; /. case $rule_number: isWhitespace = false; Q_FALLTHROUGH(); ./ scan_content_char ::= SPACE; /. case $rule_number: sym(1).len += fastScanContentCharList(); if (atEnd && !inParseEntity) { resume($rule_number); return false; } break; ./ content_char_list ::= content_char_list char_ref; content_char_list ::= content_char_list entity_ref; content_char_list ::= content_char_list entity_done; content_char_list ::= content_char_list scan_content_char; content_char_list ::= char_ref; content_char_list ::= entity_ref; content_char_list ::= entity_done; content_char_list ::= scan_content_char; character_content ::= content_char_list %prec SHIFT_THERE; /. case $rule_number: if (!textBuffer.isEmpty()) { setType(QXmlStreamReader::Characters); text = &textBuffer; } break; ./ literal ::= QUOTE QUOTE; /. case $rule_number:./ literal ::= DBLQUOTE DBLQUOTE; /. case $rule_number: clearSym(); break; ./ literal ::= QUOTE literal_content_with_dblquote QUOTE; /. case $rule_number:./ literal ::= DBLQUOTE literal_content_with_quote DBLQUOTE; /. case $rule_number: sym(1) = sym(2); break; ./ literal_content_with_dblquote ::= literal_content_with_dblquote literal_content; /. case $rule_number:./ literal_content_with_quote ::= literal_content_with_quote literal_content; /. case $rule_number:./ literal_content_with_dblquote ::= literal_content_with_dblquote DBLQUOTE; /. case $rule_number:./ literal_content_with_quote ::= literal_content_with_quote QUOTE; /. case $rule_number: sym(1).len += sym(2).len; break; ./ literal_content_with_dblquote ::= literal_content; literal_content_with_quote ::= literal_content; literal_content_with_dblquote ::= DBLQUOTE; literal_content_with_quote ::= QUOTE; literal_content_start ::= LETTER | DIGIT | RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | PERCENT | SLASH | COLON | SEMICOLON | COMMA | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG; literal_content_start ::= SPACE; /. case $rule_number: if (normalizeLiterals) textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); break; ./ literal_content ::= literal_content_start; /. case $rule_number: sym(1).len += fastScanLiteralContent(); if (atEnd) { resume($rule_number); return false; } break; ./ public_literal ::= literal; /. case $rule_number: { if (!QXmlUtils::isPublicID(symString(1))) { raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1))); resume($rule_number); return false; } } break; ./ entity_value ::= QUOTE QUOTE; /. case $rule_number:./ entity_value ::= DBLQUOTE DBLQUOTE; /. case $rule_number: clearSym(); break; ./ entity_value ::= QUOTE entity_value_content_with_dblquote QUOTE; /. case $rule_number:./ entity_value ::= DBLQUOTE entity_value_content_with_quote DBLQUOTE; /. case $rule_number: sym(1) = sym(2); break; ./ entity_value_content_with_dblquote ::= entity_value_content_with_dblquote entity_value_content; /. case $rule_number:./ entity_value_content_with_quote ::= entity_value_content_with_quote entity_value_content; /. case $rule_number:./ entity_value_content_with_dblquote ::= entity_value_content_with_dblquote DBLQUOTE; /. case $rule_number:./ entity_value_content_with_quote ::= entity_value_content_with_quote QUOTE; /. case $rule_number: sym(1).len += sym(2).len; break; ./ entity_value_content_with_dblquote ::= entity_value_content; entity_value_content_with_quote ::= entity_value_content; entity_value_content_with_dblquote ::= DBLQUOTE; entity_value_content_with_quote ::= QUOTE; entity_value_content ::= LETTER | DIGIT | LANGLE | RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | SLASH | COLON | SEMICOLON | COMMA | SPACE | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG; entity_value_content ::= char_ref | entity_ref_in_entity_value | entity_done; attribute_value ::= QUOTE QUOTE; /. case $rule_number:./ attribute_value ::= DBLQUOTE DBLQUOTE; /. case $rule_number: clearSym(); break; ./ attribute_value ::= QUOTE attribute_value_content_with_dblquote QUOTE; /. case $rule_number:./ attribute_value ::= DBLQUOTE attribute_value_content_with_quote DBLQUOTE; /. case $rule_number: sym(1) = sym(2); lastAttributeValue = symString(1); break; ./ attribute_value_content_with_dblquote ::= attribute_value_content_with_dblquote attribute_value_content; /. case $rule_number:./ attribute_value_content_with_quote ::= attribute_value_content_with_quote attribute_value_content; /. case $rule_number:./ attribute_value_content_with_dblquote ::= attribute_value_content_with_dblquote DBLQUOTE; /. case $rule_number:./ attribute_value_content_with_quote ::= attribute_value_content_with_quote QUOTE; /. case $rule_number: sym(1).len += sym(2).len; break; ./ attribute_value_content_with_dblquote ::= attribute_value_content | DBLQUOTE; attribute_value_content_with_quote ::= attribute_value_content | QUOTE; attribute_value_content ::= literal_content | char_ref | entity_ref_in_attribute_value | entity_done; attribute ::= qname space_opt EQ space_opt attribute_value; /. case $rule_number: { XmlStringRef prefix = symPrefix(1); if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); namespaceDeclaration.prefix.clear(); const XmlStringRef ns(symString(5)); if (ns.view() == QLatin1String("http://www.w3.org/2000/xmlns/") || ns.view() == 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); XmlStringRef 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(); XmlStringRef namespacePrefix = symString(attribute.key); XmlStringRef 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; ./ attribute_list_opt ::= | space | space attribute_list space_opt; attribute_list ::= attribute | attribute_list space attribute; stag_start ::= LANGLE qname; /. case $rule_number: { 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; ./ empty_element_tag ::= stag_start attribute_list_opt SLASH RANGLE; /. case $rule_number: isEmptyElement = true; Q_FALLTHROUGH(); ./ stag ::= stag_start attribute_list_opt RANGLE; /. case $rule_number: setType(QXmlStreamReader::StartElement); resolveTag(); if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); hasSeenTag = true; break; ./ etag ::= LANGLE SLASH qname space_opt RANGLE; /. case $rule_number: { 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; ./ unresolved_entity ::= UNRESOLVED_ENTITY; /. case $rule_number: if (entitiesMustBeDeclared()) { raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); break; } setType(QXmlStreamReader::EntityReference); name = &unresolvedEntity; break; ./ entity_ref ::= AMPERSAND name SEMICOLON; /. case $rule_number: { 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; ./ pereference ::= PERCENT name SEMICOLON; /. case $rule_number: { 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; ./ entity_ref_in_entity_value ::= AMPERSAND name SEMICOLON; /. case $rule_number: sym(1).len += sym(2).len + 1; break; ./ entity_ref_in_attribute_value ::= AMPERSAND name SEMICOLON; /. case $rule_number: { 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; ./ char_ref ::= AMPERSAND HASH char_ref_value SEMICOLON; /. case $rule_number: { 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; ./ char_ref_value ::= LETTER | DIGIT; char_ref_value ::= char_ref_value LETTER; /. case $rule_number:./ char_ref_value ::= char_ref_value DIGIT; /. case $rule_number: sym(1).len += sym(2).len; break; ./ content ::= content character_content; content ::= content stag content etag; content ::= content empty_element_tag; content ::= content comment; content ::= content cdata; content ::= content xml_decl; content ::= content processing_instruction; content ::= content doctype_decl; content ::= content unresolved_entity; content ::= ; space ::= SPACE; /. case $rule_number: sym(1).len += fastScanSpace(); if (atEnd) { resume($rule_number); return false; } break; ./ space_opt ::=; space_opt ::= space; qname ::= LETTER; /. case $rule_number: { sym(1).len += fastScanName(&sym(1).prefix); if (atEnd) { resume($rule_number); return false; } } break; ./ name ::= LETTER; /. case $rule_number: sym(1).len += fastScanName(); if (atEnd) { resume($rule_number); return false; } break; ./ nmtoken ::= LETTER; /. case $rule_number:./ nmtoken ::= DIGIT; /. case $rule_number:./ nmtoken ::= DOT; /. case $rule_number:./ nmtoken ::= DASH; /. case $rule_number:./ nmtoken ::= COLON; /. case $rule_number: sym(1).len += fastScanNMTOKEN(); if (atEnd) { resume($rule_number); 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 #endif ./