123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 | // Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only//// W A R N I N G// -------------//// This file is not part of the Qt API. It exists for the convenience// of other Qt classes. This header file may change from version to// version without notice, or even be removed.//// We mean it.//#include <QtCore/private/qglobal_p.h>#include <qstringconverter.h>#include <qxmlstream.h>#include"qxmlstreamgrammar_p.h"#include <QtCore/qhash.h>#include <QCoreApplication>// Q_DECLARE_TR_FUNCTIONS#include <memory>#include <optional>#ifndef QXMLSTREAM_P_H#define QXMLSTREAM_P_H QT_BEGIN_NAMESPACE namespace QtPrivate {class XmlStringRef {public:const QString *m_string =nullptr; qsizetype m_pos =0; qsizetype m_size =0;constexprXmlStringRef() =default;constexpr inlineXmlStringRef(const QString *string, qsizetype pos, qsizetype length):m_string(string),m_pos(pos),m_size((Q_ASSERT(length >=0), length)){}XmlStringRef(const QString *string):XmlStringRef(string,0, string->size()){}operatorQXmlString()const{if(!m_string)returnQXmlString(); QStringPrivate d = m_string->data_ptr(); d.setBegin(d.data() + m_pos); d.size = m_size;returnQXmlString(std::move(d));}voidclear() { m_string =nullptr; m_pos =0; m_size=0; } QStringView view()const{return m_string ?QStringView(m_string->data() + m_pos, m_size) :QStringView(); }boolisEmpty()const{return m_size ==0; }boolisNull()const{return!m_string; } QString toString()const{returnview().toString(); }using value_type =QStringView::value_type;using size_type =QStringView::size_type;using difference_type =QStringView::difference_type;using pointer =QStringView::pointer;using const_pointer =QStringView::const_pointer;using reference =QStringView::reference;using const_reference =QStringView::const_reference;using iterator =QStringView::iterator;using const_iterator =QStringView::const_iterator;using reverse_iterator =QStringView::reverse_iterator;using const_reverse_iterator =QStringView::const_reverse_iterator;#define MAKE_MEMBER(name) \ auto name () const noexcept { return view(). name (); }MAKE_MEMBER(data)MAKE_MEMBER(size)MAKE_MEMBER(empty)MAKE_MEMBER(begin)MAKE_MEMBER(end)MAKE_MEMBER(cbegin)MAKE_MEMBER(cend)MAKE_MEMBER(rbegin)MAKE_MEMBER(rend)MAKE_MEMBER(crbegin)MAKE_MEMBER(crend)#undef MAKE_MEMBER#define MAKE_OP(op) \ friend auto operator op(const XmlStringRef &lhs, const XmlStringRef &rhs) noexcept { return lhs.view() op rhs.view(); } \/*end*/MAKE_OP(==)MAKE_OP(!=)MAKE_OP(<=)MAKE_OP(>=)MAKE_OP(<)MAKE_OP(>)#undef MAKE_OP#define MAKE_OP(op) \ friend auto operator op(const XmlStringRef &lhs, QStringView rhs) noexcept { return lhs.view() op rhs; } \ friend auto operator op(QStringView lhs, const XmlStringRef &rhs) noexcept { return lhs op rhs.view(); } \/*end*/MAKE_OP(==)MAKE_OP(!=)MAKE_OP(<=)MAKE_OP(>=)MAKE_OP(<)MAKE_OP(>)#undef MAKE_OP};}using namespace QtPrivate;template<typename T>class QXmlStreamSimpleStack {Q_DISABLE_COPY_MOVE(QXmlStreamSimpleStack) T *data; qsizetype tos, cap;public:inlineQXmlStreamSimpleStack():data(nullptr),tos(-1),cap(0){}inline~QXmlStreamSimpleStack(){if(data) {std::destroy_n(data,size());free(data);}}inlinevoidreserve(qsizetype extraCapacity){if(tos + extraCapacity +1> cap) { cap =qMax(tos + extraCapacity +1, cap <<1);void*ptr =realloc(static_cast<void*>(data), cap *sizeof(T)); data =reinterpret_cast<T *>(ptr);Q_CHECK_PTR(data);}}inline T &push() {reserve(1);returnrawPush(); }inline T &rawPush() {return*new(data + (++tos)) T; }inlineconst T &top()const{return data[tos]; }inline T &top() {return data[tos]; }inline T pop() { T t =std::move(data[tos]);std::destroy_at(data + tos); --tos;return t; }inline T &operator[](qsizetype index) {return data[index]; }inlineconst T &at(qsizetype index)const{return data[index]; }inline qsizetype size()const{return tos +1; }inlinevoidresize(qsizetype s) { tos = s -1; }inlineboolisEmpty()const{return tos <0; }inlinevoidclear() { tos = -1; }using const_iterator =const T*;using iterator = T*; T *begin() {return data; }const T *begin()const{return data; }const T *cbegin()const{returnbegin(); } T *end() {return data +size(); }const T *end()const{return data +size(); }const T *cend()const{returnend(); }};class QXmlStream {Q_DECLARE_TR_FUNCTIONS(QXmlStream)};class QXmlStreamPrivateTagStack {public:struct NamespaceDeclaration { XmlStringRef prefix; XmlStringRef namespaceUri;};struct Tag { XmlStringRef name; XmlStringRef qualifiedName; NamespaceDeclaration namespaceDeclaration; qsizetype tagStackStringStorageSize; qsizetype namespaceDeclarationsSize;};QXmlStreamPrivateTagStack(); QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations; QString tagStackStringStorage; qsizetype tagStackStringStorageSize; qsizetype initialTagStackStringStorageSize;bool tagsDone; XmlStringRef addToStringStorage(QAnyStringView s){ qsizetype pos = tagStackStringStorageSize;if(pos != tagStackStringStorage.size()) tagStackStringStorage.resize(pos); s.visit([&](auto s) { tagStackStringStorage.append(s); }); qsizetype sz = (tagStackStringStorage.size() - pos); tagStackStringStorageSize += sz;returnXmlStringRef(&tagStackStringStorage, pos, sz);} QXmlStreamSimpleStack<Tag> 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;}};#if QT_CONFIG(xmlstreamreader)class QXmlStreamEntityResolver;class QXmlStreamReaderPrivate :public QXmlStreamGrammar,public QXmlStreamPrivateTagStack { QXmlStreamReader *q_ptr;Q_DECLARE_PUBLIC(QXmlStreamReader)public:QXmlStreamReaderPrivate(QXmlStreamReader *q);~QXmlStreamReaderPrivate();voidinit(); QByteArray rawReadBuffer; QByteArray dataBuffer; uchar firstByte; qint64 nbytesread; QString readBuffer; qsizetype readBufferPos; QXmlStreamSimpleStack<uint> 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){}staticinline Entity createLiteral(QLatin1StringView name, QLatin1StringView 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<QStringView, Entity> entityHash; QHash<QStringView, Entity> parameterEntityHash;struct QEntityReference { QHash<QStringView, Entity> *hash; QStringView name;}; QXmlStreamSimpleStack<QEntityReference> entityReferenceStack;int entityExpansionLimit =4096;int entityLength =0;inlineboolreferenceEntity(QHash<QStringView, Entity> *hash, Entity &entity){Q_ASSERT(hash);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() = { hash, entity.name };injectToken(ENTITY_DONE);return true;} QIODevice *device;bool deleteDevice; QStringDecoder decoder;bool atEnd;enumclass XmlContext { Prolog, Body,}; XmlContext currentContext =XmlContext::Prolog;bool foundDTD =false;boolisValidToken(QXmlStreamReader::TokenType type);voidcheckToken();/*! \sa setType() */QXmlStreamReader::TokenType type;QXmlStreamReader::Error error; QString errorString; QString unresolvedEntity; qint64 lineNumber, lastLineStart, characterOffset;voidwrite(const QString &);voidwrite(const char*); QXmlStreamAttributes attributes; XmlStringRef namespaceForPrefix(QStringView prefix);voidresolveTag();voidresolvePublicNamespaces();voidresolveDtd(); uint resolveCharRef(int symbolIndex);boolcheckStartDocument();voidstartDocument();voidparseError();voidcheckPublicLiteral(QStringView publicId);bool scanDtd; XmlStringRef lastAttributeValue;bool lastAttributeIsCData;struct DtdAttribute { XmlStringRef tagName; XmlStringRef attributeQualifiedName; XmlStringRef attributePrefix; XmlStringRef attributeName; XmlStringRef defaultValue;bool isCDATA;bool isNamespaceAttribute;}; QXmlStreamSimpleStack<DtdAttribute> dtdAttributes;struct NotationDeclaration { XmlStringRef name; XmlStringRef publicId; XmlStringRef systemId;}; QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations; QXmlStreamNotationDeclarations publicNotationDeclarations; QXmlStreamNamespaceDeclarations publicNamespaceDeclarations;struct EntityDeclaration { XmlStringRef name; XmlStringRef notationName; XmlStringRef publicId; XmlStringRef systemId; XmlStringRef value;bool parameter;bool external;inlinevoidclear() { name.clear(); notationName.clear(); publicId.clear(); systemId.clear(); value.clear(); parameter = external =false;}}; QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations; QXmlStreamEntityDeclarations publicEntityDeclarations; XmlStringRef text; XmlStringRef prefix, namespaceUri, qualifiedName, name; XmlStringRef processingInstructionTarget, processingInstructionData; XmlStringRef dtdName, dtdPublicId, dtdSystemId; XmlStringRef 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; uint hasStandalone :1;// TODO: expose in public APIint resumeReduction;voidresume(int rule);inlineboolentitiesMustBeDeclared()const{return(!inParseEntity && (standalone || (!referenceToUnparsedEntityDetected && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25&& !hasExternalDtdSubset)));}// qlalr parserint tos;int stack_size;struct Value { qsizetype pos;// offset into textBuffer qsizetype len;// length incl. prefix (if any) qint16 prefix;// prefix of a name (as in "prefix:name") limited to 4k in fastScanName() ushort c;}; Value *sym_stack;int*state_stack;inlinevoidreallocateStack();inline Value &sym(int index)const{return sym_stack[tos + index -1]; } QString textBuffer;inlinevoidclearTextBuffer() {if(!scanDtd) { textBuffer.resize(0); textBuffer.reserve(256);}}struct Attribute { Value key; Value value;}; QXmlStreamSimpleStack<Attribute> attributeStack;inline XmlStringRef symString(int index) {const Value &symbol =sym(index);returnXmlStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);} QStringView symView(int index)const{const Value &symbol =sym(index);returnQStringView(textBuffer.data() + symbol.pos, symbol.len).mid(symbol.prefix);}inline XmlStringRef symName(int index) {const Value &symbol =sym(index);returnXmlStringRef(&textBuffer, symbol.pos, symbol.len);}inline XmlStringRef symString(int index,int offset) {const Value &symbol =sym(index);returnXmlStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset);}inline XmlStringRef symPrefix(int index) {const Value &symbol =sym(index);if(symbol.prefix)returnXmlStringRef(&textBuffer, symbol.pos, symbol.prefix -1);returnXmlStringRef();}inline XmlStringRef symString(const Value &symbol) {returnXmlStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);}inline XmlStringRef symName(const Value &symbol) {returnXmlStringRef(&textBuffer, symbol.pos, symbol.len);}inline XmlStringRef symPrefix(const Value &symbol) {if(symbol.prefix)returnXmlStringRef(&textBuffer, symbol.pos, symbol.prefix -1);returnXmlStringRef();}inlinevoidclearSym() { Value &val =sym(1); val.pos = textBuffer.size(); val.len =0; }short token; uint token_char; uint filterCarriageReturn();inline uint getChar();inline uint peekChar();inlinevoidputChar(uint c) { putStack.push() = c; }inlinevoidputChar(QChar c) { putStack.push() = c.unicode(); }voidputString(QStringView s, qsizetype from =0);voidputStringLiteral(QStringView s);voidputReplacement(QStringView s);voidputReplacementInAttributeValue(QStringView s); uint getChar_helper();boolscanUntil(const char*str,short tokenToInject = -1);boolscanString(const char*str,short tokenToInject,bool requireSpace =true);inlinevoidinjectToken(ushort tokenToInject) {putChar(int(tokenToInject) <<16);} QString resolveUndeclaredEntity(const QString &name);voidparseEntity(const QString &value);std::unique_ptr<QXmlStreamReaderPrivate> entityParser;boolscanAfterLangleBang();boolscanPublicOrSystem();boolscanNData();boolscanAfterDefaultDecl();boolscanAttType();// scan optimization functions. Not strictly necessary but LALR is// not very well suited for scanning fast qsizetype fastScanLiteralContent(); qsizetype fastScanSpace(); qsizetype fastScanContentCharList();std::optional<qsizetype>fastScanName(Value *val =nullptr);inline qsizetype fastScanNMTOKEN();boolparse();inlinevoidconsumeRule(int);voidraiseError(QXmlStreamReader::Error error,const QString& message =QString());voidraiseWellFormedError(const QString &message);voidraiseNamePrefixTooLongError(); QXmlStreamEntityResolver *entityResolver;private:/*! \internal Never assign to variable type directly. Instead use this function. This prevents errors from being ignored. */inlinevoidsetType(constQXmlStreamReader::TokenType t){if(type !=QXmlStreamReader::Invalid) type = t;}};#endif// feature xmlstreamreader QT_END_NAMESPACE #endif// QXMLSTREAM_P_H
|