Revision control

++ // 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
++ // Qt-Security score:critical reason:data-parser
++
++ #include "qxml.h"
++ #include "qxml_p.h"
++ #if QT_CONFIG(textcodec)
++ #include "qtextcodec.h"
++ #endif
++ #include "qbuffer.h"
++ #if QT_CONFIG(regularexpression)
++ #include "qregularexpression.h"
++ #endif
++ #include "qmap.h"
++ #include "qhash.h"
++ #include "qstack.h"
++ #include <QtCore/qvarlengtharray.h>
++ #include <qdebug.h>
++
++ #include <climits>
++
++ #ifdef Q_CC_BOR // borland 6 finds bogus warnings when building this file in uic3
++ # pragma warn -8080
++ #endif
++
++ //#define QT_QXML_DEBUG
++
++ // Error strings for the XML reader
++ #define XMLERR_OK QT_TRANSLATE_NOOP("QXml", "no error occurred")
++ #define XMLERR_ERRORBYCONSUMER QT_TRANSLATE_NOOP("QXml", "error triggered by consumer")
++ #define XMLERR_UNEXPECTEDEOF QT_TRANSLATE_NOOP("QXml", "unexpected end of file")
++ #define XMLERR_MORETHANONEDOCTYPE QT_TRANSLATE_NOOP("QXml", "more than one document type definition")
++ #define XMLERR_ERRORPARSINGELEMENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing element")
++ #define XMLERR_TAGMISMATCH QT_TRANSLATE_NOOP("QXml", "tag mismatch")
++ #define XMLERR_ERRORPARSINGCONTENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing content")
++ #define XMLERR_UNEXPECTEDCHARACTER QT_TRANSLATE_NOOP("QXml", "unexpected character")
++ #define XMLERR_INVALIDNAMEFORPI QT_TRANSLATE_NOOP("QXml", "invalid name for processing instruction")
++ #define XMLERR_VERSIONEXPECTED QT_TRANSLATE_NOOP("QXml", "version expected while reading the XML declaration")
++ #define XMLERR_WRONGVALUEFORSDECL QT_TRANSLATE_NOOP("QXml", "wrong value for standalone declaration")
++ #define XMLERR_EDECLORSDDECLEXPECTED QT_TRANSLATE_NOOP("QXml", "encoding declaration or standalone declaration expected while reading the XML declaration")
++ #define XMLERR_SDDECLEXPECTED QT_TRANSLATE_NOOP("QXml", "standalone declaration expected while reading the XML declaration")
++ #define XMLERR_ERRORPARSINGDOCTYPE QT_TRANSLATE_NOOP("QXml", "error occurred while parsing document type definition")
++ #define XMLERR_LETTEREXPECTED QT_TRANSLATE_NOOP("QXml", "letter is expected")
++ #define XMLERR_ERRORPARSINGCOMMENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing comment")
++ #define XMLERR_ERRORPARSINGREFERENCE QT_TRANSLATE_NOOP("QXml", "error occurred while parsing reference")
++ #define XMLERR_INTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "internal general entity reference not allowed in DTD")
++ #define XMLERR_EXTERNALGENERALENTITYINAV QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in attribute value")
++ #define XMLERR_EXTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in DTD")
++ #define XMLERR_UNPARSEDENTITYREFERENCE QT_TRANSLATE_NOOP("QXml", "unparsed entity reference in wrong context")
++ #define XMLERR_RECURSIVEENTITIES QT_TRANSLATE_NOOP("QXml", "recursive entities")
++ #define XMLERR_ERRORINTEXTDECL QT_TRANSLATE_NOOP("QXml", "error in the text declaration of an external entity")
++
++ QT_BEGIN_NAMESPACE
++
++ namespace {
++
++ // work around missing std::stack::clear()
++ template <typename Container>
++ void clear(Container &c) { c = Container(); }
++
++ }
++
++ // the constants for the lookup table
++ static const signed char cltWS = 0; // white space
++ static const signed char cltPer = 1; // %
++ static const signed char cltAmp = 2; // &
++ static const signed char cltGt = 3; // >
++ static const signed char cltLt = 4; // <
++ static const signed char cltSlash = 5; // /
++ static const signed char cltQm = 6; // ?
++ static const signed char cltEm = 7; // !
++ static const signed char cltDash = 8; // -
++ static const signed char cltCB = 9; // ]
++ static const signed char cltOB = 10; // [
++ static const signed char cltEq = 11; // =
++ static const signed char cltDq = 12; // "
++ static const signed char cltSq = 13; // '
++ static const signed char cltUnknown = 14;
++
++ // character lookup table
++ static const signed char charLookupTable[256]={
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07
++ cltUnknown, // 0x08
++ cltWS, // 0x09 \t
++ cltWS, // 0x0A \n
++ cltUnknown, // 0x0B
++ cltUnknown, // 0x0C
++ cltWS, // 0x0D \r
++ cltUnknown, // 0x0E
++ cltUnknown, // 0x0F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F
++ cltWS, // 0x20 Space
++ cltEm, // 0x21 !
++ cltDq, // 0x22 "
++ cltUnknown, // 0x23
++ cltUnknown, // 0x24
++ cltPer, // 0x25 %
++ cltAmp, // 0x26 &
++ cltSq, // 0x27 '
++ cltUnknown, // 0x28
++ cltUnknown, // 0x29
++ cltUnknown, // 0x2A
++ cltUnknown, // 0x2B
++ cltUnknown, // 0x2C
++ cltDash, // 0x2D -
++ cltUnknown, // 0x2E
++ cltSlash, // 0x2F /
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37
++ cltUnknown, // 0x38
++ cltUnknown, // 0x39
++ cltUnknown, // 0x3A
++ cltUnknown, // 0x3B
++ cltLt, // 0x3C <
++ cltEq, // 0x3D =
++ cltGt, // 0x3E >
++ cltQm, // 0x3F ?
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57
++ cltUnknown, // 0x58
++ cltUnknown, // 0x59
++ cltUnknown, // 0x5A
++ cltOB, // 0x5B [
++ cltUnknown, // 0x5C
++ cltCB, // 0x5D]
++ cltUnknown, // 0x5E
++ cltUnknown, // 0x5F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7
++ cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown // 0xF8 - 0xFF
++ };
++
++ //
++ // local helper functions
++ //
++
++ /*
++ This function strips the TextDecl [77] ("<?xml ...?>") from the string \a
++ str. The stripped version is stored in \a str. If this function finds an
++ invalid TextDecl, it returns \c false, otherwise true.
++
++ This function is used for external entities since those can include an
++ TextDecl that must be stripped before inserting the entity.
++ */
++ static bool stripTextDecl(QString& str)
++ {
++ QLatin1String textDeclStart("<?xml");
++ if (str.startsWith(textDeclStart)) {
++ #if QT_CONFIG(regularexpression)
++ QRegularExpression textDecl(QString::fromLatin1(
++ "^<\\?xml\\s+"
++ "(version\\s*=\\s*((['\"])[-a-zA-Z0-9_.:]+\\3))?"
++ "\\s*"
++ "(encoding\\s*=\\s*((['\"])[A-Za-z][-a-zA-Z0-9_.]*\\6))?"
++ "\\s*\\?>"
++ ));
++ QString strTmp = str.replace(textDecl, QLatin1String(""));
++ if (strTmp.size() != str.size())
++ return false; // external entity has wrong TextDecl
++ str = strTmp;
++ #else
++ return false;
++ #endif
++ }
++ return true;
++ }
++
++ /* \class QXmlInputSourcePrivate
++ \internal
++
++ There's a slight misdesign in this class that can
++ be worth to keep in mind: the `str' member is
++ a buffer which QXmlInputSource::next() returns from,
++ and which is populated from the input device or input
++ stream. However, when the input is a QString(the user called
++ QXmlInputSource::setData()), `str' has two roles: it's the
++ buffer, but also the source. This /seems/ to be no problem
++ because in the case of having no device or stream, the QString
++ is read in one go.
++ */
++ class QXmlInputSourcePrivate
++ {
++ public:
++ QIODevice *inputDevice;
++ QTextStream *inputStream;
++
++ QString str;
++ const QChar *unicode;
++ qsizetype pos;
++ qsizetype length;
++ bool nextReturnedEndOfData;
++ #if QT_CONFIG(textcodec)
++ QTextDecoder *encMapper;
++ #endif
++
++ QByteArray encodingDeclBytes;
++ QString encodingDeclChars;
++ bool lookingForEncodingDecl;
++ };
++
++ class QXmlParseExceptionPrivate
++ {
++ public:
++ QString msg;
++ int column = -1;
++ int line = -1;
++ QString pub;
++ QString sys;
++
++ };
++
++ class QXmlLocatorPrivate
++ {
++ };
++
++ /*!
++ \class QXmlParseException
++ \reentrant
++ \brief The QXmlParseException class is used to report errors with
++ the QXmlErrorHandler interface.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ The XML subsystem constructs an instance of this class when it
++ detects an error. You can retrieve the place where the error
++ occurred using systemId(), publicId(), lineNumber() and
++ columnNumber(), along with the error message(). The possible error
++ messages are:
++
++ \list
++ \li "no error occurred"
++ \li "error triggered by consumer"
++ \li "unexpected end of file"
++ \li "more than one document type definition"
++ \li "error occurred while parsing element"
++ \li "tag mismatch"
++ \li "error occurred while parsing content"
++ \li "unexpected character"
++ \li "invalid name for processing instruction"
++ \li "version expected while reading the XML declaration"
++ \li "wrong value for standalone declaration"
++ \li "encoding declaration or standalone declaration expected while reading the XML declaration"
++ \li "standalone declaration expected while reading the XML declaration"
++ \li "error occurred while parsing document type definition"
++ \li "letter is expected"
++ \li "error occurred while parsing comment"
++ \li "error occurred while parsing reference"
++ \li "internal general entity reference not allowed in DTD"
++ \li "external parsed general entity reference not allowed in attribute value"
++ \li "external parsed general entity reference not allowed in DTD"
++ \li "unparsed entity reference n wrong context"
++ \li "recursive entities"
++ \li "error in the text declaration of an external entity"
++ \endlist
++
++ Note that, if you want to display these error messages to your
++ application's users, they will be displayed in English unless
++ they are explicitly translated.
++
++ \sa QXmlErrorHandler, QXmlReader
++ */
++
++ /*!
++ Constructs a parse exception with the error string \a name for
++ column \a c and line \a l for the public identifier \a p and the
++ system identifier \a s.
++ */
++
++ QXmlParseException::QXmlParseException(const QString& name, int c, int l,
++ const QString& p, const QString& s)
++ : d(new QXmlParseExceptionPrivate)
++ {
++ d->msg = name;
++ d->column = c;
++ d->line = l;
++ d->pub = p;
++ d->sys = s;
++ }
++
++ /*!
++ Creates a copy of \a other.
++ */
++ QXmlParseException::QXmlParseException(const QXmlParseException& other) :
++ d(new QXmlParseExceptionPrivate(*other.d))
++ {
++
++ }
++
++ /*!
++ Destroys the QXmlParseException.
++ */
++ QXmlParseException::~QXmlParseException()
++ {
++ }
++
++ /*!
++ Returns the error message.
++ */
++ QString QXmlParseException::message() const
++ {
++ return d->msg;
++ }
++ /*!
++ Returns the column number where the error occurred.
++ */
++ int QXmlParseException::columnNumber() const
++ {
++ return d->column;
++ }
++ /*!
++ Returns the line number where the error occurred.
++ */
++ int QXmlParseException::lineNumber() const
++ {
++ return d->line;
++ }
++ /*!
++ Returns the public identifier where the error occurred.
++ */
++ QString QXmlParseException::publicId() const
++ {
++ return d->pub;
++ }
++ /*!
++ Returns the system identifier where the error occurred.
++ */
++ QString QXmlParseException::systemId() const
++ {
++ return d->sys;
++ }
++
++ /*!
++ \class QXmlLocator
++ \reentrant
++ \brief The QXmlLocator class provides the XML handler classes with
++ information about the parsing position within a file.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ The reader reports a QXmlLocator to the content handler before it
++ starts to parse the document. This is done with the
++ QXmlContentHandler::setDocumentLocator() function. The handler
++ classes can now use this locator to get the position (lineNumber()
++ and columnNumber()) that the reader has reached.
++ */
++
++ /*!
++ Constructor.
++ */
++ QXmlLocator::QXmlLocator()
++ {
++ }
++
++ /*!
++ Destructor.
++ */
++ QXmlLocator::~QXmlLocator()
++ {
++ }
++
++ /*!
++ \fn int QXmlLocator::columnNumber() const
++
++ Returns the column number (starting at 1) or -1 if there is no
++ column number available.
++ */
++
++ /*!
++ \fn int QXmlLocator::lineNumber() const
++
++ Returns the line number (starting at 1) or -1 if there is no line
++ number available.
++ */
++
++ /*
++ The public API returns position as int.
++ Returns the value + 1, since human-readable line and column numbers start
++ from 1.
++
++ Report -1 if the value does not fit into the int range, in line with the
++ columnNumber() and lineNumber() docs.
++ */
++ static int reportedPosition(qsizetype position)
++ {
++ if (position >= INT_MAX - 1)
++ return -1;
++ return int(position + 1);
++ }
++
++ class QXmlSimpleReaderLocator : public QXmlLocator
++ {
++ public:
++ QXmlSimpleReaderLocator(QXmlSimpleReader* parent)
++ {
++ reader = parent;
++ }
++ ~QXmlSimpleReaderLocator()
++ {
++ }
++
++ int columnNumber() const override
++ {
++ return (reader->d_ptr->columnNr == -1 ? -1 : reportedPosition(reader->d_ptr->columnNr));
++ }
++ int lineNumber() const override
++ {
++ return (reader->d_ptr->lineNr == -1 ? -1 : reportedPosition(reader->d_ptr->lineNr));
++ }
++
++ private:
++ QXmlSimpleReader *reader;
++ };
++
++ /*********************************************
++ *
++ * QXmlNamespaceSupport
++ *
++ *********************************************/
++
++ typedef QMap<QString, QString> NamespaceMap;
++
++ class QXmlNamespaceSupportPrivate
++ {
++ public:
++ QXmlNamespaceSupportPrivate()
++ {
++ ns.insert(QLatin1String("xml"), QLatin1String("http://www.w3.org/XML/1998/namespace")); // the XML namespace
++ }
++
++ ~QXmlNamespaceSupportPrivate()
++ {
++ }
++
++ QStack<NamespaceMap> nsStack;
++ NamespaceMap ns;
++ };
++
++ /*!
++ \class QXmlNamespaceSupport
++ \since 4.4
++ \reentrant
++ \brief The QXmlNamespaceSupport class is a helper class for XML
++ readers which want to include namespace support.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ You can set the prefix for the current namespace with setPrefix(),
++ and get the list of current prefixes (or those for a given URI)
++ with prefixes(). The namespace URI is available from uri(). Use
++ pushContext() to start a new namespace context, and popContext()
++ to return to the previous namespace context. Use splitName() or
++ processName() to split a name into its prefix and local name.
++ */
++
++ /*!
++ Constructs a QXmlNamespaceSupport.
++ */
++ QXmlNamespaceSupport::QXmlNamespaceSupport()
++ {
++ d = new QXmlNamespaceSupportPrivate;
++ }
++
++ /*!
++ Destroys a QXmlNamespaceSupport.
++ */
++ QXmlNamespaceSupport::~QXmlNamespaceSupport()
++ {
++ delete d;
++ }
++
++ /*!
++ This function declares a prefix \a pre in the current namespace
++ context to be the namespace URI \a uri. The prefix remains in
++ force until this context is popped, unless it is shadowed in a
++ descendant context.
++
++ Note that there is an asymmetry in this library. prefix() does not
++ return the default "" prefix, even if you have declared one; to
++ check for a default prefix, you must look it up explicitly using
++ uri(). This asymmetry exists to make it easier to look up prefixes
++ for attribute names, where the default prefix is not allowed.
++ */
++ void QXmlNamespaceSupport::setPrefix(const QString& pre, const QString& uri)
++ {
++ if (pre.isNull()) {
++ d->ns.insert(QLatin1String(""), uri);
++ } else {
++ d->ns.insert(pre, uri);
++ }
++ }
++
++ /*!
++ Returns one of the prefixes mapped to the namespace URI \a uri.
++
++ If more than one prefix is currently mapped to the same URI, this
++ function makes an arbitrary selection; if you want all of the
++ prefixes, use prefixes() instead.
++
++ Note: to check for a default prefix, use the uri() function with
++ an argument of "".
++ */
++ QString QXmlNamespaceSupport::prefix(const QString& uri) const
++ {
++ NamespaceMap::const_iterator itc, it = d->ns.constBegin();
++ while ((itc=it) != d->ns.constEnd()) {
++ ++it;
++ if (*itc == uri && !itc.key().isEmpty())
++ return itc.key();
++ }
++ return QLatin1String("");
++ }
++
++ /*!
++ Looks up the prefix \a prefix in the current context and returns
++ the currently-mapped namespace URI. Use the empty string ("") for
++ the default namespace.
++ */
++ QString QXmlNamespaceSupport::uri(const QString& prefix) const
++ {
++ return d->ns[prefix];
++ }
++
++ /*!
++ Splits the name \a qname at the ':' and returns the prefix in \a
++ prefix and the local name in \a localname.
++
++ \sa processName()
++ */
++ void QXmlNamespaceSupport::splitName(const QString& qname, QString& prefix,
++ QString& localname) const
++ {
++ auto pos = qname.indexOf(u':');
++ if (pos == -1)
++ pos = qname.size();
++
++ prefix = qname.left(pos);
++ localname = qname.mid(pos+1);
++ }
++
++ /*!
++ Processes a raw XML 1.0 name in the current context by removing
++ the prefix and looking it up among the prefixes currently
++ declared.
++
++ \a qname is the raw XML 1.0 name to be processed. \a isAttribute
++ is true if the name is an attribute name.
++
++ This function stores the namespace URI in \a nsuri (which will be
++ set to an empty string if the raw name has an undeclared prefix),
++ and stores the local name (without prefix) in \a localname (which
++ will be set to an empty string if no namespace is in use).
++
++ Note that attribute names are processed differently than element
++ names: an unprefixed element name gets the default namespace (if
++ any), while an unprefixed attribute name does not.
++ */
++ void QXmlNamespaceSupport::processName(const QString& qname,
++ bool isAttribute,
++ QString& nsuri, QString& localname) const
++ {
++ if (const auto pos = qname.indexOf(u':'); pos >= 0) {
++ nsuri = uri(qname.left(pos));
++ localname = qname.mid(pos + 1);
++ return;
++ }
++
++ // there was no ':'
++ nsuri.clear();
++ // attributes don't take default namespace
++ if (!isAttribute && !d->ns.isEmpty()) {
++ /*
++ We want to access d->ns.value(""), but as an optimization
++ we use the fact that "" compares less than any other
++ string, so it's either first in the map or not there.
++ */
++ NamespaceMap::const_iterator first = d->ns.constBegin();
++ if (first.key().isEmpty())
++ nsuri = first.value(); // get default namespace
++ }
++ localname = qname;
++ }
++
++ /*!
++ Returns a list of all the prefixes currently declared.
++
++ If there is a default prefix, this function does not return it in
++ the list; check for the default prefix using uri() with an
++ argument of "".
++ */
++ QStringList QXmlNamespaceSupport::prefixes() const
++ {
++ QStringList list;
++
++ NamespaceMap::const_iterator itc, it = d->ns.constBegin();
++ while ((itc=it) != d->ns.constEnd()) {
++ ++it;
++ if (!itc.key().isEmpty())
++ list.append(itc.key());
++ }
++ return list;
++ }
++
++ /*!
++ \overload
++
++ Returns a list of all prefixes currently declared for the
++ namespace URI \a uri.
++
++ The "xml:" prefix is included. If you only want one prefix that is
++ mapped to the namespace URI, and you don't care which one you get,
++ use the prefix() function instead.
++
++ Note: The empty (default) prefix is never included in this list;
++ to check for the presence of a default namespace, call uri() with
++ "" as the argument.
++ */
++ QStringList QXmlNamespaceSupport::prefixes(const QString& uri) const
++ {
++ QStringList list;
++
++ NamespaceMap::const_iterator itc, it = d->ns.constBegin();
++ while ((itc=it) != d->ns.constEnd()) {
++ ++it;
++ if (*itc == uri && !itc.key().isEmpty())
++ list.append(itc.key());
++ }
++ return list;
++ }
++
++ /*!
++ Starts a new namespace context.
++
++ Normally, you should push a new context at the beginning of each
++ XML element: the new context automatically inherits the
++ declarations of its parent context, and it also keeps track of
++ which declarations were made within this context.
++
++ \sa popContext()
++ */
++ void QXmlNamespaceSupport::pushContext()
++ {
++ d->nsStack.push(d->ns);
++ }
++
++ /*!
++ Reverts to the previous namespace context.
++
++ Normally, you should pop the context at the end of each XML
++ element. After popping the context, all namespace prefix mappings
++ that were previously in force are restored.
++
++ \sa pushContext()
++ */
++ void QXmlNamespaceSupport::popContext()
++ {
++ d->ns.clear();
++ if (!d->nsStack.isEmpty())
++ d->ns = d->nsStack.pop();
++ }
++
++ /*!
++ Resets this namespace support object ready for reuse.
++ */
++ void QXmlNamespaceSupport::reset()
++ {
++ QXmlNamespaceSupportPrivate *newD = new QXmlNamespaceSupportPrivate;
++ delete d;
++ d = newD;
++ }
++
++ /*********************************************
++ *
++ * QXmlAttributes
++ *
++ *********************************************/
++
++ /*!
++ \class QXmlAttributes
++ \reentrant
++ \brief The QXmlAttributes class provides XML attributes.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ If attributes are reported by QXmlContentHandler::startElement()
++ this class is used to pass the attribute values.
++
++ Use index() to locate the position of an attribute in the list,
++ count() to retrieve the number of attributes, and clear() to
++ remove the attributes. New attributes can be added with append().
++ Use type() to get an attribute's type and value() to get its
++ value. The attribute's name is available from localName() or
++ qName(), and its namespace URI from uri().
++
++ */
++
++ /*!
++ \fn QXmlAttributes::QXmlAttributes()
++
++ Constructs an empty attribute list.
++ */
++ QXmlAttributes::QXmlAttributes()
++ = default;
++
++ /*!
++ \fn QXmlAttributes::~QXmlAttributes()
++
++ Destroys the attributes object.
++ */
++ QXmlAttributes::~QXmlAttributes()
++ {
++ }
++
++ /*!
++ \fn void QXmlAttributes::swap(QXmlAttributes &other)
++
++ Swaps \c this with \a other.
++ */
++
++ /*!
++ Looks up the index of an attribute by the qualified name \a qName.
++
++ Returns the index of the attribute or -1 if it wasn't found.
++ */
++ int QXmlAttributes::index(const QString& qName) const
++ {
++ #if QT_POINTER_SIZE != 4
++ Q_PRE(attList.size() <= INT_MAX);
++ #endif
++ for (int i = 0; i < attList.size(); ++i) {
++ if (attList.at(i).qname == qName)
++ return i;
++ }
++ return -1;
++ }
++
++ /*! \overload
++ */
++ int QXmlAttributes::index(QLatin1String qName) const
++ {
++ #if QT_POINTER_SIZE != 4
++ Q_PRE(attList.size() <= INT_MAX);
++ #endif
++ for (int i = 0; i < attList.size(); ++i) {
++ if (attList.at(i).qname == qName)
++ return i;
++ }
++ return -1;
++ }
++
++ /*!
++ \overload
++
++ Looks up the index of an attribute by a namespace name.
++
++ \a uri specifies the namespace URI, or an empty string if the name
++ has no namespace URI. \a localPart specifies the attribute's local
++ name.
++
++ Returns the index of the attribute, or -1 if it wasn't found.
++ */
++ int QXmlAttributes::index(const QString& uri, const QString& localPart) const
++ {
++ #if QT_POINTER_SIZE != 4
++ Q_PRE(attList.size() <= INT_MAX);
++ #endif
++ for (int i = 0; i < attList.size(); ++i) {
++ const Attribute &att = attList.at(i);
++ if (att.uri == uri && att.localname == localPart)
++ return i;
++ }
++ return -1;
++ }
++
++ /*!
++ Returns the number of attributes in the list.
++
++ \sa count()
++ */
++ int QXmlAttributes::length() const
++ {
++ return attList.size();
++ }
++
++ /*!
++ \fn int QXmlAttributes::count() const
++
++ Returns the number of attributes in the list. This function is
++ equivalent to length().
++ */
++
++ /*!
++ Looks up an attribute's local name for the attribute at position
++ \a index. If no namespace processing is done, the local name is
++ an empty string.
++ */
++ QString QXmlAttributes::localName(int index) const
++ {
++ return attList.at(index).localname;
++ }
++
++ /*!
++ Looks up an attribute's XML 1.0 qualified name for the attribute
++ at position \a index.
++ */
++ QString QXmlAttributes::qName(int index) const
++ {
++ return attList.at(index).qname;
++ }
++
++ /*!
++ Looks up an attribute's namespace URI for the attribute at
++ position \a index. If no namespace processing is done or if the
++ attribute has no namespace, the namespace URI is an empty string.
++ */
++ QString QXmlAttributes::uri(int index) const
++ {
++ return attList.at(index).uri;
++ }
++
++ /*!
++ Looks up an attribute's type for the attribute at position \a
++ index.
++
++ Currently only "CDATA" is returned.
++ */
++ QString QXmlAttributes::type(int) const
++ {
++ return QLatin1String("CDATA");
++ }
++
++ /*!
++ \overload
++
++ Looks up an attribute's type for the qualified name \a qName.
++
++ Currently only "CDATA" is returned.
++ */
++ QString QXmlAttributes::type(const QString&) const
++ {
++ return QLatin1String("CDATA");
++ }
++
++ /*!
++ \overload
++
++ Looks up an attribute's type by namespace name.
++
++ \a uri specifies the namespace URI and \a localName specifies the
++ local name. If the name has no namespace URI, use an empty string
++ for \a uri.
++
++ Currently only "CDATA" is returned.
++ */
++ QString QXmlAttributes::type(const QString&, const QString&) const
++ {
++ return QLatin1String("CDATA");
++ }
++
++ /*!
++ Returns an attribute's value for the attribute at position \a
++ index. The index must be a valid position
++ (i.e., 0 <= \a index < count()).
++ */
++ QString QXmlAttributes::value(int index) const
++ {
++ return attList.at(index).value;
++ }
++
++ /*!
++ \overload
++
++ Returns an attribute's value for the qualified name \a qName, or an
++ empty string if no attribute exists for the name given.
++ */
++ QString QXmlAttributes::value(const QString& qName) const
++ {
++ int i = index(qName);
++ if (i == -1)
++ return QString();
++ return attList.at(i).value;
++ }
++
++ /*!
++ \overload
++
++ Returns an attribute's value for the qualified name \a qName, or an
++ empty string if no attribute exists for the name given.
++ */
++ QString QXmlAttributes::value(QLatin1String qName) const
++ {
++ int i = index(qName);
++ if (i == -1)
++ return QString();
++ return attList.at(i).value;
++ }
++
++ /*!
++ \overload
++
++ Returns an attribute's value by namespace name.
++
++ \a uri specifies the namespace URI, or an empty string if the name
++ has no namespace URI. \a localName specifies the attribute's local
++ name.
++ */
++ QString QXmlAttributes::value(const QString& uri, const QString& localName) const
++ {
++ int i = index(uri, localName);
++ if (i == -1)
++ return QString();
++ return attList.at(i).value;
++ }
++
++ /*!
++ Clears the list of attributes.
++
++ \sa append()
++ */
++ void QXmlAttributes::clear()
++ {
++ attList.clear();
++ }
++
++ /*!
++ Appends a new attribute entry to the list of attributes. The
++ qualified name of the attribute is \a qName, the namespace URI is
++ \a uri and the local name is \a localPart. The value of the
++ attribute is \a value.
++
++ \sa qName(), uri(), localName(), value()
++ */
++ void QXmlAttributes::append(const QString &qName, const QString &uri, const QString &localPart, const QString &value)
++ {
++ Q_PRE(attList.size() < INT_MAX);
++
++ Attribute att;
++ att.qname = qName;
++ att.uri = uri;
++ att.localname = localPart;
++ att.value = value;
++
++ attList.append(att);
++ }
++
++ /*********************************************
++ *
++ * QXmlInputSource
++ *
++ *********************************************/
++
++ /*!
++ \class QXmlInputSource
++ \reentrant
++ \brief The QXmlInputSource class provides the input data for the
++ QXmlReader subclasses.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ All subclasses of QXmlReader read the input XML document from this
++ class.
++
++ This class recognizes the encoding of the data by reading the
++ encoding declaration in the XML file if it finds one, and reading
++ the data using the corresponding encoding. If it does not find an
++ encoding declaration, then it assumes that the data is either in
++ UTF-8 or UTF-16, depending on whether it can find a byte-order
++ mark.
++
++ There are two ways to populate the input source with data: you can
++ construct it with a QIODevice* so that the input source reads the
++ data from that device. Or you can set the data explicitly with one
++ of the setData() functions.
++
++ Usually you either construct a QXmlInputSource that works on a
++ QIODevice* or you construct an empty QXmlInputSource and set the
++ data with setData(). There are only rare occasions where you would
++ want to mix both methods.
++
++ The QXmlReader subclasses use the next() function to read the
++ input character by character. If you want to start from the
++ beginning again, use reset().
++
++ The functions data() and fetchData() are useful if you want to do
++ something with the data other than parsing, e.g. displaying the
++ raw XML file. The benefit of using the QXmlInputClass in such
++ cases is that it tries to use the correct encoding.
++
++ \sa QXmlReader, QXmlSimpleReader
++ */
++
++ // the following two are guaranteed not to be a character
++ const char16_t QXmlInputSource::EndOfData = 0xfffe;
++ const char16_t QXmlInputSource::EndOfDocument = 0xffff;
++
++ /*
++ Common part of the constructors.
++ */
++ void QXmlInputSource::init()
++ {
++ d = new QXmlInputSourcePrivate;
++
++ try {
++ d->inputDevice = nullptr;
++ d->inputStream = nullptr;
++
++ setData(QString());
++ #if QT_CONFIG(textcodec)
++ d->encMapper = nullptr;
++ #endif
++ d->nextReturnedEndOfData = true; // first call to next() will call fetchData()
++
++ d->encodingDeclBytes.clear();
++ d->encodingDeclChars.clear();
++ d->lookingForEncodingDecl = true;
++ } catch (...) {
++ delete(d);
++ throw;
++ }
++ }
++
++ /*!
++ Constructs an input source which contains no data.
++
++ \sa setData()
++ */
++ QXmlInputSource::QXmlInputSource()
++ {
++ init();
++ }
++
++ /*!
++ Constructs an input source and gets the data from device \a dev.
++ If \a dev is not open, it is opened in read-only mode. If \a dev
++ is 0 or it is not possible to read from the device, the input
++ source will contain no data.
++
++ \sa setData(), fetchData(), QIODevice
++ */
++ QXmlInputSource::QXmlInputSource(QIODevice *dev)
++ {
++ init();
++ d->inputDevice = dev;
++ if (dev->isOpen())
++ d->inputDevice->setTextModeEnabled(false);
++ }
++
++ /*!
++ Destructor.
++ */
++ QXmlInputSource::~QXmlInputSource()
++ {
++ // ### close the input device.
++ #if QT_CONFIG(textcodec)
++ delete d->encMapper;
++ #endif
++ delete d;
++ }
++
++ /*!
++ Returns the next character of the input source. If this function
++ reaches the end of available data, it returns
++ QXmlInputSource::EndOfData. If you call next() after that, it
++ tries to fetch more data by calling fetchData(). If the
++ fetchData() call results in new data, this function returns the
++ first character of that data; otherwise it returns
++ QXmlInputSource::EndOfDocument.
++
++ Readers, such as QXmlSimpleReader, will assume that the end of
++ the XML document has been reached if the this function returns
++ QXmlInputSource::EndOfDocument, and will check that the
++ supplied input is well-formed. Therefore, when reimplementing
++ this function, it is important to ensure that this behavior is
++ duplicated.
++
++ \sa reset(), fetchData(), QXmlSimpleReader::parse(),
++ QXmlSimpleReader::parseContinue()
++ */
++ QChar QXmlInputSource::next()
++ {
++ if (d->pos >= d->length) {
++ if (d->nextReturnedEndOfData) {
++ d->nextReturnedEndOfData = false;
++ fetchData();
++ if (d->pos >= d->length) {
++ return EndOfDocument;
++ }
++ return next();
++ }
++ d->nextReturnedEndOfData = true;
++ return EndOfData;
++ }
++
++ // QXmlInputSource has no way to signal encoding errors. The best we can do
++ // is return EndOfDocument. We do *not* return EndOfData, because the reader
++ // will then just call this function again to get the next char.
++ QChar c = d->unicode[d->pos++];
++ if (c == EndOfData)
++ c = EndOfDocument;
++ return c;
++ }
++
++ /*!
++ This function sets the position used by next() to the beginning of
++ the data returned by data(). This is useful if you want to use the
++ input source for more than one parse.
++
++ \note In the case that the underlying data source is a QIODevice,
++ the current position in the device is not automatically set to the
++ start of input. Call QIODevice::seek(0) on the device to do this.
++
++ \sa next()
++ */
++ void QXmlInputSource::reset()
++ {
++ d->nextReturnedEndOfData = false;
++ d->pos = 0;
++ }
++
++ /*!
++ Returns the data the input source contains or an empty string if the
++ input source does not contain any data.
++
++ \sa setData(), QXmlInputSource(), fetchData()
++ */
++ QString QXmlInputSource::data() const
++ {
++ if (d->nextReturnedEndOfData) {
++ QXmlInputSource *that = const_cast<QXmlInputSource*>(this);
++ that->d->nextReturnedEndOfData = false;
++ that->fetchData();
++ }
++ return d->str;
++ }
++
++ /*!
++ Sets the data of the input source to \a dat.
++
++ If the input source already contains data, this function deletes
++ that data first.
++
++ \sa data()
++ */
++ void QXmlInputSource::setData(const QString& dat)
++ {
++ d->str = dat;
++ d->unicode = dat.unicode();
++ d->pos = 0;
++ d->length = d->str.size();
++ d->nextReturnedEndOfData = false;
++ }
++
++ /*!
++ \overload
++
++ The data \a dat is passed through the correct text-codec, before
++ it is set.
++ */
++ void QXmlInputSource::setData(const QByteArray& dat)
++ {
++ setData(fromRawData(dat));
++ }
++
++ /*!
++ This function reads more data from the device that was set during
++ construction. If the input source already contained data, this
++ function deletes that data first.
++
++ This object contains no data after a call to this function if the
++ object was constructed without a device to read data from or if
++ this function was not able to get more data from the device.
++
++ There are two occasions where a fetch is done implicitly by
++ another function call: during construction (so that the object
++ starts out with some initial data where available), and during a
++ call to next() (if the data had run out).
++
++ You don't normally need to use this function if you use next().
++
++ \sa data(), next(), QXmlInputSource()
++ */
++
++ void QXmlInputSource::fetchData()
++ {
++ enum
++ {
++ BufferSize = 1024
++ };
++
++ QByteArray rawData;
++
++ if (d->inputDevice || d->inputStream) {
++ QIODevice *device = d->inputDevice ? d->inputDevice : d->inputStream->device();
++
++ if (!device) {
++ if (d->inputStream && d->inputStream->string()) {
++ QString *s = d->inputStream->string();
++ rawData = QByteArray(reinterpret_cast<const char *>(s->constData()),
++ s->size() * qsizetype(sizeof(QChar)));
++ }
++ } else if (device->isOpen() || device->open(QIODevice::ReadOnly)) {
++ rawData.resize(BufferSize);
++ qint64 size = device->read(rawData.data(), BufferSize);
++ if (size == 0 && device->waitForReadyRead(-1))
++ size = device->read(rawData.data(), BufferSize);
++
++ rawData.resize(qMax(qint64(0), size));
++ }
++
++ /* We do this inside the "if (d->inputDevice ..." scope
++ * because if we're not using a stream or device, that is,
++ * the user set a QString manually, we don't want to set
++ * d->str. */
++ setData(fromRawData(rawData));
++ }
++ }
++
++ #if QT_CONFIG(textcodec)
++ static QString extractEncodingDecl(const QString &text, bool *needMoreText)
++ {
++ *needMoreText = false;
++
++ qsizetype l = text.size();
++ const QLatin1String snip("<?xml", std::min(l, qsizetype(5)));
++ if (l > 0 && !text.startsWith(snip))
++ return QString();
++
++ qsizetype endPos = text.indexOf(QLatin1Char('>'));
++ if (endPos == -1) {
++ *needMoreText = l < 255; // we won't look forever
++ return QString();
++ }
++
++ qsizetype pos = text.indexOf(QLatin1String("encoding"));
++ if (pos == -1 || pos >= endPos)
++ return QString();
++
++ while (pos < endPos) {
++ QChar uc = text.at(pos);
++ if (uc == u'\'' || uc == u'"')
++ break;
++ ++pos;
++ }
++
++ if (pos == endPos)
++ return QString();
++
++ QString encoding;
++ ++pos;
++ while (pos < endPos) {
++ QChar uc = text.at(pos);
++ if (uc == u'\'' || uc == u'"')
++ break;
++ encoding.append(uc);
++ ++pos;
++ }
++
++ return encoding;
++ }
++ #endif // textcodec
++
++ /*!
++ This function reads the XML file from \a data and tries to
++ recognize the encoding. It converts the raw data \a data into a
++ QString and returns it. It tries its best to get the correct
++ encoding for the XML file.
++
++ If \a beginning is true, this function assumes that the data
++ starts at the beginning of a new XML document and looks for an
++ encoding declaration. If \a beginning is false, it converts the
++ raw data using the encoding determined from prior calls.
++ */
++ QString QXmlInputSource::fromRawData(const QByteArray &data, bool beginning)
++ {
++ #if !QT_CONFIG(textcodec)
++ Q_UNUSED(beginning);
++ return QString::fromLatin1(data.constData(), data.size());
++ #else
++ if (data.size() == 0)
++ return QString();
++ if (beginning) {
++ delete d->encMapper;
++ d->encMapper = nullptr;
++ }
++
++ int mib = 106; // UTF-8
++
++ // This is the initial UTF codec we will read the encoding declaration with
++ if (d->encMapper == nullptr) {
++ d->encodingDeclBytes.clear();
++ d->encodingDeclChars.clear();
++ d->lookingForEncodingDecl = true;
++
++ // look for byte order mark and read the first 5 characters
++ if (data.size() >= 4) {
++ uchar ch1 = data.at(0);
++ uchar ch2 = data.at(1);
++ uchar ch3 = data.at(2);
++ uchar ch4 = data.at(3);
++
++ if ((ch1 == 0 && ch2 == 0 && ch3 == 0xfe && ch4 == 0xff) ||
++ (ch1 == 0xff && ch2 == 0xfe && ch3 == 0 && ch4 == 0))
++ mib = 1017; // UTF-32 with byte order mark
++ else if (ch1 == 0x3c && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x00)
++ mib = 1019; // UTF-32LE
++ else if (ch1 == 0x00 && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x3c)
++ mib = 1018; // UTF-32BE
++ }
++ if (mib == 106 && data.size() >= 2) {
++ uchar ch1 = data.at(0);
++ uchar ch2 = data.at(1);
++
++ if ((ch1 == 0xfe && ch2 == 0xff) || (ch1 == 0xff && ch2 == 0xfe))
++ mib = 1015; // UTF-16 with byte order mark
++ else if (ch1 == 0x3c && ch2 == 0x00)
++ mib = 1014; // UTF-16LE
++ else if (ch1 == 0x00 && ch2 == 0x3c)
++ mib = 1013; // UTF-16BE
++ }
++
++ QTextCodec *codec = QTextCodec::codecForMib(mib);
++ Q_ASSERT(codec);
++
++ d->encMapper = codec->makeDecoder();
++ }
++
++ QString input = d->encMapper->toUnicode(data.constData(), data.size());
++
++ if (d->lookingForEncodingDecl) {
++ d->encodingDeclChars += input;
++
++ bool needMoreText;
++ QString encoding = extractEncodingDecl(d->encodingDeclChars, &needMoreText);
++
++ if (!encoding.isEmpty()) {
++ if (QTextCodec *codec = QTextCodec::codecForName(std::move(encoding).toLatin1())) {
++ /* If the encoding is the same, we don't have to do toUnicode() all over again. */
++ if(codec->mibEnum() != mib) {
++ delete d->encMapper;
++ d->encMapper = codec->makeDecoder();
++
++ /* The variable input can potentially be large, so we deallocate
++ * it before calling toUnicode() in order to avoid having two
++ * large QStrings in memory simultaneously. */
++ input.clear();
++
++ // prime the decoder with the data so far
++ d->encMapper->toUnicode(d->encodingDeclBytes.constData(), d->encodingDeclBytes.size());
++ // now feed it the new data
++ input = d->encMapper->toUnicode(data.constData(), data.size());
++ }
++ }
++ }
++
++ d->encodingDeclBytes += data;
++ d->lookingForEncodingDecl = needMoreText;
++ }
++
++ return input;
++ #endif
++ }
++
++ /*********************************************
++ *
++ * QXmlDefaultHandler
++ *
++ *********************************************/
++
++ /*!
++ \class QXmlContentHandler
++ \reentrant
++ \brief The QXmlContentHandler class provides an interface to
++ report the logical content of XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ If the application needs to be informed of basic parsing events,
++ it can implement this interface and activate it using
++ QXmlReader::setContentHandler(). The reader can then report basic
++ document-related events like the start and end of elements and
++ character data through this interface.
++
++ The order of events in this interface is very important, and
++ mirrors the order of information in the document itself. For
++ example, all of an element's content (character data, processing
++ instructions, and sub-elements) appears, in order, between the
++ startElement() event and the corresponding endElement() event.
++
++ The class QXmlDefaultHandler provides a default implementation for
++ this interface; subclassing from the QXmlDefaultHandler class is
++ very convenient if you only want to be informed of some parsing
++ events.
++
++ The startDocument() function is called at the start of the
++ document, and endDocument() is called at the end. Before parsing
++ begins setDocumentLocator() is called. For each element
++ startElement() is called, with endElement() being called at the
++ end of each element. The characters() function is called with
++ chunks of character data; ignorableWhitespace() is called with
++ chunks of whitespace and processingInstruction() is called with
++ processing instructions. If an entity is skipped skippedEntity()
++ is called. At the beginning of prefix-URI scopes
++ startPrefixMapping() is called.
++
++ \sa QXmlDTDHandler, QXmlDeclHandler, QXmlEntityResolver, QXmlErrorHandler,
++ QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlContentHandler::~QXmlContentHandler()
++
++ Destroys the content handler.
++ */
++ QXmlContentHandler::~QXmlContentHandler()
++ = default;
++
++ /*!
++ \fn void QXmlContentHandler::setDocumentLocator(QXmlLocator* locator)
++
++ The reader calls this function before it starts parsing the
++ document. The argument \a locator is a pointer to a QXmlLocator
++ which allows the application to get the parsing position within
++ the document.
++
++ Do not destroy the \a locator; it is destroyed when the reader is
++ destroyed. (Do not use the \a locator after the reader is
++ destroyed).
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::startDocument()
++
++ The reader calls this function when it starts parsing the
++ document. The reader calls this function just once, after the call
++ to setDocumentLocator(), and before any other functions in this
++ class or in the QXmlDTDHandler class are called.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endDocument()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::endDocument()
++
++ The reader calls this function after it has finished parsing. It
++ is called just once, and is the last handler function called. It
++ is called after the reader has read all input or has abandoned
++ parsing because of a fatal error.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa startDocument()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::startPrefixMapping(const QString& prefix, const QString& uri)
++
++ The reader calls this function to signal the begin of a prefix-URI
++ namespace mapping scope. This information is not necessary for
++ normal namespace processing since the reader automatically
++ replaces prefixes for element and attribute names.
++
++ Note that startPrefixMapping() and endPrefixMapping() calls are
++ not guaranteed to be properly nested relative to each other: all
++ startPrefixMapping() events occur before the corresponding
++ startElement() event, and all endPrefixMapping() events occur
++ after the corresponding endElement() event, but their order is not
++ otherwise guaranteed.
++
++ The argument \a prefix is the namespace prefix being declared and
++ the argument \a uri is the namespace URI the prefix is mapped to.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endPrefixMapping()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::endPrefixMapping(const QString& prefix)
++
++ The reader calls this function to signal the end of a prefix
++ mapping for the prefix \a prefix.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa startPrefixMapping()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts)
++
++ The reader calls this function when it has parsed a start element
++ tag.
++
++ There is a corresponding endElement() call when the corresponding
++ end element tag is read. The startElement() and endElement() calls
++ are always nested correctly. Empty element tags (e.g. \c{<x/>})
++ cause a startElement() call to be immediately followed by an
++ endElement() call.
++
++ The attribute list provided only contains attributes with explicit
++ values. The attribute list contains attributes used for namespace
++ declaration (i.e. attributes starting with xmlns) only if the
++ namespace-prefix property of the reader is true.
++
++ The argument \a namespaceURI is the namespace URI, or
++ an empty string if the element has no namespace URI or if no
++ namespace processing is done. \a localName is the local name
++ (without prefix), or an empty string if no namespace processing is
++ done, \a qName is the qualified name (with prefix) and \a atts are
++ the attributes attached to the element. If there are no
++ attributes, \a atts is an empty attributes object.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endElement()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::endElement(const QString& namespaceURI, const QString& localName, const QString& qName)
++
++ The reader calls this function when it has parsed an end element
++ tag with the qualified name \a qName, the local name \a localName
++ and the namespace URI \a namespaceURI.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa startElement()
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::characters(const QString& ch)
++
++ The reader calls this function when it has parsed a chunk of
++ character data (either normal character data or character data
++ inside a CDATA section; if you need to distinguish between those
++ two types you must use QXmlLexicalHandler::startCDATA() and
++ QXmlLexicalHandler::endCDATA()). The character data is reported in
++ \a ch.
++
++ Some readers report whitespace in element content using the
++ ignorableWhitespace() function rather than using this one.
++
++ A reader may report the character data of an element in more than
++ one chunk; e.g. a reader might want to report "a\<b" in three
++ characters() events ("a ", "\<" and " b").
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::ignorableWhitespace(const QString& ch)
++
++ Some readers may use this function to report each chunk of
++ whitespace in element content. The whitespace is reported in \a ch.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::processingInstruction(const QString& target, const QString& data)
++
++ The reader calls this function when it has parsed a processing
++ instruction.
++
++ \a target is the target name of the processing instruction and \a
++ data is the data in the processing instruction.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlContentHandler::skippedEntity(const QString& name)
++
++ Some readers may skip entities if they have not seen the
++ declarations (e.g. because they are in an external DTD). If they
++ do so they report that they skipped the entity called \a name by
++ calling this function.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn QString QXmlContentHandler::errorString() const
++
++ The reader calls this function to get an error string, e.g. if any
++ of the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlErrorHandler
++ \reentrant
++ \brief The QXmlErrorHandler class provides an interface to report
++ errors in XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ If you want your application to report errors to the user or to
++ perform customized error handling, you should subclass this class.
++
++ You can set the error handler with QXmlReader::setErrorHandler().
++
++ Errors can be reported using warning(), error() and fatalError(),
++ with the error text being reported with errorString().
++
++ \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
++ QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlErrorHandler::~QXmlErrorHandler()
++
++ Destroys the error handler.
++ */
++ QXmlErrorHandler::~QXmlErrorHandler()
++ = default;
++
++ /*!
++ \fn bool QXmlErrorHandler::warning(const QXmlParseException& exception)
++
++ A reader might use this function to report a warning. Warnings are
++ conditions that are not errors or fatal errors as defined by the
++ XML 1.0 specification. Details of the warning are stored in \a
++ exception.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlErrorHandler::error(const QXmlParseException& exception)
++
++ A reader might use this function to report a recoverable error. A
++ recoverable error corresponds to the definiton of "error" in
++ section 1.2 of the XML 1.0 specification. Details of the error are
++ stored in \a exception.
++
++ The reader must continue to provide normal parsing events after
++ invoking this function.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlErrorHandler::fatalError(const QXmlParseException& exception)
++
++ A reader must use this function to report a non-recoverable error.
++ Details of the error are stored in \a exception.
++
++ If this function returns \c true the reader might try to go on
++ parsing and reporting further errors, but no regular parsing
++ events are reported.
++ */
++
++ /*!
++ \fn QString QXmlErrorHandler::errorString() const
++
++ The reader calls this function to get an error string if any of
++ the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlDTDHandler
++ \reentrant
++ \brief The QXmlDTDHandler class provides an interface to report
++ DTD content of XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ If an application needs information about notations and unparsed
++ entities, it can implement this interface and register an instance
++ with QXmlReader::setDTDHandler().
++
++ Note that this interface includes only those DTD events that the
++ XML recommendation requires processors to report, i.e. notation
++ and unparsed entity declarations using notationDecl() and
++ unparsedEntityDecl() respectively.
++
++ \sa QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler,
++ QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlDTDHandler::~QXmlDTDHandler()
++
++ Destroys the DTD handler.
++ */
++ QXmlDTDHandler::~QXmlDTDHandler()
++ = default;
++
++ /*!
++ \fn bool QXmlDTDHandler::notationDecl(const QString& name, const QString& publicId, const QString& systemId)
++
++ The reader calls this function when it has parsed a notation
++ declaration.
++
++ The argument \a name is the notation name, \a publicId is the
++ notation's public identifier and \a systemId is the notation's
++ system identifier.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlDTDHandler::unparsedEntityDecl(const QString& name, const QString& publicId, const QString& systemId, const QString& notationName)
++
++ The reader calls this function when it finds an unparsed entity
++ declaration.
++
++ The argument \a name is the unparsed entity's name, \a publicId is
++ the entity's public identifier, \a systemId is the entity's system
++ identifier and \a notationName is the name of the associated
++ notation.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn QString QXmlDTDHandler::errorString() const
++
++ The reader calls this function to get an error string if any of
++ the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlEntityResolver
++ \reentrant
++ \brief The QXmlEntityResolver class provides an interface to
++ resolve external entities contained in XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ If an application needs to implement customized handling for
++ external entities, it must implement this interface, i.e.
++ resolveEntity(), and register it with
++ QXmlReader::setEntityResolver().
++
++ \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlErrorHandler,
++ QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlEntityResolver::~QXmlEntityResolver()
++
++ Destroys the entity resolver.
++ */
++ QXmlEntityResolver::~QXmlEntityResolver()
++ = default;
++
++ /*!
++ \fn bool QXmlEntityResolver::resolveEntity(const QString& publicId, const QString& systemId, QXmlInputSource*& ret)
++
++ The reader calls this function before it opens any external
++ entity, except the top-level document entity. The application may
++ request the reader to resolve the entity itself (\a ret is 0) or
++ to use an entirely different input source (\a ret points to the
++ input source).
++
++ The reader deletes the input source \a ret when it no longer needs
++ it, so you should allocate it on the heap with \c new.
++
++ The argument \a publicId is the public identifier of the external
++ entity, \a systemId is the system identifier of the external
++ entity and \a ret is the return value of this function. If \a ret
++ is 0 the reader should resolve the entity itself, if it is
++ non-zero it must point to an input source which the reader uses
++ instead.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn QString QXmlEntityResolver::errorString() const
++
++ The reader calls this function to get an error string if any of
++ the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlLexicalHandler
++ \reentrant
++ \brief The QXmlLexicalHandler class provides an interface to
++ report the lexical content of XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ The events in the lexical handler apply to the entire document,
++ not just to the document element, and all lexical handler events
++ appear between the content handler's startDocument and endDocument
++ events.
++
++ You can set the lexical handler with
++ QXmlReader::setLexicalHandler().
++
++ This interface's design is based on the SAX2 extension
++ LexicalHandler.
++
++ The interface provides the startDTD(), endDTD(), startEntity(),
++ endEntity(), startCDATA(), endCDATA() and comment() functions.
++
++ \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
++ QXmlErrorHandler
++ */
++
++ /*!
++ \fn QXmlLexicalHandler::~QXmlLexicalHandler()
++
++ Destroys the lexical handler.
++ */
++ QXmlLexicalHandler::~QXmlLexicalHandler()
++ = default;
++
++ /*!
++ \fn bool QXmlLexicalHandler::startDTD(const QString& name, const QString& publicId, const QString& systemId)
++
++ The reader calls this function to report the start of a DTD
++ declaration, if any. It reports the name of the document type in
++ \a name, the public identifier in \a publicId and the system
++ identifier in \a systemId.
++
++ If the public identifier is missing, \a publicId is set to
++ an empty string. If the system identifier is missing, \a systemId is
++ set to an empty string. Note that it is not valid XML to have a
++ public identifier but no system identifier; in such cases a parse
++ error will occur.
++
++ All declarations reported through QXmlDTDHandler or
++ QXmlDeclHandler appear between the startDTD() and endDTD() calls.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endDTD()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::endDTD()
++
++ The reader calls this function to report the end of a DTD
++ declaration, if any.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa startDTD()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::startEntity(const QString& name)
++
++ The reader calls this function to report the start of an entity
++ called \a name.
++
++ Note that if the entity is unknown, the reader reports it through
++ QXmlContentHandler::skippedEntity() and not through this
++ function.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endEntity(), QXmlSimpleReader::setFeature()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::endEntity(const QString& name)
++
++ The reader calls this function to report the end of an entity
++ called \a name.
++
++ For every startEntity() call, there is a corresponding endEntity()
++ call. The calls to startEntity() and endEntity() are properly
++ nested.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa startEntity(), QXmlContentHandler::skippedEntity(), QXmlSimpleReader::setFeature()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::startCDATA()
++
++ The reader calls this function to report the start of a CDATA
++ section. The content of the CDATA section is reported through the
++ QXmlContentHandler::characters() function. This function is
++ intended only to report the boundary.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++
++ \sa endCDATA()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::endCDATA()
++
++ The reader calls this function to report the end of a CDATA
++ section.
++
++ If this function returns \c false the reader stops parsing and reports
++ an error. The reader uses the function errorString() to get the error
++ message.
++
++ \sa startCDATA(), QXmlContentHandler::characters()
++ */
++
++ /*!
++ \fn bool QXmlLexicalHandler::comment(const QString& ch)
++
++ The reader calls this function to report an XML comment anywhere
++ in the document. It reports the text of the comment in \a ch.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn QString QXmlLexicalHandler::errorString() const
++
++ The reader calls this function to get an error string if any of
++ the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlDeclHandler
++ \reentrant
++ \brief The QXmlDeclHandler class provides an interface to report declaration
++ content of XML data.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ You can set the declaration handler with
++ QXmlReader::setDeclHandler().
++
++ This interface is based on the SAX2 extension DeclHandler.
++
++ The interface provides attributeDecl(), internalEntityDecl() and
++ externalEntityDecl() functions.
++
++ \sa QXmlDTDHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler,
++ QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlDeclHandler::~QXmlDeclHandler()
++
++ Destroys the declaration handler.
++ */
++ QXmlDeclHandler::~QXmlDeclHandler()
++ = default;
++
++ /*!
++ \fn bool QXmlDeclHandler::attributeDecl(const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value)
++
++ The reader calls this function to report an attribute type
++ declaration. Only the effective (first) declaration for an
++ attribute is reported.
++
++ The reader passes the name of the associated element in \a eName
++ and the name of the attribute in \a aName. It passes a string that
++ represents the attribute type in \a type and a string that
++ represents the attribute default in \a valueDefault. This string
++ is one of "#IMPLIED", "#REQUIRED", "#FIXED" or an empty string (if
++ none of the others applies). The reader passes the attribute's
++ default value in \a value. If no default value is specified in the
++ XML file, \a value is an empty string.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlDeclHandler::internalEntityDecl(const QString& name, const QString& value)
++
++ The reader calls this function to report an internal entity
++ declaration. Only the effective (first) declaration is reported.
++
++ The reader passes the name of the entity in \a name and the value
++ of the entity in \a value.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn bool QXmlDeclHandler::externalEntityDecl(const QString& name, const QString& publicId, const QString& systemId)
++
++ The reader calls this function to report a parsed external entity
++ declaration. Only the effective (first) declaration for each
++ entity is reported.
++
++ The reader passes the name of the entity in \a name, the public
++ identifier in \a publicId and the system identifier in \a
++ systemId. If there is no public identifier specified, it passes
++ an empty string in \a publicId.
++
++ If this function returns \c false the reader stops parsing and
++ reports an error. The reader uses the function errorString() to
++ get the error message.
++ */
++
++ /*!
++ \fn QString QXmlDeclHandler::errorString() const
++
++ The reader calls this function to get an error string if any of
++ the handler functions returns \c false.
++ */
++
++ /*!
++ \class QXmlDefaultHandler
++ \reentrant
++ \brief The QXmlDefaultHandler class provides a default implementation of all
++ the XML handler classes.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ This class gathers together the features of
++ the specialized handler classes, making it a convenient
++ starting point when implementing custom handlers for
++ subclasses of QXmlReader, particularly QXmlSimpleReader.
++ The virtual functions from each of the base classes are
++ reimplemented in this class, providing sensible default behavior
++ for many common cases. By subclassing this class, and
++ overriding these functions, you can concentrate
++ on implementing the parts of the handler relevant to your
++ application.
++
++ The XML reader must be told which handler to use for different
++ kinds of events during parsing. This means that, although
++ QXmlDefaultHandler provides default implementations of functions
++ inherited from all its base classes, we can still use specialized
++ handlers for particular kinds of events.
++
++ For example, QXmlDefaultHandler subclasses both
++ QXmlContentHandler and QXmlErrorHandler, so by subclassing
++ it we can use the same handler for both of the following
++ reader functions:
++
++ \snippet rsslisting/listing.cpp 0
++
++ Since the reader will inform the handler of parsing errors, it is
++ necessary to reimplement QXmlErrorHandler::fatalError() if, for
++ example, we want to stop parsing when such an error occurs:
++
++ \snippet rsslisting/handler.cpp 0
++
++ The above function returns \c false, which tells the reader to stop
++ parsing. To continue to use the same reader,
++ it is necessary to create a new handler instance, and set up the
++ reader to use it in the manner described above.
++
++ It is useful to examine some of the functions inherited by
++ QXmlDefaultHandler, and consider why they might be
++ reimplemented in a custom handler.
++ Custom handlers will typically reimplement
++ QXmlContentHandler::startDocument() to prepare the handler for
++ new content. Document elements and the text within them can be
++ processed by reimplementing QXmlContentHandler::startElement(),
++ QXmlContentHandler::endElement(), and
++ QXmlContentHandler::characters().
++ You may want to reimplement QXmlContentHandler::endDocument()
++ to perform some finalization or validation on the content once the
++ document has been read completely.
++
++ \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
++ QXmlErrorHandler, QXmlLexicalHandler
++ */
++
++ /*!
++ \fn QXmlDefaultHandler::QXmlDefaultHandler()
++
++ Constructs a handler for use with subclasses of QXmlReader.
++ */
++ QXmlDefaultHandler::QXmlDefaultHandler()
++ = default;
++
++ /*!
++ \fn QXmlDefaultHandler::~QXmlDefaultHandler()
++
++ Destroys the handler.
++ */
++ QXmlDefaultHandler::~QXmlDefaultHandler()
++ {
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ void QXmlDefaultHandler::setDocumentLocator(QXmlLocator*)
++ {
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startDocument()
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endDocument()
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startPrefixMapping(const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endPrefixMapping(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startElement(const QString&, const QString&,
++ const QString&, const QXmlAttributes&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endElement(const QString&, const QString&,
++ const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::characters(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::ignorableWhitespace(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::processingInstruction(const QString&,
++ const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::skippedEntity(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::warning(const QXmlParseException&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::error(const QXmlParseException&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::fatalError(const QXmlParseException&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::notationDecl(const QString&, const QString&,
++ const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::unparsedEntityDecl(const QString&, const QString&,
++ const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ Sets \a ret to \nullptr, so that the reader uses the system identifier
++ provided in the XML document.
++ */
++ bool QXmlDefaultHandler::resolveEntity(const QString&, const QString&,
++ QXmlInputSource*& ret)
++ {
++ ret = nullptr;
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ Returns the default error string.
++ */
++ QString QXmlDefaultHandler::errorString() const
++ {
++ return QString::fromLatin1(XMLERR_ERRORBYCONSUMER);
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startDTD(const QString&, const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endDTD()
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startEntity(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endEntity(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::startCDATA()
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::endCDATA()
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::comment(const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::attributeDecl(const QString&, const QString&, const QString&, const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::internalEntityDecl(const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*!
++ \reimp
++
++ This reimplementation does nothing.
++ */
++ bool QXmlDefaultHandler::externalEntityDecl(const QString&, const QString&, const QString&)
++ {
++ return true;
++ }
++
++ /*********************************************
++ *
++ * QXmlSimpleReaderPrivate
++ *
++ *********************************************/
++
++ inline bool QXmlSimpleReaderPrivate::atEnd()
++ {
++ return (c.unicode()|0x0001) == 0xffff;
++ }
++
++ inline void QXmlSimpleReaderPrivate::stringClear()
++ {
++ stringValue.resize(0);
++ stringArrayPos = 0;
++ }
++ inline void QXmlSimpleReaderPrivate::nameClear()
++ {
++ nameValue.resize(0);
++ nameArrayPos = 0;
++ }
++
++ inline void QXmlSimpleReaderPrivate::refClear()
++ {
++ refValue.resize(0);
++ refArrayPos = 0;
++ }
++
++ QXmlSimpleReaderPrivate::QXmlSimpleReaderPrivate(QXmlSimpleReader *reader)
++ {
++ q_ptr = reader;
++ parseStack = nullptr;
++
++ locator.reset(new QXmlSimpleReaderLocator(reader));
++ entityRes = nullptr;
++ dtdHnd = nullptr;
++ contentHnd = nullptr;
++ errorHnd = nullptr;
++ lexicalHnd = nullptr;
++ declHnd = nullptr;
++
++ // default feature settings
++ useNamespaces = true;
++ useNamespacePrefixes = false;
++ reportWhitespaceCharData = true;
++ reportEntities = false;
++ }
++
++ QXmlSimpleReaderPrivate::~QXmlSimpleReaderPrivate()
++ {
++ delete parseStack;
++ }
++
++ void QXmlSimpleReaderPrivate::initIncrementalParsing()
++ {
++ if (parseStack)
++ parseStack->clear();
++ else
++ parseStack = new QStack<ParseState>;
++ }
++
++ /*!
++ \internal
++
++ A helper function that executes the topmost function from the
++ stack. Returns the result of the execution
++ */
++ bool QXmlSimpleReaderPrivate::resumeSuspendedCall()
++ {
++ if (!parseStack->isEmpty()) {
++ ParseFunction function = parseStack->top().function;
++ if (function == &QXmlSimpleReaderPrivate::eat_ws) {
++ parseStack->pop();
++ #if defined(QT_QXML_DEBUG)
++ qDebug("QXmlSimpleReader: eat_ws (cont)");
++ #endif
++ }
++ return (this->*function)();
++ }
++ return true; // nothing to execute
++ }
++
++ constexpr int ItemInitState = 0;
++
++ /*!
++ \internal
++
++ Returns the new state of the parser or -1 in case of an error.
++ */
++ int QXmlSimpleReaderPrivate::tryUnwindParseStack(ParseState::ParseFunction func)
++ {
++ int state;
++ if (parseStack == nullptr || parseStack->isEmpty()) {
++ state = ItemInitState;
++ } else {
++ state = parseStack->pop().state;
++ #if defined(QT_QXML_DEBUG)
++ qDebug("QXmlSimpleReader: %s (cont) in state %d",
++ func == &QXmlSimpleReaderPrivate::parseProlog ? "parseProlog" :
++ func == &QXmlSimpleReaderPrivate::parseElement ? "parseElement" :
++ func == &QXmlSimpleReaderPrivate::parseContent ? "parseContent" :
++ func == &QXmlSimpleReaderPrivate::parseMisc ? "parseMisc" :
++ func == &QXmlSimpleReaderPrivate::parsePI ? "parsePI" :
++ func == &QXmlSimpleReaderPrivate::parseDoctype ? "parseDoctype" :
++ func == &QXmlSimpleReaderPrivate::parseExternalID ? "parseExternalID" :
++ func == &QXmlSimpleReaderPrivate::parseMarkupdecl ? "parseMarkupdecl" :
++ func == &QXmlSimpleReaderPrivate::parsePEReference ? "parsePEReference" :
++ func == &QXmlSimpleReaderPrivate::parseAttlistDecl ? "parseAttlistDecl" :
++ func == &QXmlSimpleReaderPrivate::parseAttType ? "parseAttType" :
++ func == &QXmlSimpleReaderPrivate::parseAttValue ? "parseAttValue" :
++ func == &QXmlSimpleReaderPrivate::parseElementDecl ? "parseElementDecl" :
++ func == &QXmlSimpleReaderPrivate::parseNotationDecl ? "parseNotationDecl" :
++ func == &QXmlSimpleReaderPrivate::parseChoiceSeq ? "parseChoiceSeq" :
++ func == &QXmlSimpleReaderPrivate::parseEntityDecl ? "parseEntityDecl" :
++ func == &QXmlSimpleReaderPrivate::parseEntityValue ? "parseEntityValue" :
++ func == &QXmlSimpleReaderPrivate::parseComment ? "parseComment" :
++ func == &QXmlSimpleReaderPrivate::parseAttribute ? "parseAttribute" :
++ func == &QXmlSimpleReaderPrivate::parseName ? "parseName" :
++ func == &QXmlSimpleReaderPrivate::parseNmtoken ? "parseNmtoken" :
++ func == &QXmlSimpleReaderPrivate::parseReference ? "parseReference" :
++ func == &QXmlSimpleReaderPrivate::parseString ? "parseString" :
++ /* else */ "<unknown function>",
++ state);
++ #endif
++ if (!resumeSuspendedCall()) {
++ parseFailed(func, state);
++ return -1;
++ }
++ }
++
++ return state;
++ }
++
++ /*********************************************
++ *
++ * QXmlSimpleReader
++ *
++ *********************************************/
++
++ /*!
++ \class QXmlReader
++ \reentrant
++ \brief The QXmlReader class provides an interface for XML readers (i.e.
++ parsers).
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ This abstract class provides an interface for all of Qt's XML
++ readers. Currently there is only one implementation of a reader
++ included in Qt's XML module: QXmlSimpleReader. In future releases
++ there might be more readers with different properties available
++ (e.g. a validating parser).
++
++ The design of the XML classes follows the
++ \l {http://www.saxproject.org/}{SAX2 Java interface}, with
++ the names adapted to fit Qt naming conventions. It should be very
++ easy for anybody who has worked with SAX2 to get started with the
++ Qt XML classes.
++
++ All readers use the class QXmlInputSource to read the input
++ document. Since you are normally interested in particular content
++ in the XML document, the reader reports the content through
++ special handler classes (QXmlDTDHandler, QXmlDeclHandler,
++ QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler and
++ QXmlLexicalHandler), which you must subclass, if you want to
++ process the contents.
++
++ Since the handler classes only describe interfaces you must
++ implement all the functions. We provide the QXmlDefaultHandler
++ class to make this easier: it implements a default behavior (do
++ nothing) for all functions, so you can subclass it and just
++ implement the functions you are interested in.
++
++ Features and properties of the reader can be set with setFeature()
++ and setProperty() respectively. You can set the reader to use your
++ own subclasses with setEntityResolver(), setDTDHandler(),
++ setContentHandler(), setErrorHandler(), setLexicalHandler() and
++ setDeclHandler(). The parse itself is started with a call to
++ parse().
++
++ Note that this class is now deprecated, please use QXmlStreamReader or
++ QDomDocument for reading XML files.
++
++ \sa QXmlSimpleReader
++ */
++
++ /*!
++ \fn QXmlReader::~QXmlReader()
++
++ Destroys the reader.
++ */
++ QXmlReader::~QXmlReader()
++ = default;
++
++ /*!
++ \fn bool QXmlReader::feature(const QString& name, bool *ok) const
++
++ If the reader has the feature called \a name, the feature's value
++ is returned. If no such feature exists the return value is
++ undefined.
++
++ If \a ok is not \nullptr: \c{*}\a{ok} is set to true if the
++ reader has the feature called \a name; otherwise \c{*}\a{ok} is
++ set to false.
++
++ \sa setFeature(), hasFeature()
++ */
++
++ /*!
++ \fn void QXmlReader::setFeature(const QString& name, bool value)
++
++ Sets the feature called \a name to the given \a value. If the
++ reader doesn't have the feature nothing happens.
++
++ \sa feature(), hasFeature()
++ */
++
++ /*!
++ \fn bool QXmlReader::hasFeature(const QString& name) const
++
++ Returns \c true if the reader has the feature called \a name;
++ otherwise returns \c false.
++
++ \sa feature(), setFeature()
++ */
++
++ /*!
++ \fn void* QXmlReader::property(const QString& name, bool *ok) const
++
++ If the reader has the property \a name, this function returns the
++ value of the property; otherwise the return value is undefined.
++
++ If \a ok is not \nullptr: if the reader has the \a name property
++ \c{*}\a{ok} is set to true; otherwise \c{*}\a{ok} is set to false.
++
++ \sa setProperty(), hasProperty()
++ */
++
++ /*!
++ \fn void QXmlReader::setProperty(const QString& name, void* value)
++
++ Sets the property \a name to \a value. If the reader doesn't have
++ the property nothing happens.
++
++ \sa property(), hasProperty()
++ */
++
++ /*!
++ \fn bool QXmlReader::hasProperty(const QString& name) const
++
++ Returns \c true if the reader has the property \a name; otherwise
++ returns \c false.
++
++ \sa property(), setProperty()
++ */
++
++ /*!
++ \fn void QXmlReader::setEntityResolver(QXmlEntityResolver* handler)
++
++ Sets the entity resolver to \a handler.
++
++ \sa entityResolver()
++ */
++
++ /*!
++ \fn QXmlEntityResolver *QXmlReader::entityResolver() const
++
++ Returns the entity resolver or \nullptr if none was set.
++
++ \sa setEntityResolver()
++ */
++
++ /*!
++ \fn void QXmlReader::setDTDHandler(QXmlDTDHandler* handler)
++
++ Sets the DTD handler to \a handler.
++
++ \sa DTDHandler()
++ */
++
++ /*!
++ \fn QXmlDTDHandler *QXmlReader::DTDHandler() const
++
++ Returns the DTD handler or \nullptr if none was set.
++
++ \sa setDTDHandler()
++ */
++
++ /*!
++ \fn void QXmlReader::setContentHandler(QXmlContentHandler* handler)
++
++ Sets the content handler to \a handler.
++
++ \sa contentHandler()
++ */
++
++ /*!
++ \fn QXmlContentHandler *QXmlReader::contentHandler() const
++
++ Returns the content handler or \nullptr if none was set.
++
++ \sa setContentHandler()
++ */
++
++ /*!
++ \fn void QXmlReader::setErrorHandler(QXmlErrorHandler* handler)
++
++ Sets the error handler to \a handler. Clears the error handler if
++ \a handler is 0.
++
++ \sa errorHandler()
++ */
++
++ /*!
++ \fn QXmlErrorHandler *QXmlReader::errorHandler() const
++
++ Returns the error handler or \nullptr if none is set.
++
++ \sa setErrorHandler()
++ */
++
++ /*!
++ \fn void QXmlReader::setLexicalHandler(QXmlLexicalHandler* handler)
++
++ Sets the lexical handler to \a handler.
++
++ \sa lexicalHandler()
++ */
++
++ /*!
++ \fn QXmlLexicalHandler *QXmlReader::lexicalHandler() const
++
++ Returns the lexical handler or \nullptr if none was set.
++
++ \sa setLexicalHandler()
++ */
++
++ /*!
++ \fn void QXmlReader::setDeclHandler(QXmlDeclHandler* handler)
++
++ Sets the declaration handler to \a handler.
++
++ \sa declHandler()
++ */
++
++ /*!
++ \fn QXmlDeclHandler *QXmlReader::declHandler() const
++
++ Returns the declaration handler or \nullptr if none was set.
++
++ \sa setDeclHandler()
++ */
++
++ /*!
++ \fn bool QXmlReader::parse(const QXmlInputSource &input)
++
++ \deprecated
++
++ Parses the given \a input.
++ */
++
++ /*!
++ \fn bool QXmlReader::parse(const QXmlInputSource *input)
++
++ Reads an XML document from \a input and parses it. Returns \c true if
++ the parsing was successful; otherwise returns \c false.
++ */
++
++ /*!
++ \class QXmlSimpleReader
++ \nonreentrant
++ \brief The QXmlSimpleReader class provides an implementation of a
++ simple XML parser.
++
++ \inmodule QtCore5Compat
++ \ingroup xml-tools
++
++ This XML reader is suitable for a wide range of applications. It
++ is able to parse well-formed XML and can report the namespaces of
++ elements to a content handler; however, it does not parse any
++ external entities. For historical reasons, Attribute Value
++ Normalization and End-of-Line Handling as described in the XML 1.0
++ specification is not performed.
++
++ The easiest pattern of use for this class is to create a reader
++ instance, define an input source, specify the handlers to be used
++ by the reader, and parse the data.
++
++ For example, we could use a QFile to supply the input. Here, we
++ create a reader, and define an input source to be used by the
++ reader:
++
++ \snippet simpleparse/main.cpp 0
++
++ A handler lets us perform actions when the reader encounters
++ certain types of content, or if errors in the input are found. The
++ reader must be told which handler to use for each type of
++ event. For many common applications, we can create a custom
++ handler by subclassing QXmlDefaultHandler, and use this to handle
++ both error and content events:
++
++ \snippet simpleparse/main.cpp 1
++
++ If you don't set at least the content and error handlers, the
++ parser will fall back on its default behavior---and will do
++ nothing.
++
++ The most convenient way to handle the input is to read it in a
++ single pass using the parse() function with an argument that
++ specifies the input source:
++
++ \snippet simpleparse/main.cpp 2
++
++ If you can't parse the entire input in one go (for example, it is
++ huge, or is being delivered over a network connection), data can
++ be fed to the parser in pieces. This is achieved by telling
++ parse() to work incrementally, and making subsequent calls to the
++ parseContinue() function, until all the data has been processed.
++
++ A common way to perform incremental parsing is to connect the \c
++ readyRead() signal of a \l{QNetworkReply} {network reply} a slot,
++ and handle the incoming data there. See QNetworkAccessManager.
++
++ Aspects of the parsing behavior can be adapted using setFeature()
++ and setProperty().
++
++ \snippet code/src_xml_sax_qxml.cpp 0
++
++ QXmlSimpleReader is not reentrant. If you want to use the class
++ in threaded code, lock the code using QXmlSimpleReader with a
++ locking mechanism, such as a QMutex.
++
++ Note that this class is now deprecated, please use QXmlStreamReader or
++ QDomDocument for reading XML files.
++
++ \section1 Entity expansion limit
++
++ QXmlSimpleReader enforces a limit of \c {4096} characters when expanding
++ general and parameter entities. If any entity expands past this limit, the
++ document is considered to be malformed, and an error is raised. This limit
++ can be adjusted using the
++
++ See \l {QXmlSimpleReader::}{setProperty()} for an example of how to apply
++ a new limit.
++
++ \note This limit is only applicable to the internal entities. Use
++ QXmlEntityResolver to handle external entities.
++ */
++
++ static inline bool is_S(QChar ch)
++ {
++ ushort uc = ch.unicode();
++ return (uc == ' ' || uc == '\t' || uc == '\n' || uc == '\r');
++ }
++
++ enum NameChar { NameBeginning, NameNotBeginning, NotName };
++
++ static const char Begi = (char)NameBeginning;
++ static const char NtBg = (char)NameNotBeginning;
++ static const char NotN = (char)NotName;
++
++ static const char nameCharTable[128] =
++ {
++ // 0x00
++ NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
++ NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
++ // 0x10
++ NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
++ NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
++ // 0x20 (0x2D is '-', 0x2E is '.')
++ NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
++ NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
++ // 0x30 (0x30..0x39 are '0'..'9', 0x3A is ':')
++ NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
++ NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
++ // 0x40 (0x41..0x5A are 'A'..'Z')
++ NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ // 0x50 (0x5F is '_')
++ Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
++ // 0x60 (0x61..0x7A are 'a'..'z')
++ NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ // 0x70
++ Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
++ Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
++ };
++
++ static inline NameChar fastDetermineNameChar(QChar ch)
++ {
++ ushort uc = ch.unicode();
++ if (!(uc & ~0x7f)) // uc < 128
++ return (NameChar)nameCharTable[uc];
++
++ QChar::Category cat = ch.category();
++ // ### some these categories might be slightly wrong
++ if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
++ || cat == QChar::Number_Letter)
++ return NameBeginning;
++ if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
++ || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
++ return NameNotBeginning;
++ return NotName;
++ }
++
++ static NameChar determineNameChar(QChar ch)
++ {
++ return fastDetermineNameChar(ch);
++ }
++
++ /*!
++ Constructs a simple XML reader.
++
++ */
++ QXmlSimpleReader::QXmlSimpleReader()
++ : d_ptr(new QXmlSimpleReaderPrivate(this))
++ {
++ }
++
++ /*!
++ Destroys the simple XML reader.
++ */
++ QXmlSimpleReader::~QXmlSimpleReader()
++ {
++ }
++
++ /*!
++ \reimp
++ */
++ bool QXmlSimpleReader::feature(const QString& name, bool *ok) const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++
++ if (ok)
++ *ok = true;
++ if (name == QLatin1String("http://xml.org/sax/features/namespaces")) {
++ return d->useNamespaces;
++ } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) {
++ return d->useNamespacePrefixes;
++ } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
++ return d->reportWhitespaceCharData;
++ } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
++ return d->reportEntities;
++ } else {
++ qWarning("Unknown feature %s", name.toLatin1().data());
++ if (ok)
++ *ok = false;
++ }
++ return false;
++ }
++
++ /*!
++ Turns on the feature \a name if \a enable is true; otherwise turns it off.
++
++ The \a name parameter must be one of the following strings:
++ \table
++ \header \li Feature \li Default \li Notes
++ \li true
++ \li If enabled, namespaces are reported to the content handler.
++ \li false
++ \li If enabled, the original prefixed names
++ and attributes used for namespace declarations are
++ reported.
++ \li true
++ \li If enabled, CharData that consist of
++ only whitespace characters are reported
++ using QXmlContentHandler::characters(). If disabled, whitespace is silently
++ discarded.
++ \li false
++ \li If enabled, the parser reports
++ QXmlContentHandler::startEntity() and
++ QXmlContentHandler::endEntity() events, so character data
++ might be reported in chunks.
++ If disabled, the parser does not report these events, but
++ silently substitutes the entities, and reports the character
++ data in one chunk.
++ \endtable
++
++ \sa feature(), hasFeature()
++ */
++ void QXmlSimpleReader::setFeature(const QString& name, bool enable)
++ {
++ Q_D(QXmlSimpleReader);
++ if (name == QLatin1String("http://xml.org/sax/features/namespaces")) {
++ d->useNamespaces = enable;
++ } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) {
++ d->useNamespacePrefixes = enable;
++ } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
++ d->reportWhitespaceCharData = enable;
++ } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
++ d->reportEntities = enable;
++ } else {
++ qWarning("Unknown feature %s", name.toLatin1().data());
++ }
++ }
++
++ /*! \reimp
++ */
++ bool QXmlSimpleReader::hasFeature(const QString& name) const
++ {
++ if (name == QLatin1String("http://xml.org/sax/features/namespaces")
++ || name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")
++ || name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
++ || name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
++ return true;
++ } else {
++ return false;
++ }
++ }
++
++ constexpr const char *SaxEntityExpansionLimitProperty =
++
++ /*!
++ \reimp
++
++ Returns the value of the property \a name and sets \a ok to \c {true} if the
++ property exists. Otherwise sets \a ok to \c {false} and returns \c nullptr.
++
++ The only supported property is
++ returned value is not a pointer to the limit, but the limit itself, stored
++ in the \c {void *}. Convert it back to an integer using \l qintptr, and
++ never dereference it.
++
++ \code
++ QXmlSimpleReader reader;
++ bool ok = false;
++ void *value =
++ if (ok) {
++ const qintptr limit = reinterpret_cast<qintptr>(value);
++ qDebug() << "The entity expansion limit is" << limit;
++ }
++ \endcode
++ */
++ void* QXmlSimpleReader::property(const QString &name, bool *ok) const
++ {
++ if (name == QLatin1String(SaxEntityExpansionLimitProperty)) {
++ if (ok)
++ *ok = true;
++ Q_D(const QXmlSimpleReader);
++ return reinterpret_cast<void *>(qintptr(d->entityCharacterLimit));
++ }
++
++ if (ok)
++ *ok = false;
++ return nullptr;
++ }
++
++ /*!
++ \reimp
++
++ Sets the property \a name to \a value.
++
++ The only supported property is
++ input value is not a pointer to the limit, but the limit itself, converted
++ to \c {void *} via \l qintptr. Values that are not positive or do not fit
++ into an \c int are ignored.
++
++ \code
++ QXmlSimpleReader reader;
++ const qintptr limit = 1024;
++ reinterpret_cast<void *>(limit));
++ \endcode
++ */
++ void QXmlSimpleReader::setProperty(const QString &name, void *value)
++ {
++ if (name == QLatin1String(SaxEntityExpansionLimitProperty)) {
++ const qintptr limit = reinterpret_cast<qintptr>(value);
++ if (limit > 0 && limit <= INT_MAX) {
++ Q_D(QXmlSimpleReader);
++ d->entityCharacterLimit = int(limit);
++ }
++ }
++ }
++
++ /*!
++ \reimp
++ */
++ bool QXmlSimpleReader::hasProperty(const QString &name) const
++ {
++ return name == QLatin1String(SaxEntityExpansionLimitProperty);
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setEntityResolver(QXmlEntityResolver* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->entityRes = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlEntityResolver* QXmlSimpleReader::entityResolver() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->entityRes;
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setDTDHandler(QXmlDTDHandler* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->dtdHnd = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->dtdHnd;
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setContentHandler(QXmlContentHandler* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->contentHnd = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlContentHandler* QXmlSimpleReader::contentHandler() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->contentHnd;
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setErrorHandler(QXmlErrorHandler* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->errorHnd = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlErrorHandler* QXmlSimpleReader::errorHandler() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->errorHnd;
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setLexicalHandler(QXmlLexicalHandler* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->lexicalHnd = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->lexicalHnd;
++ }
++
++ /*!
++ \reimp
++ */
++ void QXmlSimpleReader::setDeclHandler(QXmlDeclHandler* handler)
++ {
++ Q_D(QXmlSimpleReader);
++ d->declHnd = handler;
++ }
++
++ /*!
++ \reimp
++ */
++ QXmlDeclHandler* QXmlSimpleReader::declHandler() const
++ {
++ const QXmlSimpleReaderPrivate *d = d_func();
++ return d->declHnd;
++ }
++
++ /*!
++ \reimp
++ */
++ bool QXmlSimpleReader::parse(const QXmlInputSource& input)
++ {
++ return parse(&input, false);
++ }
++
++ /*!
++ Reads an XML document from \a input and parses it in one pass (non-incrementally).
++ Returns \c true if the parsing was successful; otherwise returns \c false.
++ */
++ bool QXmlSimpleReader::parse(const QXmlInputSource* input)
++ {
++ return parse(input, false);
++ }
++
++ /*!
++ Reads an XML document from \a input and parses it. Returns \c true
++ if the parsing is completed successfully; otherwise returns \c false,
++ indicating that an error occurred.
++
++ If \a incremental is false, this function will return false if the XML
++ file is not read completely. The parsing cannot be continued in this
++ case.
++
++ If \a incremental is true, the parser does not return false if
++ it reaches the end of the \a input before reaching the end
++ of the XML file. Instead, it stores the state of the parser so that
++ parsing can be continued later when more data is available.
++ In such a case, you can use the function parseContinue() to
++ continue with parsing. This class stores a pointer to the input
++ source \a input and the parseContinue() function tries to read from
++ that input source. Therefore, you should not delete the input
++ source \a input until you no longer need to call parseContinue().
++
++ If this function is called with \a incremental set to true
++ while an incremental parse is in progress, a new parsing
++ session will be started, and the previous session will be lost.
++
++ \sa parseContinue(), QTcpSocket
++ */
++ bool QXmlSimpleReader::parse(const QXmlInputSource *input, bool incremental)
++ {
++ Q_D(QXmlSimpleReader);
++
++ d->includedParameterEntitySize = 0;
++
++ if (incremental) {
++ d->initIncrementalParsing();
++ } else {
++ delete d->parseStack;
++ d->parseStack = nullptr;
++ }
++ d->init(input);
++
++ // call the handler
++ if (d->contentHnd) {
++ d->contentHnd->setDocumentLocator(d->locator.get());
++ if (!d->contentHnd->startDocument()) {
++ d->reportParseError(d->contentHnd->errorString());
++ clear(d->tags);
++ return false;
++ }
++ }
++ d->skipped_entity_in_content = false;
++ return d->parseBeginOrContinue(0, incremental);
++ }
++
++ /*!
++ Continues incremental parsing, taking input from the
++ QXmlInputSource that was specified with the most recent
++ call to parse(). To use this function, you \e must have called
++ parse() with the incremental argument set to true.
++
++ Returns \c false if a parsing error occurs; otherwise returns \c true,
++ even if the end of the XML file has not been reached. You can
++ continue parsing at a later stage by calling this function again
++ when there is more data available to parse.
++
++ Calling this function when there is no data available in the input
++ source indicates to the reader that the end of the XML file has
++ been reached. If the input supplied up to this point was
++ not well-formed then a parsing error occurs, and false is returned.
++ If the input supplied was well-formed, true is returned.
++ It is important to end the input in this way because it allows you
++ to reuse the reader to parse other XML files.
++
++ Calling this function after the end of file has been reached, but
++ without available data will cause false to be returned whether the
++ previous input was well-formed or not.
++
++ \sa parse(), QXmlInputSource::data(), QXmlInputSource::next()
++ */
++ bool QXmlSimpleReader::parseContinue()
++ {
++ Q_D(QXmlSimpleReader);
++ if (d->parseStack == nullptr || d->parseStack->isEmpty())
++ return false;
++ d->initData();
++ int state = d->parseStack->pop().state;
++ return d->parseBeginOrContinue(state, true);
++ }
++
++ /*
++ Common part of parse() and parseContinue()
++ */
++ bool QXmlSimpleReaderPrivate::parseBeginOrContinue(int state, bool incremental)
++ {
++ bool atEndOrig = atEnd();
++
++ if (state==0) {
++ if (!parseProlog()) {
++ if (incremental && error.isNull()) {
++ pushParseState(nullptr, 0);
++ return true;
++ } else {
++ clear(tags);
++ return false;
++ }
++ }
++ state = 1;
++ }
++ if (state==1) {
++ if (!parseElement()) {
++ if (incremental && error.isNull()) {
++ pushParseState(nullptr, 1);
++ return true;
++ } else {
++ clear(tags);
++ return false;
++ }
++ }
++ state = 2;
++ }
++ // parse Misc*
++ while (!atEnd()) {
++ if (!parseMisc()) {
++ if (incremental && error.isNull()) {
++ pushParseState(nullptr, 2);
++ return true;
++ } else {
++ clear(tags);
++ return false;
++ }
++ }
++ }
++ if (!atEndOrig && incremental) {
++ // we parsed something at all, so be prepared to come back later
++ pushParseState(nullptr, 2);
++ return true;
++ }
++ // is stack empty?
++ if (!tags.empty() && !error.isNull()) {
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
++ clear(tags);
++ return false;
++ }
++ // call the handler
++ if (contentHnd) {
++ delete parseStack;
++ parseStack = nullptr;
++ if (!contentHnd->endDocument()) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ }
++
++ /*
++ Parses parts of the document that can potentially recurse.
++ For example, when parsing an element, we can have:
++ element -> content -> element -> content -> ...
++
++ Instead of recursing into the parse*() calls, this method creates a local
++ stack of calls.
++ */
++ bool QXmlSimpleReaderPrivate::parseNestedFrames(FrameType outermost)
++ {
++ QVarLengthArray<FrameState, 16> frames;
++
++ const auto frameTypeToFunc = [](FrameType t) -> ParseFunction {
++ switch (t) {
++ case FrameType::Element:
++ return &QXmlSimpleReaderPrivate::parseElement;
++ case FrameType::Content:
++ return &QXmlSimpleReaderPrivate::parseContent;
++ case FrameType::ChoiceSeq:
++ return &QXmlSimpleReaderPrivate::parseChoiceSeq;
++ }
++ Q_UNREACHABLE_RETURN(nullptr);
++ };
++
++ // Suspends frames[0..last], innermost first, so the outermost ends up on
++ // top of parseStack.
++ const auto suspendFrames = [&frames, &frameTypeToFunc, this](qsizetype last) {
++ for (qsizetype i = last; i >= 0; --i)
++ parseFailed(frameTypeToFunc(frames[i].frame), frames[i].state);
++ };
++
++ const auto enterFrame = [this, &frames](FrameType t) {
++ if (t == FrameType::Content)
++ contentCharDataRead = false;
++ frames.append({t, ItemInitState});
++ };
++
++ if (parseStack == nullptr || parseStack->isEmpty()) {
++ enterFrame(outermost);
++ } else {
++ // Continuing an incremental parse: parseStack holds the state of this
++ // frame, then the states of the frames that were nested inside it,
++ // outermost first, and finally the function that ran out of data.
++ Q_ASSERT(parseStack->top().function == frameTypeToFunc(outermost));
++ frames.append({outermost, parseStack->pop().state});
++ while (!parseStack->isEmpty()) {
++ const ParseFunction func = parseStack->top().function;
++ if (func == &QXmlSimpleReaderPrivate::parseElement)
++ frames.append({FrameType::Element, parseStack->pop().state});
++ else if (func == &QXmlSimpleReaderPrivate::parseContent)
++ frames.append({FrameType::Content, parseStack->pop().state});
++ else if (func == &QXmlSimpleReaderPrivate::parseChoiceSeq)
++ frames.append({FrameType::ChoiceSeq, parseStack->pop().state});
++ else
++ break;
++ }
++ // Now all the potentially recursing calls are added to frames
++ #if defined(QT_QXML_DEBUG)
++ qDebug("QXmlSimpleReader: parseNestedFrames (cont) with %lld frames",
++ qlonglong(frames.size()));
++ #endif
++ if (!resumeSuspendedCall()) {
++ suspendFrames(frames.size() - 1);
++ return false;
++ }
++ }
++
++ const auto stepFrame = [this](FrameState &innermost) {
++ switch (innermost.frame) {
++ case FrameType::Content:
++ return parseContentFrame(innermost.state);
++ case FrameType::Element:
++ return parseElementFrame(innermost.state);
++ case FrameType::ChoiceSeq:
++ return parseChoiceSeqFrame(innermost.state);
++ }
++ Q_UNREACHABLE_RETURN(FrameParseResult::Failed);
++ };
++
++ while (true) {
++ switch (stepFrame(frames.back())) {
++ case FrameParseResult::EnterContent:
++ enterFrame(FrameType::Content);
++ break;
++ case FrameParseResult::EnterElement:
++ enterFrame(FrameType::Element);
++ break;
++ case FrameParseResult::EnterChoiceSeq:
++ enterFrame(FrameType::ChoiceSeq);
++ break;
++ case FrameParseResult::Done:
++ frames.removeLast();
++ if (frames.isEmpty())
++ return true;
++ break;
++ case FrameParseResult::Failed:
++ // The innermost frame either ran out of data while parsing
++ // incrementally, in which case it has saved its own state
++ // already and only the frames around it still need to save
++ // theirs, or it reported a parse error, in which case no state
++ // is saved at all.
++ suspendFrames(frames.size() - 2);
++ return false;
++ }
++ }
++ }
++
++ //
++ // The following private parse functions have another semantics for the return
++ // value: They return true iff parsing has finished successfully (i.e. the end
++ // of the XML file must be reached!). If one of these functions return false,
++ // there is only an error when d->error.isNULL() is also false.
++ //
++
++ /*
++ For the incremental parsing, it is very important that the parse...()
++ functions have a certain structure. Since it might be hard to understand how
++ they work, here is a description of the layout of these functions:
++
++ bool QXmlSimpleReader::parse...()
++ {
++ (1) const signed char Init = 0;
++ ...
++
++ (2) const signed char Inp... = 0;
++ ...
++
++ (3) static const signed char table[3][2] = {
++ ...
++ };
++ signed char state;
++ signed char input;
++
++ (4) if (d->parseStack == nullptr || d->parseStack->isEmpty()) {
++ (4a) ...
++ } else {
++ (4b) ...
++ }
++
++ for (; ;) {
++ (5) switch (state) {
++ ...
++ }
++
++ (6)
++ (6a) if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReader::parseNmtoken, state);
++ return false;
++ }
++ (6b) if (determineNameChar(c) != NotName) {
++ ...
++ }
++ (7) state = table[state][input];
++
++ (8) switch (state) {
++ ...
++ }
++ }
++ }
++
++ Explanation:
++ ad 1: constants for the states (used in the transition table)
++ ad 2: constants for the input (used in the transition table)
++ ad 3: the transition table for the state machine
++ ad 4: test if we are in a parseContinue() step
++ a) if no, do initializations
++ b) if yes, restore the state and call parse functions recursively
++ ad 5: Do some actions according to the state; from the logical execution
++ order, this code belongs after 8 (see there for an explanation)
++ ad 6: Check the character that is at the actual "cursor" position:
++ a) If we reached the EOF, report either error or push the state (in the
++ case of incremental parsing).
++ b) Otherwise, set the input character constant for the transition
++ table.
++ ad 7: Get the new state according to the input that was read.
++ ad 8: Do some actions according to the state. The last line in every case
++ statement reads new data (i.e. it move the cursor). This can also be
++ done by calling another parse...() function. If you need processing for
++ this state after that, you have to put it into the switch statement 5.
++ This ensures that you have a well defined re-entry point, when you ran
++ out of data.
++ */
++
++ /*
++ Parses the prolog [22].
++ */
++
++ bool QXmlSimpleReaderPrivate::parseProlog()
++ {
++ const signed char Init = 0;
++ const signed char EatWS = 1; // eat white spaces
++ const signed char Lt = 2; // '<' read
++ const signed char Em = 3; // '!' read
++ const signed char DocType = 4; // read doctype
++ const signed char Comment = 5; // read comment
++ const signed char CommentR = 6; // same as Comment, but already reported
++ const signed char PInstr = 7; // read PI
++ const signed char PInstrR = 8; // same as PInstr, but already reported
++ const signed char Done = 9;
++
++ const signed char InpWs = 0;
++ const signed char InpLt = 1; // <
++ const signed char InpQm = 2; // ?
++ const signed char InpEm = 3; // !
++ const signed char InpD = 4; // D
++ const signed char InpDash = 5; // -
++ const signed char InpUnknown = 6;
++
++ static const signed char table[9][7] = {
++ /* InpWs InpLt InpQm InpEm InpD InpDash InpUnknown */
++ { EatWS, Lt, -1, -1, -1, -1, -1 }, // Init
++ { -1, Lt, -1, -1, -1, -1, -1 }, // EatWS
++ { -1, -1, PInstr,Em, Done, -1, Done }, // Lt
++ { -1, -1, -1, -1, DocType, Comment, -1 }, // Em
++ { EatWS, Lt, -1, -1, -1, -1, -1 }, // DocType
++ { EatWS, Lt, -1, -1, -1, -1, -1 }, // Comment
++ { EatWS, Lt, -1, -1, -1, -1, -1 }, // CommentR
++ { EatWS, Lt, -1, -1, -1, -1, -1 }, // PInstr
++ { EatWS, Lt, -1, -1, -1, -1, -1 } // PInstrR
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ if (parseStack == nullptr|| parseStack->isEmpty()) {
++ xmldecl_possible = true;
++ doctype_read = false;
++ }
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseProlog);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case DocType:
++ if (doctype_read) {
++ reportParseError(QLatin1String(XMLERR_MORETHANONEDOCTYPE));
++ return false;
++ } else {
++ doctype_read = false;
++ }
++ break;
++ case Comment:
++ if (lexicalHnd) {
++ if (!lexicalHnd->comment(string())) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ state = CommentR;
++ break;
++ case PInstr:
++ // call the handler
++ if (contentHnd) {
++ if (xmldecl_possible && !xmlVersion.isEmpty()) {
++ QString value(QLatin1String("version='"));
++ value += xmlVersion;
++ value += QLatin1Char('\'');
++ if (!encoding.isEmpty()) {
++ value += QLatin1String(" encoding='");
++ value += encoding;
++ value += QLatin1Char('\'');
++ }
++ if (standalone == QXmlSimpleReaderPrivate::Yes) {
++ value += QLatin1String(" standalone='yes'");
++ } else if (standalone == QXmlSimpleReaderPrivate::No) {
++ value += QLatin1String(" standalone='no'");
++ }
++ if (!contentHnd->processingInstruction(QLatin1String("xml"), value)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ } else {
++ if (!contentHnd->processingInstruction(name(), string())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ }
++ // XML declaration only on first position possible
++ xmldecl_possible = false;
++ state = PInstrR;
++ break;
++ case Done:
++ return true;
++ case -1:
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseProlog, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('<')) {
++ input = InpLt;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else if (c == QLatin1Char('!')) {
++ input = InpEm;
++ } else if (c == QLatin1Char('D')) {
++ input = InpD;
++ } else if (c == QLatin1Char('-')) {
++ input = InpDash;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case EatWS:
++ // XML declaration only on first position possible
++ xmldecl_possible = false;
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
++ return false;
++ }
++ break;
++ case Lt:
++ next();
++ break;
++ case Em:
++ // XML declaration only on first position possible
++ xmldecl_possible = false;
++ next();
++ break;
++ case DocType:
++ if (!parseDoctype()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
++ return false;
++ }
++ break;
++ case Comment:
++ case CommentR:
++ if (!parseComment()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
++ return false;
++ }
++ break;
++ case PInstr:
++ case PInstrR:
++ parsePI_xmldecl = xmldecl_possible;
++ if (!parsePI()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
++ return false;
++ }
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse an element [39].
++
++ Precondition: the opening '<' is already read.
++ */
++ bool QXmlSimpleReaderPrivate::parseElement()
++ {
++ return parseNestedFrames(FrameType::Element);
++ }
++
++ /*
++ Parses the element, except its content.
++ Returns FrameParseResult::EnterContent when it reaches the content, so that
++ parseNestedFrames() could call parseContentFrame() from the outer loop.
++ Continues parsing the element when its content is handled.
++ */
++ QXmlSimpleReaderPrivate::FrameParseResult QXmlSimpleReaderPrivate::parseElementFrame(int &state)
++ {
++ const int Init = 0;
++ const int ReadName = 1;
++ const int Ws1 = 2;
++ const int STagEnd = 3;
++ const int STagEnd2 = 4;
++ const int ETagBegin = 5;
++ const int ETagBegin2 = 6;
++ const int Ws2 = 7;
++ const int EmptyTag = 8;
++ const int Attrib = 9;
++ const int AttribPro = 10; // like Attrib, but processAttribute was already called
++ const int Ws3 = 11;
++ const int Done = 12;
++
++ const int InpWs = 0; // whitespace
++ const int InpNameBe = 1; // NameBeginning
++ const int InpGt = 2; // >
++ const int InpSlash = 3; // /
++ const int InpUnknown = 4;
++
++ static const int table[12][5] = {
++ /* InpWs InpNameBe InpGt InpSlash InpUnknown */
++ { -1, ReadName, -1, -1, -1 }, // Init
++ { Ws1, Attrib, STagEnd, EmptyTag, -1 }, // ReadName
++ { -1, Attrib, STagEnd, EmptyTag, -1 }, // Ws1
++ { STagEnd2, STagEnd2, STagEnd2, STagEnd2, STagEnd2 }, // STagEnd
++ { -1, -1, -1, ETagBegin, -1 }, // STagEnd2
++ { -1, ETagBegin2, -1, -1, -1 }, // ETagBegin
++ { Ws2, -1, Done, -1, -1 }, // ETagBegin2
++ { -1, -1, Done, -1, -1 }, // Ws2
++ { -1, -1, Done, -1, -1 }, // EmptyTag
++ { Ws3, Attrib, STagEnd, EmptyTag, -1 }, // Attrib
++ { Ws3, Attrib, STagEnd, EmptyTag, -1 }, // AttribPro
++ { -1, Attrib, STagEnd, EmptyTag, -1 } // Ws3
++ };
++ static_assert(Init == ItemInitState);
++ int input;
++
++ for (;;) {
++ switch (state) {
++ case ReadName:
++ // store it on the stack
++ tags.push(name());
++ // empty the attributes
++ attList.clear();
++ if (useNamespaces)
++ namespaceSupport.pushContext();
++ break;
++ case ETagBegin2:
++ if (!processElementETagBegin2())
++ return FrameParseResult::Failed;
++ break;
++ case Attrib:
++ if (!processElementAttribute())
++ return FrameParseResult::Failed;
++ state = AttribPro;
++ break;
++ case Done:
++ return FrameParseResult::Done;
++ case -1:
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
++ return FrameParseResult::Failed;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseElement, state);
++ return FrameParseResult::Failed;
++ }
++ if (fastDetermineNameChar(c) == NameBeginning) {
++ input = InpNameBe;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('/')) {
++ input = InpSlash;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case ReadName:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case Ws1:
++ case Ws2:
++ case Ws3:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case STagEnd:
++ // call the handler
++ if (contentHnd) {
++ if (useNamespaces) {
++ QString uri, lname;
++ namespaceSupport.processName(tags.top(), false, uri, lname);
++ if (!contentHnd->startElement(uri, lname, tags.top(), attList)) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ } else {
++ if (!contentHnd->startElement(QString(), QString(), tags.top(), attList)) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ }
++ next();
++ break;
++ case STagEnd2:
++ // the content of this element follows
++ return FrameParseResult::EnterContent;
++ case ETagBegin:
++ next();
++ break;
++ case ETagBegin2:
++ // get the name of the tag
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case EmptyTag:
++ if (tags.empty()) {
++ reportParseError(QLatin1String(XMLERR_TAGMISMATCH));
++ return FrameParseResult::Failed;
++ }
++ if (!processElementEmptyTag())
++ return FrameParseResult::Failed;
++ next();
++ break;
++ case Attrib:
++ case AttribPro:
++ // get name and value of attribute
++ if (!parseAttribute()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return FrameParseResult::Failed;
++ }
++
++ /*
++ Helper to break down the size of the code in the case statement.
++ Return false on error, otherwise true.
++ */
++ bool QXmlSimpleReaderPrivate::processElementEmptyTag()
++ {
++ QString uri, lname;
++ // pop the stack and call the handler
++ if (contentHnd) {
++ if (useNamespaces) {
++ // report startElement first...
++ namespaceSupport.processName(tags.top(), false, uri, lname);
++ if (!contentHnd->startElement(uri, lname, tags.top(), attList)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ // ... followed by endElement...
++ const bool endElementReturnedFalse = !contentHnd->endElement(uri, lname, tags.top());
++ tags.pop();
++ if (endElementReturnedFalse) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ // ... followed by endPrefixMapping
++ QStringList prefixesBefore, prefixesAfter;
++ if (contentHnd) {
++ prefixesBefore = namespaceSupport.prefixes();
++ }
++ namespaceSupport.popContext();
++ // call the handler for prefix mapping
++ prefixesAfter = namespaceSupport.prefixes();
++ for (QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it) {
++ if (!prefixesAfter.contains(*it)) {
++ if (!contentHnd->endPrefixMapping(*it)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ }
++ } else {
++ // report startElement first...
++ if (!contentHnd->startElement(QString(), QString(), tags.top(), attList)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ // ... followed by endElement
++ const bool endElementReturnedFalse = !contentHnd->endElement(QString(), QString(), tags.top());
++ tags.pop();
++ if (endElementReturnedFalse) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ } else {
++ tags.pop();
++ namespaceSupport.popContext();
++ }
++ return true;
++ }
++ /*
++ Helper to break down the size of the code in the case statement.
++ Return false on error, otherwise true.
++ */
++ bool QXmlSimpleReaderPrivate::processElementETagBegin2()
++ {
++ const QString &name = QXmlSimpleReaderPrivate::name();
++
++ // pop the stack and compare it with the name
++ const bool nameIsTagsTop = tags.top() == name;
++ tags.pop();
++ if (!nameIsTagsTop) {
++ reportParseError(QLatin1String(XMLERR_TAGMISMATCH));
++ return false;
++ }
++ // call the handler
++ if (contentHnd) {
++ QString uri, lname;
++
++ if (useNamespaces)
++ namespaceSupport.processName(name, false, uri, lname);
++ if (!contentHnd->endElement(uri, lname, name)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ if (useNamespaces) {
++ NamespaceMap prefixesBefore, prefixesAfter;
++ if (contentHnd)
++ prefixesBefore = namespaceSupport.d->ns;
++
++ namespaceSupport.popContext();
++ // call the handler for prefix mapping
++ if (contentHnd) {
++ prefixesAfter = namespaceSupport.d->ns;
++ if (prefixesBefore.size() != prefixesAfter.size()) {
++ for (NamespaceMap::const_iterator it = prefixesBefore.constBegin(); it != prefixesBefore.constEnd(); ++it) {
++ if (!it.key().isEmpty() && !prefixesAfter.contains(it.key())) {
++ if (!contentHnd->endPrefixMapping(it.key())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ }
++ }
++ }
++ }
++ return true;
++ }
++ /*
++ Helper to break down the size of the code in the case statement.
++ Return false on error, otherwise true.
++ */
++ bool QXmlSimpleReaderPrivate::processElementAttribute()
++ {
++ QString uri, lname, prefix;
++ const QString &name = QXmlSimpleReaderPrivate::name();
++ const QString &string = QXmlSimpleReaderPrivate::string();
++
++ auto tryAppend = [this](const QString &qName, const QString &uri,
++ const QString &localPart, const QString &value) {
++ if (attList.length() < INT_MAX) {
++ attList.append(qName, uri, localPart, value);
++ return true;
++ }
++ return false;
++ };
++
++ // add the attribute to the list
++ if (useNamespaces) {
++ // is it a namespace declaration?
++ namespaceSupport.splitName(name, prefix, lname);
++ if (prefix == QLatin1String("xmlns")) {
++ // namespace declaration
++ namespaceSupport.setPrefix(lname, string);
++ if (useNamespacePrefixes) {
++ // according to http://www.w3.org/2000/xmlns/, the "prefix"
++ // xmlns maps to the namespace name
++ if (!tryAppend(name, QLatin1String("http://www.w3.org/2000/xmlns/"),
++ lname, string)) {
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
++ return false;
++ }
++ }
++ // call the handler for prefix mapping
++ if (contentHnd) {
++ if (!contentHnd->startPrefixMapping(lname, string)) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ } else {
++ // no namespace delcaration
++ namespaceSupport.processName(name, true, uri, lname);
++ if (!tryAppend(name, uri, lname, string)) {
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
++ return false;
++ }
++ }
++ } else {
++ // no namespace support
++ if (!tryAppend(name, uri, lname, string)) {
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
++ return false;
++ }
++ }
++ return true;
++ }
++
++ /*
++ Parse a content [43].
++
++ A content is only used between tags. If a end tag is found the < is already
++ read and the head stand on the '/' of the end tag '</name>'.
++ */
++ bool QXmlSimpleReaderPrivate::parseContent()
++ {
++ return parseNestedFrames(FrameType::Content);
++ }
++
++ /*
++ Parses the element's content, but stops at a nested element.
++ Returns FrameParseResult::EnterElement when it reaches the nested element,
++ so that parseNestedFrames() could call parseElementFrame() from the outer
++ loop. Continues parsing the content when the nested element is handled.
++ */
++ QXmlSimpleReaderPrivate::FrameParseResult QXmlSimpleReaderPrivate::parseContentFrame(int &state)
++ {
++ const signed char Init = 0;
++ const signed char ChD = 1; // CharData
++ const signed char ChD1 = 2; // CharData help state
++ const signed char ChD2 = 3; // CharData help state
++ const signed char Ref = 4; // Reference
++ const signed char Lt = 5; // '<' read
++ const signed char PInstr = 6; // PI
++ const signed char PInstrR = 7; // same as PInstr, but already reported
++ const signed char Elem = 8; // Element
++ const signed char Em = 9; // '!' read
++ const signed char Com = 10; // Comment
++ const signed char ComR = 11; // same as Com, but already reported
++ const signed char CDS = 12; // CDSect
++ const signed char CDS1 = 13; // read a CDSect
++ const signed char CDS2 = 14; // read a CDSect (help state)
++ const signed char CDS3 = 15; // read a CDSect (help state)
++ const signed char Done = 16; // finished reading content
++
++ const signed char InpLt = 0; // <
++ const signed char InpGt = 1; // >
++ const signed char InpSlash = 2; // /
++ const signed char InpQMark = 3; // ?
++ const signed char InpEMark = 4; // !
++ const signed char InpAmp = 5; // &
++ const signed char InpDash = 6; // -
++ const signed char InpOpenB = 7; // [
++ const signed char InpCloseB = 8; //]
++ const signed char InpUnknown = 9;
++
++ static const signed char mapCLT2FSMChar[] = {
++ InpUnknown, // white space
++ InpUnknown, // %
++ InpAmp, // &
++ InpGt, // >
++ InpLt, // <
++ InpSlash, // /
++ InpQMark, // ?
++ InpEMark, // !
++ InpDash, // -
++ InpCloseB, //]
++ InpOpenB, // [
++ InpUnknown, // =
++ InpUnknown, // "
++ InpUnknown, // '
++ InpUnknown // unknown
++ };
++
++ static const signed char table[16][10] = {
++ /* InpLt InpGt InpSlash InpQMark InpEMark InpAmp InpDash InpOpenB InpCloseB InpUnknown */
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // Init
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // ChD
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD1
++ { Lt, -1, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD2
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Ref (same as Init)
++ { -1, -1, Done, PInstr, Em, -1, -1, -1, -1, Elem }, // Lt
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PInstr (same as Init)
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PInstrR
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Elem (same as Init)
++ { -1, -1, -1, -1, -1, -1, Com, CDS, -1, -1 }, // Em
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Com (same as Init)
++ { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // ComR
++ { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS
++ { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS1
++ { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 }, // CDS2
++ { CDS1, Init, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 } // CDS3
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ for (;;) {
++ switch (state) {
++ case Ref:
++ if (!contentCharDataRead)
++ contentCharDataRead = parseReference_charDataRead;
++ break;
++ case PInstr:
++ if (contentHnd) {
++ if (!contentHnd->processingInstruction(name(),string())) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ state = PInstrR;
++ break;
++ case Com:
++ if (lexicalHnd) {
++ if (!lexicalHnd->comment(string())) {
++ reportParseError(lexicalHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ state = ComR;
++ break;
++ case CDS:
++ stringClear();
++ break;
++ case CDS2:
++ if (!atEnd() && c != QLatin1Char(']'))
++ stringAddC(QLatin1Char(']'));
++ break;
++ case CDS3:
++ // test if this skipping was legal
++ if (!atEnd()) {
++ if (c == QLatin1Char('>')) {
++ // the end of the CDSect
++ if (lexicalHnd) {
++ if (!lexicalHnd->startCDATA()) {
++ reportParseError(lexicalHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ if (contentHnd) {
++ if (!contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ if (lexicalHnd) {
++ if (!lexicalHnd->endCDATA()) {
++ reportParseError(lexicalHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ } else if (c == QLatin1Char(']')) {
++ // three or more ']'
++ stringAddC(QLatin1Char(']'));
++ } else {
++ // after ']]' comes another character
++ stringAddC(QLatin1Char(']'));
++ stringAddC(QLatin1Char(']'));
++ }
++ }
++ break;
++ case Done:
++ // call the handler for CharData
++ if (contentHnd) {
++ if (contentCharDataRead) {
++ if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
++ if (!contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ }
++ }
++ // Done
++ return FrameParseResult::Done;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGCONTENT));
++ return FrameParseResult::Failed;
++ }
++
++ // get input (use lookup-table instead of nested ifs for performance
++ // reasons)
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ if (c.row()) {
++ input = InpUnknown;
++ } else {
++ input = mapCLT2FSMChar[charLookupTable[c.cell()]];
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Init:
++ // skip the ending '>' of a CDATASection
++ next();
++ break;
++ case ChD:
++ // on first call: clear string
++ if (!contentCharDataRead) {
++ contentCharDataRead = true;
++ stringClear();
++ }
++ stringAddC();
++ if (reportEntities) {
++ if (!reportEndEntities())
++ return FrameParseResult::Failed;
++ }
++ next();
++ break;
++ case ChD1:
++ // on first call: clear string
++ if (!contentCharDataRead) {
++ contentCharDataRead = true;
++ stringClear();
++ }
++ stringAddC();
++ if (reportEntities) {
++ if (!reportEndEntities())
++ return FrameParseResult::Failed;
++ }
++ next();
++ break;
++ case ChD2:
++ stringAddC();
++ if (reportEntities) {
++ if (!reportEndEntities())
++ return FrameParseResult::Failed;
++ }
++ next();
++ break;
++ case Ref:
++ if (!contentCharDataRead) {
++ // reference may be CharData; so clear string to be safe
++ stringClear();
++ parseReference_context = InContent;
++ if (!parseReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ } else {
++ if (reportEntities) {
++ // report character data in chunks
++ if (contentHnd) {
++ if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
++ if (!contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ }
++ stringClear();
++ }
++ parseReference_context = InContent;
++ if (!parseReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ }
++ break;
++ case Lt:
++ // call the handler for CharData
++ if (contentHnd) {
++ if (contentCharDataRead) {
++ if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
++ if (!contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return FrameParseResult::Failed;
++ }
++ }
++ }
++ }
++ contentCharDataRead = false;
++ next();
++ break;
++ case PInstr:
++ case PInstrR:
++ parsePI_xmldecl = false;
++ if (!parsePI()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case Elem:
++ // a child element follows
++ return FrameParseResult::EnterElement;
++ case Em:
++ next();
++ break;
++ case Com:
++ case ComR:
++ if (!parseComment()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case CDS:
++ parseString_s = QLatin1String("[CDATA[");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case CDS1:
++ stringAddC();
++ next();
++ break;
++ case CDS2:
++ // skip ']'
++ next();
++ break;
++ case CDS3:
++ // skip ']'...
++ next();
++ break;
++ }
++ }
++ return FrameParseResult::Failed;
++ }
++
++ bool QXmlSimpleReaderPrivate::reportEndEntities()
++ {
++ qsizetype count = xmlRefStack.size();
++ while (count != 0 && xmlRefStack.top().isEmpty()) {
++ if (contentHnd) {
++ if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
++ if (!contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ }
++ stringClear();
++ if (lexicalHnd) {
++ if (!lexicalHnd->endEntity(xmlRefStack.top().name)) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ xmlRefStack.pop_back();
++ count--;
++ }
++ return true;
++ }
++
++ /*
++ Parse Misc [27].
++ */
++ bool QXmlSimpleReaderPrivate::parseMisc()
++ {
++ const signed char Init = 0;
++ const signed char Lt = 1; // '<' was read
++ const signed char Comment = 2; // read comment
++ const signed char eatWS = 3; // eat whitespaces
++ const signed char PInstr = 4; // read PI
++ const signed char Comment2 = 5; // read comment
++
++ const signed char InpWs = 0; // S
++ const signed char InpLt = 1; // <
++ const signed char InpQm = 2; // ?
++ const signed char InpEm = 3; // !
++ const signed char InpUnknown = 4;
++
++ static const signed char table[3][5] = {
++ /* InpWs InpLt InpQm InpEm InpUnknown */
++ { eatWS, Lt, -1, -1, -1 }, // Init
++ { -1, -1, PInstr,Comment, -1 }, // Lt
++ { -1, -1, -1, -1, Comment2 } // Comment
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseMisc);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case eatWS:
++ return true;
++ case PInstr:
++ if (contentHnd) {
++ if (!contentHnd->processingInstruction(name(),string())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ case Comment2:
++ if (lexicalHnd) {
++ if (!lexicalHnd->comment(string())) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseMisc, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('<')) {
++ input = InpLt;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else if (c == QLatin1Char('!')) {
++ input = InpEm;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case eatWS:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
++ return false;
++ }
++ break;
++ case Lt:
++ next();
++ break;
++ case PInstr:
++ parsePI_xmldecl = false;
++ if (!parsePI()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
++ return false;
++ }
++ break;
++ case Comment:
++ next();
++ break;
++ case Comment2:
++ if (!parseComment()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
++ return false;
++ }
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a processing instruction [16].
++
++ If xmldec is true, it tries to parse a PI or a XML declaration [23].
++
++ Precondition: the beginning '<' of the PI is already read and the head stand
++ on the '?' of '<?'.
++
++ If this funktion was successful, the head-position is on the first
++ character after the PI.
++ */
++ bool QXmlSimpleReaderPrivate::parsePI()
++ {
++ const signed char Init = 0;
++ const signed char QmI = 1; // ? was read
++ const signed char Name = 2; // read Name
++ const signed char XMLDecl = 3; // read XMLDecl
++ const signed char Ws1 = 4; // eat ws after "xml" of XMLDecl
++ const signed char PInstr = 5; // read PI
++ const signed char Ws2 = 6; // eat ws after Name of PI
++ const signed char Version = 7; // read versionInfo
++ const signed char Ws3 = 8; // eat ws after versionInfo
++ const signed char EorSD = 9; // read EDecl or SDDecl
++ const signed char Ws4 = 10; // eat ws after EDecl or SDDecl
++ const signed char SD = 11; // read SDDecl
++ const signed char Ws5 = 12; // eat ws after SDDecl
++ const signed char ADone = 13; // almost done
++ const signed char Char = 14; // Char was read
++ const signed char Qm = 15; // Qm was read
++ const signed char Done = 16; // finished reading content
++
++ const signed char InpWs = 0; // whitespace
++ const signed char InpNameBe = 1; // NameBeginning
++ const signed char InpGt = 2; // >
++ const signed char InpQm = 3; // ?
++ const signed char InpUnknown = 4;
++
++ static const signed char table[16][5] = {
++ /* InpWs, InpNameBe InpGt InpQm InpUnknown */
++ { -1, -1, -1, QmI, -1 }, // Init
++ { -1, Name, -1, -1, -1 }, // QmI
++ { -1, -1, -1, -1, -1 }, // Name (this state is left not through input)
++ { Ws1, -1, -1, -1, -1 }, // XMLDecl
++ { -1, Version, -1, -1, -1 }, // Ws1
++ { Ws2, -1, -1, Qm, -1 }, // PInstr
++ { Char, Char, Char, Qm, Char }, // Ws2
++ { Ws3, -1, -1, ADone, -1 }, // Version
++ { -1, EorSD, -1, ADone, -1 }, // Ws3
++ { Ws4, -1, -1, ADone, -1 }, // EorSD
++ { -1, SD, -1, ADone, -1 }, // Ws4
++ { Ws5, -1, -1, ADone, -1 }, // SD
++ { -1, -1, -1, ADone, -1 }, // Ws5
++ { -1, -1, Done, -1, -1 }, // ADone
++ { Char, Char, Char, Qm, Char }, // Char
++ { Char, Char, Done, Qm, Char }, // Qm
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parsePI);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Name:
++ // test what name was read and determine the next state
++ // (not very beautiful, I admit)
++ if (name().toLower() == QLatin1String("xml")) {
++ if (parsePI_xmldecl && name() == QLatin1String("xml")) {
++ state = XMLDecl;
++ } else {
++ reportParseError(QLatin1String(XMLERR_INVALIDNAMEFORPI));
++ return false;
++ }
++ } else {
++ state = PInstr;
++ stringClear();
++ }
++ break;
++ case Version:
++ // get version (syntax like an attribute)
++ if (name() != QLatin1String("version")) {
++ reportParseError(QLatin1String(XMLERR_VERSIONEXPECTED));
++ return false;
++ }
++ xmlVersion = string();
++ break;
++ case EorSD:
++ // get the EDecl or SDDecl (syntax like an attribute)
++ if (name() == QLatin1String("standalone")) {
++ if (string()== QLatin1String("yes")) {
++ standalone = QXmlSimpleReaderPrivate::Yes;
++ } else if (string() == QLatin1String("no")) {
++ standalone = QXmlSimpleReaderPrivate::No;
++ } else {
++ reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL));
++ return false;
++ }
++ } else if (name() == QLatin1String("encoding")) {
++ encoding = string();
++ } else {
++ reportParseError(QLatin1String(XMLERR_EDECLORSDDECLEXPECTED));
++ return false;
++ }
++ break;
++ case SD:
++ if (name() != QLatin1String("standalone")) {
++ reportParseError(QLatin1String(XMLERR_SDDECLEXPECTED));
++ return false;
++ }
++ if (string() == QLatin1String("yes")) {
++ standalone = QXmlSimpleReaderPrivate::Yes;
++ } else if (string() == QLatin1String("no")) {
++ standalone = QXmlSimpleReaderPrivate::No;
++ } else {
++ reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL));
++ return false;
++ }
++ break;
++ case Qm:
++ // test if the skipping was legal
++ if (!atEnd() && c != QLatin1Char('>'))
++ stringAddC(QLatin1Char('?'));
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (determineNameChar(c) == NameBeginning) {
++ input = InpNameBe;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case QmI:
++ next();
++ break;
++ case Name:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ break;
++ case Ws1:
++ case Ws2:
++ case Ws3:
++ case Ws4:
++ case Ws5:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ break;
++ case Version:
++ if (!parseAttribute()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ break;
++ case EorSD:
++ if (!parseAttribute()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ break;
++ case SD:
++ // get the SDDecl (syntax like an attribute)
++ if (standalone != QXmlSimpleReaderPrivate::Unknown) {
++ // already parsed the standalone declaration
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++ if (!parseAttribute()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
++ return false;
++ }
++ break;
++ case ADone:
++ next();
++ break;
++ case Char:
++ stringAddC();
++ next();
++ break;
++ case Qm:
++ // skip the '?'
++ next();
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a document type definition (doctypedecl [28]).
++
++ Precondition: the beginning '<!' of the doctype is already read the head
++ stands on the 'D' of '<!DOCTYPE'.
++
++ If this function was successful, the head-position is on the first
++ character after the document type definition.
++ */
++ bool QXmlSimpleReaderPrivate::parseDoctype()
++ {
++ const signed char Init = 0;
++ const signed char Doctype = 1; // read the doctype
++ const signed char Ws1 = 2; // eat_ws
++ const signed char Doctype2 = 3; // read the doctype, part 2
++ const signed char Ws2 = 4; // eat_ws
++ const signed char Sys = 5; // read SYSTEM or PUBLIC
++ const signed char Ws3 = 6; // eat_ws
++ const signed char MP = 7; // markupdecl or PEReference
++ const signed char MPR = 8; // same as MP, but already reported
++ const signed char PER = 9; // PERReference
++ const signed char Mup = 10; // markupdecl
++ const signed char Ws4 = 11; // eat_ws
++ const signed char MPE = 12; // end of markupdecl or PEReference
++ const signed char Done = 13;
++
++ const signed char InpWs = 0;
++ const signed char InpD = 1; // 'D'
++ const signed char InpS = 2; // 'S' or 'P'
++ const signed char InpOB = 3; // [
++ const signed char InpCB = 4; //]
++ const signed char InpPer = 5; // %
++ const signed char InpGt = 6; // >
++ const signed char InpUnknown = 7;
++
++ static const signed char table[13][8] = {
++ /* InpWs, InpD InpS InpOB InpCB InpPer InpGt InpUnknown */
++ { -1, Doctype, -1, -1, -1, -1, -1, -1 }, // Init
++ { Ws1, -1, -1, -1, -1, -1, -1, -1 }, // Doctype
++ { -1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Ws1
++ { Ws2, -1, Sys, MP, -1, -1, Done, -1 }, // Doctype2
++ { -1, -1, Sys, MP, -1, -1, Done, -1 }, // Ws2
++ { Ws3, -1, -1, MP, -1, -1, Done, -1 }, // Sys
++ { -1, -1, -1, MP, -1, -1, Done, -1 }, // Ws3
++ { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MP
++ { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MPR
++ { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // PER
++ { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // Mup
++ { -1, -1, -1, -1, MPE, PER, -1, Mup }, // Ws4
++ { -1, -1, -1, -1, -1, -1, Done, -1 } // MPE
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ if (parseStack == nullptr || parseStack->isEmpty()) {
++ startDTDwasReported = false;
++ systemId.clear();
++ publicId.clear();
++ }
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseDoctype);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Doctype2:
++ doctype = name();
++ break;
++ case MP:
++ if (!startDTDwasReported && lexicalHnd ) {
++ startDTDwasReported = true;
++ if (!lexicalHnd->startDTD(doctype, publicId, systemId)) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ state = MPR;
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGDOCTYPE));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('D')) {
++ input = InpD;
++ } else if (c == QLatin1Char('S')) {
++ input = InpS;
++ } else if (c == QLatin1Char('P')) {
++ input = InpS;
++ } else if (c == QLatin1Char('[')) {
++ input = InpOB;
++ } else if (c == QLatin1Char(']')) {
++ input = InpCB;
++ } else if (c == QLatin1Char('%')) {
++ input = InpPer;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Doctype:
++ parseString_s = QLatin1String("DOCTYPE");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case Ws1:
++ case Ws2:
++ case Ws3:
++ case Ws4:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case Doctype2:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case Sys:
++ parseExternalID_allowPublicID = false;
++ if (!parseExternalID()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ thisPublicId = publicId;
++ thisSystemId = systemId;
++ break;
++ case MP:
++ case MPR:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case PER:
++ parsePEReference_context = InDTD;
++ if (!parsePEReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case Mup:
++ if (dtdRecursionLimit > 0 && parameterEntities.size() > dtdRecursionLimit) {
++ reportParseError(QString::fromLatin1(
++ "DTD parsing exceeded recursion limit of %1.").arg(dtdRecursionLimit));
++ return false;
++ }
++ if (!parseMarkupdecl()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case MPE:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
++ return false;
++ }
++ break;
++ case Done:
++ if (lexicalHnd) {
++ if (!startDTDwasReported) {
++ startDTDwasReported = true;
++ if (!lexicalHnd->startDTD(doctype, publicId, systemId)) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ if (!lexicalHnd->endDTD()) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a ExternalID [75].
++
++ If allowPublicID is true parse ExternalID [75] or PublicID [83].
++ */
++ bool QXmlSimpleReaderPrivate::parseExternalID()
++ {
++ const signed char Init = 0;
++ const signed char Sys = 1; // parse 'SYSTEM'
++ const signed char SysWS = 2; // parse the whitespace after 'SYSTEM'
++ const signed char SysSQ = 3; // parse SystemLiteral with '
++ const signed char SysSQ2 = 4; // parse SystemLiteral with '
++ const signed char SysDQ = 5; // parse SystemLiteral with "
++ const signed char SysDQ2 = 6; // parse SystemLiteral with "
++ const signed char Pub = 7; // parse 'PUBLIC'
++ const signed char PubWS = 8; // parse the whitespace after 'PUBLIC'
++ const signed char PubSQ = 9; // parse PubidLiteral with '
++ const signed char PubSQ2 = 10; // parse PubidLiteral with '
++ const signed char PubDQ = 11; // parse PubidLiteral with "
++ const signed char PubDQ2 = 12; // parse PubidLiteral with "
++ const signed char PubE = 13; // finished parsing the PubidLiteral
++ const signed char PubWS2 = 14; // parse the whitespace after the PubidLiteral
++ const signed char PDone = 15; // done if allowPublicID is true
++ const signed char Done = 16;
++
++ const signed char InpSQ = 0; // '
++ const signed char InpDQ = 1; // "
++ const signed char InpS = 2; // S
++ const signed char InpP = 3; // P
++ const signed char InpWs = 4; // white space
++ const signed char InpUnknown = 5;
++
++ static const signed char table[15][6] = {
++ /* InpSQ InpDQ InpS InpP InpWs InpUnknown */
++ { -1, -1, Sys, Pub, -1, -1 }, // Init
++ { -1, -1, -1, -1, SysWS, -1 }, // Sys
++ { SysSQ, SysDQ, -1, -1, -1, -1 }, // SysWS
++ { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ
++ { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ2
++ { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ
++ { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ2
++ { -1, -1, -1, -1, PubWS, -1 }, // Pub
++ { PubSQ, PubDQ, -1, -1, -1, -1 }, // PubWS
++ { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ
++ { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ2
++ { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ
++ { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ2
++ { PDone, PDone, PDone, PDone, PubWS2, PDone }, // PubE
++ { SysSQ, SysDQ, PDone, PDone, PDone, PDone } // PubWS2
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ if (parseStack == nullptr || parseStack->isEmpty()) {
++ systemId.clear();
++ publicId.clear();
++ }
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseExternalID);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case PDone:
++ if (parseExternalID_allowPublicID) {
++ publicId = string();
++ return true;
++ } else {
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('\'')) {
++ input = InpSQ;
++ } else if (c == QLatin1Char('"')) {
++ input = InpDQ;
++ } else if (c == QLatin1Char('S')) {
++ input = InpS;
++ } else if (c == QLatin1Char('P')) {
++ input = InpP;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Sys:
++ parseString_s = QLatin1String("SYSTEM");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ break;
++ case SysWS:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ break;
++ case SysSQ:
++ case SysDQ:
++ stringClear();
++ next();
++ break;
++ case SysSQ2:
++ case SysDQ2:
++ stringAddC();
++ next();
++ break;
++ case Pub:
++ parseString_s = QLatin1String("PUBLIC");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ break;
++ case PubWS:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ break;
++ case PubSQ:
++ case PubDQ:
++ stringClear();
++ next();
++ break;
++ case PubSQ2:
++ case PubDQ2:
++ stringAddC();
++ next();
++ break;
++ case PubE:
++ next();
++ break;
++ case PubWS2:
++ publicId = string();
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
++ return false;
++ }
++ break;
++ case Done:
++ systemId = string();
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a markupdecl [29].
++ */
++ bool QXmlSimpleReaderPrivate::parseMarkupdecl()
++ {
++ const signed char Init = 0;
++ const signed char Lt = 1; // < was read
++ const signed char Em = 2; // ! was read
++ const signed char CE = 3; // E was read
++ const signed char Qm = 4; // ? was read
++ const signed char Dash = 5; // - was read
++ const signed char CA = 6; // A was read
++ const signed char CEL = 7; // EL was read
++ const signed char CEN = 8; // EN was read
++ const signed char CN = 9; // N was read
++ const signed char Done = 10;
++
++ const signed char InpLt = 0; // <
++ const signed char InpQm = 1; // ?
++ const signed char InpEm = 2; // !
++ const signed char InpDash = 3; // -
++ const signed char InpA = 4; // A
++ const signed char InpE = 5; // E
++ const signed char InpL = 6; // L
++ const signed char InpN = 7; // N
++ const signed char InpUnknown = 8;
++
++ static const signed char table[4][9] = {
++ /* InpLt InpQm InpEm InpDash InpA InpE InpL InpN InpUnknown */
++ { Lt, -1, -1, -1, -1, -1, -1, -1, -1 }, // Init
++ { -1, Qm, Em, -1, -1, -1, -1, -1, -1 }, // Lt
++ { -1, -1, -1, Dash, CA, CE, -1, CN, -1 }, // Em
++ { -1, -1, -1, -1, -1, -1, CEL, CEN, -1 } // CE
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseMarkupdecl);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Qm:
++ if (contentHnd) {
++ if (!contentHnd->processingInstruction(name(),string())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ case Dash:
++ if (lexicalHnd) {
++ if (!lexicalHnd->comment(string())) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ case CA:
++ return true;
++ case CEL:
++ return true;
++ case CEN:
++ return true;
++ case CN:
++ return true;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ if (c == QLatin1Char('<')) {
++ input = InpLt;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else if (c == QLatin1Char('!')) {
++ input = InpEm;
++ } else if (c == QLatin1Char('-')) {
++ input = InpDash;
++ } else if (c == QLatin1Char('A')) {
++ input = InpA;
++ } else if (c == QLatin1Char('E')) {
++ input = InpE;
++ } else if (c == QLatin1Char('L')) {
++ input = InpL;
++ } else if (c == QLatin1Char('N')) {
++ input = InpN;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Lt:
++ next();
++ break;
++ case Em:
++ next();
++ break;
++ case CE:
++ next();
++ break;
++ case Qm:
++ parsePI_xmldecl = false;
++ if (!parsePI()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ case Dash:
++ if (!parseComment()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ case CA:
++ if (!parseAttlistDecl()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ case CEL:
++ if (!parseElementDecl()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ case CEN:
++ if (!parseEntityDecl()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ case CN:
++ if (!parseNotationDecl()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
++ return false;
++ }
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a PEReference [69]
++ */
++ bool QXmlSimpleReaderPrivate::parsePEReference()
++ {
++ const signed char Init = 0;
++ const signed char Next = 1;
++ const signed char Name = 2;
++ const signed char NameR = 3; // same as Name, but already reported
++ const signed char Done = 4;
++
++ const signed char InpSemi = 0; // ;
++ const signed char InpPer = 1; // %
++ const signed char InpUnknown = 2;
++
++ static const signed char table[4][3] = {
++ /* InpSemi InpPer InpUnknown */
++ { -1, Next, -1 }, // Init
++ { -1, -1, Name }, // Next
++ { Done, -1, -1 }, // Name
++ { Done, -1, -1 } // NameR
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parsePEReference);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Name:
++ {
++ bool skipIt = true;
++ ExpansionCheck check = ExpansionCheck::None;
++ QString xmlRefString;
++
++ QMap<QString,QString>::Iterator it;
++ it = parameterEntities.find(ref());
++ if (it != parameterEntities.end()) {
++ skipIt = false;
++ check = ExpansionCheck::ParameterEntity;
++ xmlRefString = *it;
++ } else if (entityRes) {
++ QMap<QString,QXmlSimpleReaderPrivate::ExternParameterEntity>::Iterator it2;
++ it2 = externParameterEntities.find(ref());
++ QXmlInputSource *ret = nullptr;
++ if (it2 != externParameterEntities.end()) {
++ if (!entityRes->resolveEntity((*it2).publicId, (*it2).systemId, ret)) {
++ delete ret;
++ reportParseError(entityRes->errorString());
++ return false;
++ }
++ if (ret) {
++ QString buffer = ret->data();
++ while (!buffer.isEmpty()) {
++ xmlRefString += buffer;
++ ret->fetchData();
++ buffer = ret->data();
++ }
++ delete ret;
++ if (!stripTextDecl(xmlRefString)) {
++ reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL));
++ return false;
++ }
++ skipIt = false;
++ }
++ }
++ }
++
++ if (skipIt) {
++ if (contentHnd) {
++ if (!contentHnd->skippedEntity(QLatin1Char('%') + ref())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ } else {
++ if (parsePEReference_context == InEntityValue) {
++ // Included in literal
++ // Check that the overall size does not exceed the
++ // expansion limit right here, instead of doing the
++ // full expansion. Note that all the nested
++ // parameter entities are already expanded here, so
++ // xmlRefString contains only literals or general
++ // entities.
++ includedParameterEntitySize += xmlRefString.size();
++ if (includedParameterEntitySize > entityCharacterLimit) {
++ reportParseError(QString::fromLatin1(
++ "Expanding the XML entity \"%%1\" makes the enclosing "
++ "entity value exceed the limit of %2 characters.")
++ .arg(ref(), QString::number(entityCharacterLimit)));
++ return false;
++ }
++ if (!insertXmlRef(xmlRefString, ref(), true))
++ return false;
++ } else if (parsePEReference_context == InDTD) {
++ // Included as PE
++ // The replacement text is parsed again, and can
++ // expand further parameter entities and general
++ // entities, so count it like a general entity.
++ // The external entities are not counted, same as
++ // for general entities.
++ if (!insertXmlRef(QLatin1Char(' ') + xmlRefString + QLatin1Char(' '),
++ ref(), false, check)) {
++ return false;
++ }
++ }
++ }
++ }
++ state = NameR;
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parsePEReference, state);
++ return false;
++ }
++ if (c == QLatin1Char(';')) {
++ input = InpSemi;
++ } else if (c == QLatin1Char('%')) {
++ input = InpPer;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Next:
++ next();
++ break;
++ case Name:
++ case NameR:
++ parseName_useRef = true;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parsePEReference, state);
++ return false;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a AttlistDecl [52].
++
++ Precondition: the beginning '<!' is already read and the head
++ stands on the 'A' of '<!ATTLIST'
++ */
++ bool QXmlSimpleReaderPrivate::parseAttlistDecl()
++ {
++ const signed char Init = 0;
++ const signed char Attlist = 1; // parse the string "ATTLIST"
++ const signed char Ws = 2; // whitespace read
++ const signed char Name = 3; // parse name
++ const signed char Ws1 = 4; // whitespace read
++ const signed char Attdef = 5; // parse the AttDef
++ const signed char Ws2 = 6; // whitespace read
++ const signed char Atttype = 7; // parse the AttType
++ const signed char Ws3 = 8; // whitespace read
++ const signed char DDecH = 9; // DefaultDecl with #
++ const signed char DefReq = 10; // parse the string "REQUIRED"
++ const signed char DefImp = 11; // parse the string "IMPLIED"
++ const signed char DefFix = 12; // parse the string "FIXED"
++ const signed char Attval = 13; // parse the AttValue
++ const signed char Ws4 = 14; // whitespace read
++ const signed char Done = 15;
++
++ const signed char InpWs = 0; // white space
++ const signed char InpGt = 1; // >
++ const signed char InpHash = 2; // #
++ const signed char InpA = 3; // A
++ const signed char InpI = 4; // I
++ const signed char InpF = 5; // F
++ const signed char InpR = 6; // R
++ const signed char InpUnknown = 7;
++
++ static const signed char table[15][8] = {
++ /* InpWs InpGt InpHash InpA InpI InpF InpR InpUnknown */
++ { -1, -1, -1, Attlist, -1, -1, -1, -1 }, // Init
++ { Ws, -1, -1, -1, -1, -1, -1, -1 }, // Attlist
++ { -1, -1, -1, Name, Name, Name, Name, Name }, // Ws
++ { Ws1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Name
++ { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Ws1
++ { Ws2, -1, -1, -1, -1, -1, -1, -1 }, // Attdef
++ { -1, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype }, // Ws2
++ { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // Attype
++ { -1, Attval, DDecH, Attval, Attval, Attval, Attval, Attval }, // Ws3
++ { -1, -1, -1, -1, DefImp, DefFix, DefReq, -1 }, // DDecH
++ { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefReq
++ { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefImp
++ { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // DefFix
++ { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // Attval
++ { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef } // Ws4
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseAttlistDecl);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Name:
++ attDeclEName = name();
++ break;
++ case Attdef:
++ attDeclAName = name();
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (c == QLatin1Char('#')) {
++ input = InpHash;
++ } else if (c == QLatin1Char('A')) {
++ input = InpA;
++ } else if (c == QLatin1Char('I')) {
++ input = InpI;
++ } else if (c == QLatin1Char('F')) {
++ input = InpF;
++ } else if (c == QLatin1Char('R')) {
++ input = InpR;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Attlist:
++ parseString_s = QLatin1String("ATTLIST");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Ws:
++ case Ws1:
++ case Ws2:
++ case Ws3:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Name:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Attdef:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Atttype:
++ if (!parseAttType()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case DDecH:
++ next();
++ break;
++ case DefReq:
++ parseString_s = QLatin1String("REQUIRED");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case DefImp:
++ parseString_s = QLatin1String("IMPLIED");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case DefFix:
++ parseString_s = QLatin1String("FIXED");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Attval:
++ if (!parseAttValue()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Ws4:
++ if (declHnd) {
++ // ### not all values are computed yet...
++ if (!declHnd->attributeDecl(attDeclEName, attDeclAName, QLatin1String(""), QLatin1String(""), QLatin1String(""))) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
++ return false;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a AttType [54]
++ */
++ bool QXmlSimpleReaderPrivate::parseAttType()
++ {
++ const signed char Init = 0;
++ const signed char ST = 1; // StringType
++ const signed char TTI = 2; // TokenizedType starting with 'I'
++ const signed char TTI2 = 3; // TokenizedType helpstate
++ const signed char TTI3 = 4; // TokenizedType helpstate
++ const signed char TTE = 5; // TokenizedType starting with 'E'
++ const signed char TTEY = 6; // TokenizedType starting with 'ENTITY'
++ const signed char TTEI = 7; // TokenizedType starting with 'ENTITI'
++ const signed char N = 8; // N read (TokenizedType or Notation)
++ const signed char TTNM = 9; // TokenizedType starting with 'NM'
++ const signed char TTNM2 = 10; // TokenizedType helpstate
++ const signed char NO = 11; // Notation
++ const signed char NO2 = 12; // Notation helpstate
++ const signed char NO3 = 13; // Notation helpstate
++ const signed char NOName = 14; // Notation, read name
++ const signed char NO4 = 15; // Notation helpstate
++ const signed char EN = 16; // Enumeration
++ const signed char ENNmt = 17; // Enumeration, read Nmtoken
++ const signed char EN2 = 18; // Enumeration helpstate
++ const signed char ADone = 19; // almost done (make next and accept)
++ const signed char Done = 20;
++
++ const signed char InpWs = 0; // whitespace
++ const signed char InpOp = 1; // (
++ const signed char InpCp = 2; //)
++ const signed char InpPipe = 3; // |
++ const signed char InpC = 4; // C
++ const signed char InpE = 5; // E
++ const signed char InpI = 6; // I
++ const signed char InpM = 7; // M
++ const signed char InpN = 8; // N
++ const signed char InpO = 9; // O
++ const signed char InpR = 10; // R
++ const signed char InpS = 11; // S
++ const signed char InpY = 12; // Y
++ const signed char InpUnknown = 13;
++
++ static const signed char table[19][14] = {
++ /* InpWs InpOp InpCp InpPipe InpC InpE InpI InpM InpN InpO InpR InpS InpY InpUnknown */
++ { -1, EN, -1, -1, ST, TTE, TTI, -1, N, -1, -1, -1, -1, -1 }, // Init
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // ST
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI2, Done, Done, Done }, // TTI
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI3, Done, Done }, // TTI2
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTI3
++ { -1, -1, -1, -1, -1, -1, TTEI, -1, -1, -1, -1, -1, TTEY, -1 }, // TTE
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEY
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEI
++ { -1, -1, -1, -1, -1, -1, -1, TTNM, -1, NO, -1, -1, -1, -1 }, // N
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTNM2, Done, Done }, // TTNM
++ { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTNM2
++ { NO2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO
++ { -1, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO2
++ { NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName }, // NO3
++ { NO4, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NOName
++ { -1, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO4
++ { -1, -1, ENNmt, -1, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt }, // EN
++ { EN2, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // ENNmt
++ { -1, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // EN2
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseAttType);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case ADone:
++ return true;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('(')) {
++ input = InpOp;
++ } else if (c == QLatin1Char(')')) {
++ input = InpCp;
++ } else if (c == QLatin1Char('|')) {
++ input = InpPipe;
++ } else if (c == QLatin1Char('C')) {
++ input = InpC;
++ } else if (c == QLatin1Char('E')) {
++ input = InpE;
++ } else if (c == QLatin1Char('I')) {
++ input = InpI;
++ } else if (c == QLatin1Char('M')) {
++ input = InpM;
++ } else if (c == QLatin1Char('N')) {
++ input = InpN;
++ } else if (c == QLatin1Char('O')) {
++ input = InpO;
++ } else if (c == QLatin1Char('R')) {
++ input = InpR;
++ } else if (c == QLatin1Char('S')) {
++ input = InpS;
++ } else if (c == QLatin1Char('Y')) {
++ input = InpY;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case ST:
++ parseString_s = QLatin1String("CDATA");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case TTI:
++ parseString_s = QLatin1String("ID");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case TTI2:
++ parseString_s = QLatin1String("REF");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case TTI3:
++ next(); // S
++ break;
++ case TTE:
++ parseString_s = QLatin1String("ENTIT");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case TTEY:
++ next(); // Y
++ break;
++ case TTEI:
++ parseString_s = QLatin1String("IES");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case N:
++ next(); // N
++ break;
++ case TTNM:
++ parseString_s = QLatin1String("MTOKEN");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case TTNM2:
++ next(); // S
++ break;
++ case NO:
++ parseString_s = QLatin1String("OTATION");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case NO2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case NO3:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case NOName:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case NO4:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case EN:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case ENNmt:
++ if (!parseNmtoken()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case EN2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
++ return false;
++ }
++ break;
++ case ADone:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a AttValue [10]
++
++ Precondition: the head stands on the beginning " or '
++
++ If this function was successful, the head stands on the first
++ character after the closing " or ' and the value of the attribute
++ is in string().
++ */
++ bool QXmlSimpleReaderPrivate::parseAttValue()
++ {
++ const signed char Init = 0;
++ const signed char Dq = 1; // double quotes were read
++ const signed char DqRef = 2; // read references in double quotes
++ const signed char DqC = 3; // signed character read in double quotes
++ const signed char Sq = 4; // single quotes were read
++ const signed char SqRef = 5; // read references in single quotes
++ const signed char SqC = 6; // signed character read in single quotes
++ const signed char Done = 7;
++
++ const signed char InpDq = 0; // "
++ const signed char InpSq = 1; // '
++ const signed char InpAmp = 2; // &
++ const signed char InpLt = 3; // <
++ const signed char InpUnknown = 4;
++
++ static const signed char table[7][5] = {
++ /* InpDq InpSq InpAmp InpLt InpUnknown */
++ { Dq, Sq, -1, -1, -1 }, // Init
++ { Done, DqC, DqRef, -1, DqC }, // Dq
++ { Done, DqC, DqRef, -1, DqC }, // DqRef
++ { Done, DqC, DqRef, -1, DqC }, // DqC
++ { SqC, Done, SqRef, -1, SqC }, // Sq
++ { SqC, Done, SqRef, -1, SqC }, // SqRef
++ { SqC, Done, SqRef, -1, SqC } // SqRef
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseAttValue);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseAttValue, state);
++ return false;
++ }
++ if (c == QLatin1Char('"')) {
++ input = InpDq;
++ } else if (c == QLatin1Char('\'')) {
++ input = InpSq;
++ } else if (c == QLatin1Char('&')) {
++ input = InpAmp;
++ } else if (c == QLatin1Char('<')) {
++ input = InpLt;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Dq:
++ case Sq:
++ stringClear();
++ next();
++ break;
++ case DqRef:
++ case SqRef:
++ parseReference_context = InAttributeValue;
++ if (!parseReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttValue, state);
++ return false;
++ }
++ break;
++ case DqC:
++ case SqC:
++ stringAddC();
++ next();
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a elementdecl [45].
++
++ Precondition: the beginning '<!E' is already read and the head
++ stands on the 'L' of '<!ELEMENT'
++ */
++ bool QXmlSimpleReaderPrivate::parseElementDecl()
++ {
++ const signed char Init = 0;
++ const signed char Elem = 1; // parse the beginning string
++ const signed char Ws1 = 2; // whitespace required
++ const signed char Nam = 3; // parse Name
++ const signed char Ws2 = 4; // whitespace required
++ const signed char Empty = 5; // read EMPTY
++ const signed char Any = 6; // read ANY
++ const signed char Cont = 7; // read contentspec (except ANY or EMPTY)
++ const signed char Mix = 8; // read Mixed
++ const signed char Mix2 = 9; //
++ const signed char Mix3 = 10; //
++ const signed char MixN1 = 11; //
++ const signed char MixN2 = 12; //
++ const signed char MixN3 = 13; //
++ const signed char MixN4 = 14; //
++ const signed char Cp = 15; // parse cp
++ const signed char Cp2 = 16; //
++ const signed char WsD = 17; // eat whitespace before Done
++ const signed char Done = 18;
++
++ const signed char InpWs = 0;
++ const signed char InpGt = 1; // >
++ const signed char InpPipe = 2; // |
++ const signed char InpOp = 3; // (
++ const signed char InpCp = 4; //)
++ const signed char InpHash = 5; // #
++ const signed char InpQm = 6; // ?
++ const signed char InpAst = 7; // *
++ const signed char InpPlus = 8; // +
++ const signed char InpA = 9; // A
++ const signed char InpE = 10; // E
++ const signed char InpL = 11; // L
++ const signed char InpUnknown = 12;
++
++ static const signed char table[18][13] = {
++ /* InpWs InpGt InpPipe InpOp InpCp InpHash InpQm InpAst InpPlus InpA InpE InpL InpUnknown */
++ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Elem, -1 }, // Init
++ { Ws1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Elem
++ { -1, -1, -1, -1, -1, -1, -1, -1, -1, Nam, Nam, Nam, Nam }, // Ws1
++ { Ws2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Nam
++ { -1, -1, -1, Cont, -1, -1, -1, -1, -1, Any, Empty, -1, -1 }, // Ws2
++ { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Empty
++ { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Any
++ { -1, -1, -1, Cp, Cp, Mix, -1, -1, -1, Cp, Cp, Cp, Cp }, // Cont
++ { Mix2, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix
++ { -1, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix2
++ { WsD, Done, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // Mix3
++ { -1, -1, -1, -1, -1, -1, -1, -1, -1, MixN2, MixN2, MixN2, MixN2 }, // MixN1
++ { MixN3, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN2
++ { -1, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN3
++ { -1, -1, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // MixN4
++ { WsD, Done, -1, -1, -1, -1, Cp2, Cp2, Cp2, -1, -1, -1, -1 }, // Cp
++ { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Cp2
++ { -1, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // WsD
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseElementDecl);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return true;
++ case -1:
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (c == QLatin1Char('|')) {
++ input = InpPipe;
++ } else if (c == QLatin1Char('(')) {
++ input = InpOp;
++ } else if (c == QLatin1Char(')')) {
++ input = InpCp;
++ } else if (c == QLatin1Char('#')) {
++ input = InpHash;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else if (c == QLatin1Char('*')) {
++ input = InpAst;
++ } else if (c == QLatin1Char('+')) {
++ input = InpPlus;
++ } else if (c == QLatin1Char('A')) {
++ input = InpA;
++ } else if (c == QLatin1Char('E')) {
++ input = InpE;
++ } else if (c == QLatin1Char('L')) {
++ input = InpL;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Elem:
++ parseString_s = QLatin1String("LEMENT");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Ws1:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Nam:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Ws2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Empty:
++ parseString_s = QLatin1String("EMPTY");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Any:
++ parseString_s = QLatin1String("ANY");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Cont:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Mix:
++ parseString_s = QLatin1String("#PCDATA");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Mix2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Mix3:
++ next();
++ break;
++ case MixN1:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case MixN2:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case MixN3:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case MixN4:
++ next();
++ break;
++ case Cp:
++ if (!parseChoiceSeq()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Cp2:
++ next();
++ break;
++ case WsD:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
++ return false;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a NotationDecl [82].
++
++ Precondition: the beginning '<!' is already read and the head
++ stands on the 'N' of '<!NOTATION'
++ */
++ bool QXmlSimpleReaderPrivate::parseNotationDecl()
++ {
++ const signed char Init = 0;
++ const signed char Not = 1; // read NOTATION
++ const signed char Ws1 = 2; // eat whitespaces
++ const signed char Nam = 3; // read Name
++ const signed char Ws2 = 4; // eat whitespaces
++ const signed char ExtID = 5; // parse ExternalID
++ const signed char ExtIDR = 6; // same as ExtID, but already reported
++ const signed char Ws3 = 7; // eat whitespaces
++ const signed char Done = 8;
++
++ const signed char InpWs = 0;
++ const signed char InpGt = 1; // >
++ const signed char InpN = 2; // N
++ const signed char InpUnknown = 3;
++
++ static const signed char table[8][4] = {
++ /* InpWs InpGt InpN InpUnknown */
++ { -1, -1, Not, -1 }, // Init
++ { Ws1, -1, -1, -1 }, // Not
++ { -1, -1, Nam, Nam }, // Ws1
++ { Ws2, Done, -1, -1 }, // Nam
++ { -1, Done, ExtID, ExtID }, // Ws2
++ { Ws3, Done, -1, -1 }, // ExtID
++ { Ws3, Done, -1, -1 }, // ExtIDR
++ { -1, Done, -1, -1 } // Ws3
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseNotationDecl);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case ExtID:
++ // call the handler
++ if (dtdHnd) {
++ if (!dtdHnd->notationDecl(name(), publicId, systemId)) {
++ reportParseError(dtdHnd->errorString());
++ return false;
++ }
++ }
++ state = ExtIDR;
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (c == QLatin1Char('N')) {
++ input = InpN;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Not:
++ parseString_s = QLatin1String("NOTATION");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case Ws1:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case Nam:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case Ws2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case ExtID:
++ case ExtIDR:
++ parseExternalID_allowPublicID = true;
++ if (!parseExternalID()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case Ws3:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
++ return false;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse choice [49] or seq [50].
++
++ Precondition: the beginning '('S? is already read and the head
++ stands on the first non-whitespace character after it.
++ */
++ bool QXmlSimpleReaderPrivate::parseChoiceSeq()
++ {
++ return parseNestedFrames(FrameType::ChoiceSeq);
++ }
++
++ /*
++ Parses one choice or seq, but stops at a nested choice or seq.
++ Returns FrameParseResult::EnterChoiceSeq when it reaches a nested group,
++ so that parseNestedFrames() could call parseChoiceSeqFrame() from the outer
++ loop to parse the next choice or seq. Continues parsing when the nested
++ item is handled.
++ */
++ QXmlSimpleReaderPrivate::FrameParseResult QXmlSimpleReaderPrivate::parseChoiceSeqFrame(int &state)
++ {
++ const signed char Init = 0;
++ const signed char Ws1 = 1; // eat whitespace
++ const signed char CoS = 2; // choice or set
++ const signed char Ws2 = 3; // eat whitespace
++ const signed char More = 4; // more cp to read
++ const signed char Name = 5; // read name
++ const signed char Done = 6; //
++
++ const signed char InpWs = 0; // S
++ const signed char InpOp = 1; // (
++ const signed char InpCp = 2; //)
++ const signed char InpQm = 3; // ?
++ const signed char InpAst = 4; // *
++ const signed char InpPlus = 5; // +
++ const signed char InpPipe = 6; // |
++ const signed char InpComm = 7; // ,
++ const signed char InpUnknown = 8;
++
++ static const signed char table[6][9] = {
++ /* InpWs InpOp InpCp InpQm InpAst InpPlus InpPipe InpComm InpUnknown */
++ { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // Init
++ { -1, CoS, -1, -1, -1, -1, -1, -1, CoS }, // Ws1
++ { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 }, // CS
++ { -1, -1, Done, -1, -1, -1, More, More, -1 }, // Ws2
++ { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // More (same as Init)
++ { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 } // Name (same as CS)
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return FrameParseResult::Done;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return FrameParseResult::Failed;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
++ return FrameParseResult::Failed;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('(')) {
++ input = InpOp;
++ } else if (c == QLatin1Char(')')) {
++ input = InpCp;
++ } else if (c == QLatin1Char('?')) {
++ input = InpQm;
++ } else if (c == QLatin1Char('*')) {
++ input = InpAst;
++ } else if (c == QLatin1Char('+')) {
++ input = InpPlus;
++ } else if (c == QLatin1Char('|')) {
++ input = InpPipe;
++ } else if (c == QLatin1Char(',')) {
++ input = InpComm;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Ws1:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case CoS:
++ // a nested choice or seq follows
++ return FrameParseResult::EnterChoiceSeq;
++ case Ws2:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case More:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case Name:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
++ return FrameParseResult::Failed;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return FrameParseResult::Failed;
++ }
++
++ /*
++ Called before the value \a value of the entity \a name is inserted for
++ parsing. The entity is either an internal general entity, or an internal
++ parameter entity included in the DTD. Accumulates the expanded size of the
++ outermost such entity that is currently being expanded. Returns \c true and
++ sets \a errorMessage if that size exceeds entityCharacterLimit.
++
++ The size is counted like the expanded value of the outermost entity: every
++ reference to such an entity is replaced by the value of that entity. All
++ other references (unknown entities, standard entities, and character
++ references) are counted with their literal size.
++
++ Since the size is accumulated while the entities are being expanded, it
++ does not depend on the order in which the entities were declared, and it
++ covers every place where the entities are expanded (content, attribute
++ values, the DTD itself, and default attribute values in the DTD).
++ */
++ bool QXmlSimpleReaderPrivate::addToExpandedEntitySize(const QString &name, const QString &value,
++ ExpansionCheck entityType,
++ QString *errorMessage)
++ {
++ // Find the closest entity that is being expanded and counts towards the
++ // limit. The entity that contains this reference is still on the stack,
++ // even if the reference is at the very end of its value, because the stack
++ // is only popped when the next character is read.
++ qsizetype i = xmlRefStack.size() - 1;
++ while (i >= 0 && xmlRefStack.at(i).check == ExpansionCheck::None)
++ --i;
++
++ if (i < 0) {
++ // This is the outermost entity, start counting.
++ expandedEntityName =
++ entityType == ExpansionCheck::ParameterEntity ? QLatin1Char('%') + name : name;
++ expandedEntitySize = value.size();
++ } else if (i == xmlRefStack.size() - 1) {
++ // The reference ("&name;" or "%name;") is a part of the value of the
++ // enclosing entity, so it was already counted. Replace it with the
++ // value.
++ expandedEntitySize += value.size() - (name.size() + 2);
++ } else {
++ // The reference comes from an entity that does not count towards the
++ // limit (e.g. an external entity) included by the enclosing entity, so
++ // it was not counted.
++ expandedEntitySize += value.size();
++ }
++
++ if (expandedEntitySize > entityCharacterLimit) {
++ if (errorMessage) {
++ *errorMessage = QString::fromLatin1("The XML entity \"%1\" expands to a string that "
++ "is too large to process (%2 characters > %3).")
++ .arg(expandedEntityName, QString::number(expandedEntitySize),
++ QString::number(entityCharacterLimit));
++ }
++ return true;
++ }
++ return false;
++ }
++
++ /*
++ Parse a EntityDecl [70].
++
++ Precondition: the beginning '<!E' is already read and the head
++ stand on the 'N' of '<!ENTITY'
++ */
++ bool QXmlSimpleReaderPrivate::parseEntityDecl()
++ {
++ const signed char Init = 0;
++ const signed char Ent = 1; // parse "ENTITY"
++ const signed char Ws1 = 2; // white space read
++ const signed char Name = 3; // parse name
++ const signed char Ws2 = 4; // white space read
++ const signed char EValue = 5; // parse entity value
++ const signed char EValueR = 6; // same as EValue, but already reported
++ const signed char ExtID = 7; // parse ExternalID
++ const signed char Ws3 = 8; // white space read
++ const signed char Ndata = 9; // parse "NDATA"
++ const signed char Ws4 = 10; // white space read
++ const signed char NNam = 11; // parse name
++ const signed char NNamR = 12; // same as NNam, but already reported
++ const signed char PEDec = 13; // parse PEDecl
++ const signed char Ws6 = 14; // white space read
++ const signed char PENam = 15; // parse name
++ const signed char Ws7 = 16; // white space read
++ const signed char PEVal = 17; // parse entity value
++ const signed char PEValR = 18; // same as PEVal, but already reported
++ const signed char PEEID = 19; // parse ExternalID
++ const signed char PEEIDR = 20; // same as PEEID, but already reported
++ const signed char WsE = 21; // white space read
++ const signed char Done = 22;
++ const signed char EDDone = 23; // done, but also report an external, unparsed entity decl
++
++ const signed char InpWs = 0; // white space
++ const signed char InpPer = 1; // %
++ const signed char InpQuot = 2; // " or '
++ const signed char InpGt = 3; // >
++ const signed char InpN = 4; // N
++ const signed char InpUnknown = 5;
++
++ static const signed char table[22][6] = {
++ /* InpWs InpPer InpQuot InpGt InpN InpUnknown */
++ { -1, -1, -1, -1, Ent, -1 }, // Init
++ { Ws1, -1, -1, -1, -1, -1 }, // Ent
++ { -1, PEDec, -1, -1, Name, Name }, // Ws1
++ { Ws2, -1, -1, -1, -1, -1 }, // Name
++ { -1, -1, EValue, -1, -1, ExtID }, // Ws2
++ { WsE, -1, -1, Done, -1, -1 }, // EValue
++ { WsE, -1, -1, Done, -1, -1 }, // EValueR
++ { Ws3, -1, -1, EDDone,-1, -1 }, // ExtID
++ { -1, -1, -1, EDDone,Ndata, -1 }, // Ws3
++ { Ws4, -1, -1, -1, -1, -1 }, // Ndata
++ { -1, -1, -1, -1, NNam, NNam }, // Ws4
++ { WsE, -1, -1, Done, -1, -1 }, // NNam
++ { WsE, -1, -1, Done, -1, -1 }, // NNamR
++ { Ws6, -1, -1, -1, -1, -1 }, // PEDec
++ { -1, -1, -1, -1, PENam, PENam }, // Ws6
++ { Ws7, -1, -1, -1, -1, -1 }, // PENam
++ { -1, -1, PEVal, -1, -1, PEEID }, // Ws7
++ { WsE, -1, -1, Done, -1, -1 }, // PEVal
++ { WsE, -1, -1, Done, -1, -1 }, // PEValR
++ { WsE, -1, -1, Done, -1, -1 }, // PEEID
++ { WsE, -1, -1, Done, -1, -1 }, // PEEIDR
++ { -1, -1, -1, Done, -1, -1 } // WsE
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseEntityDecl);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case EValue:
++ if ( !entityExist(name())) {
++ entities.insert(name(), string());
++ if (declHnd) {
++ if (!declHnd->internalEntityDecl(name(), string())) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ }
++ state = EValueR;
++ break;
++ case NNam:
++ if ( !entityExist(name())) {
++ externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, ref()));
++ if (dtdHnd) {
++ if (!dtdHnd->unparsedEntityDecl(name(), publicId, systemId, ref())) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ }
++ state = NNamR;
++ break;
++ case PEVal:
++ if ( !entityExist(name())) {
++ parameterEntities.insert(name(), string());
++ if (declHnd) {
++ if (!declHnd->internalEntityDecl(QLatin1Char('%') + name(), string())) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ }
++ state = PEValR;
++ break;
++ case PEEID:
++ if ( !entityExist(name())) {
++ externParameterEntities.insert(name(), QXmlSimpleReaderPrivate::ExternParameterEntity(publicId, systemId));
++ if (declHnd) {
++ if (!declHnd->externalEntityDecl(QLatin1Char('%') + name(), publicId, systemId)) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ }
++ state = PEEIDR;
++ break;
++ case EDDone:
++ if ( !entityExist(name())) {
++ externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, QString()));
++ if (declHnd) {
++ if (!declHnd->externalEntityDecl(name(), publicId, systemId)) {
++ reportParseError(declHnd->errorString());
++ return false;
++ }
++ }
++ }
++ return true;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ if (is_S(c)) {
++ input = InpWs;
++ } else if (c == QLatin1Char('%')) {
++ input = InpPer;
++ } else if (c == QLatin1Char('"') || c == QLatin1Char('\'')) {
++ input = InpQuot;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else if (c == QLatin1Char('N')) {
++ input = InpN;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Ent:
++ parseString_s = QLatin1String("NTITY");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ws1:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Name:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ws2:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case EValue:
++ case EValueR:
++ if (!parseEntityValue()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case ExtID:
++ parseExternalID_allowPublicID = false;
++ if (!parseExternalID()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ws3:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ndata:
++ parseString_s = QLatin1String("NDATA");
++ if (!parseString()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ws4:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case NNam:
++ case NNamR:
++ parseName_useRef = true;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case PEDec:
++ next();
++ break;
++ case Ws6:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case PENam:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case Ws7:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case PEVal:
++ case PEValR:
++ if (!parseEntityValue()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case PEEID:
++ case PEEIDR:
++ parseExternalID_allowPublicID = false;
++ if (!parseExternalID()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case WsE:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
++ return false;
++ }
++ break;
++ case EDDone:
++ next();
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a EntityValue [9]
++ */
++ bool QXmlSimpleReaderPrivate::parseEntityValue()
++ {
++ const signed char Init = 0;
++ const signed char Dq = 1; // EntityValue is double quoted
++ const signed char DqC = 2; // signed character
++ const signed char DqPER = 3; // PERefence
++ const signed char DqRef = 4; // Reference
++ const signed char Sq = 5; // EntityValue is double quoted
++ const signed char SqC = 6; // signed character
++ const signed char SqPER = 7; // PERefence
++ const signed char SqRef = 8; // Reference
++ const signed char Done = 9;
++
++ const signed char InpDq = 0; // "
++ const signed char InpSq = 1; // '
++ const signed char InpAmp = 2; // &
++ const signed char InpPer = 3; // %
++ const signed char InpUnknown = 4;
++
++ static const signed char table[9][5] = {
++ /* InpDq InpSq InpAmp InpPer InpUnknown */
++ { Dq, Sq, -1, -1, -1 }, // Init
++ { Done, DqC, DqRef, DqPER, DqC }, // Dq
++ { Done, DqC, DqRef, DqPER, DqC }, // DqC
++ { Done, DqC, DqRef, DqPER, DqC }, // DqPER
++ { Done, DqC, DqRef, DqPER, DqC }, // DqRef
++ { SqC, Done, SqRef, SqPER, SqC }, // Sq
++ { SqC, Done, SqRef, SqPER, SqC }, // SqC
++ { SqC, Done, SqRef, SqPER, SqC }, // SqPER
++ { SqC, Done, SqRef, SqPER, SqC } // SqRef
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseEntityValue);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityValue, state);
++ return false;
++ }
++ if (c == QLatin1Char('"')) {
++ input = InpDq;
++ } else if (c == QLatin1Char('\'')) {
++ input = InpSq;
++ } else if (c == QLatin1Char('&')) {
++ input = InpAmp;
++ } else if (c == QLatin1Char('%')) {
++ input = InpPer;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Dq:
++ case Sq:
++ includedParameterEntitySize = 0;
++ stringClear();
++ next();
++ break;
++ case DqC:
++ case SqC:
++ stringAddC();
++ next();
++ break;
++ case DqPER:
++ case SqPER:
++ parsePEReference_context = InEntityValue;
++ if (!parsePEReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state);
++ return false;
++ }
++ break;
++ case DqRef:
++ case SqRef:
++ parseReference_context = InEntityValue;
++ if (!parseReference()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state);
++ return false;
++ }
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a comment [15].
++
++ Precondition: the beginning '<!' of the comment is already read and the head
++ stands on the first '-' of '<!--'.
++
++ If this funktion was successful, the head-position is on the first
++ character after the comment.
++ */
++ bool QXmlSimpleReaderPrivate::parseComment()
++ {
++ const signed char Init = 0;
++ const signed char Dash1 = 1; // the first dash was read
++ const signed char Dash2 = 2; // the second dash was read
++ const signed char Com = 3; // read comment
++ const signed char Com2 = 4; // read comment (help state)
++ const signed char ComE = 5; // finished reading comment
++ const signed char Done = 6;
++
++ const signed char InpDash = 0; // -
++ const signed char InpGt = 1; // >
++ const signed char InpUnknown = 2;
++
++ static const signed char table[6][3] = {
++ /* InpDash InpGt InpUnknown */
++ { Dash1, -1, -1 }, // Init
++ { Dash2, -1, -1 }, // Dash1
++ { Com2, Com, Com }, // Dash2
++ { Com2, Com, Com }, // Com
++ { ComE, Com, Com }, // Com2
++ { -1, Done, -1 } // ComE
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseComment);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Dash2:
++ stringClear();
++ break;
++ case Com2:
++ // if next character is not a dash than don't skip it
++ if (!atEnd() && c != QLatin1Char('-'))
++ stringAddC(QLatin1Char('-'));
++ break;
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGCOMMENT));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseComment, state);
++ return false;
++ }
++ if (c == QLatin1Char('-')) {
++ input = InpDash;
++ } else if (c == QLatin1Char('>')) {
++ input = InpGt;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case Dash1:
++ next();
++ break;
++ case Dash2:
++ next();
++ break;
++ case Com:
++ stringAddC();
++ next();
++ break;
++ case Com2:
++ next();
++ break;
++ case ComE:
++ next();
++ break;
++ case Done:
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse an Attribute [41].
++
++ Precondition: the head stands on the first character of the name
++ of the attribute (i.e. all whitespaces are already parsed).
++
++ The head stand on the next character after the end quotes. The
++ variable name contains the name of the attribute and the variable
++ string contains the value of the attribute.
++ */
++ bool QXmlSimpleReaderPrivate::parseAttribute()
++ {
++ const int Init = 0;
++ const int PName = 1; // parse name
++ const int Ws = 2; // eat ws
++ const int Eq = 3; // the '=' was read
++ const int Quotes = 4; // " or ' were read
++
++ const int InpNameBe = 0;
++ const int InpEq = 1; // =
++ const int InpDq = 2; // "
++ const int InpSq = 3; // '
++ const int InpUnknown = 4;
++
++ static const int table[4][5] = {
++ /* InpNameBe InpEq InpDq InpSq InpUnknown */
++ { PName, -1, -1, -1, -1 }, // Init
++ { -1, Eq, -1, -1, Ws }, // PName
++ { -1, Eq, -1, -1, -1 }, // Ws
++ { -1, -1, Quotes, Quotes, -1 } // Eq
++ };
++ static_assert(Init == ItemInitState);
++ int input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseAttribute);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Quotes:
++ // Done
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseAttribute, state);
++ return false;
++ }
++ if (determineNameChar(c) == NameBeginning) {
++ input = InpNameBe;
++ } else if (c == QLatin1Char('=')) {
++ input = InpEq;
++ } else if (c == QLatin1Char('"')) {
++ input = InpDq;
++ } else if (c == QLatin1Char('\'')) {
++ input = InpSq;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case PName:
++ parseName_useRef = false;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
++ return false;
++ }
++ break;
++ case Ws:
++ if (!eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
++ return false;
++ }
++ break;
++ case Eq:
++ if (!next_eat_ws()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
++ return false;
++ }
++ break;
++ case Quotes:
++ if (!parseAttValue()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
++ return false;
++ }
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a Name [5] and store the name in name or ref (if useRef is true).
++ */
++ bool QXmlSimpleReaderPrivate::parseName()
++ {
++ const int Init = 0;
++ const int Name1 = 1; // parse first character of the name
++ const int Name = 2; // parse name
++ const int Done = 3;
++
++ static const int table[3][3] = {
++ /* InpNameBe InpNameCh InpUnknown */
++ { Name1, -1, -1 }, // Init
++ { Name, Name, Done }, // Name1
++ { Name, Name, Done } // Name
++ };
++
++ static_assert(Init == ItemInitState);
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseName);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseName, state);
++ return false;
++ }
++
++ // we can safely do the (int) cast thanks to the Q_ASSERTs earlier in this function
++ state = table[state][(int)fastDetermineNameChar(c)];
++
++ switch (state) {
++ case Name1:
++ if (parseName_useRef) {
++ refClear();
++ refAddC();
++ } else {
++ nameClear();
++ nameAddC();
++ }
++ next();
++ break;
++ case Name:
++ if (parseName_useRef) {
++ refAddC();
++ } else {
++ nameAddC();
++ }
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a Nmtoken [7] and store the name in name.
++ */
++ bool QXmlSimpleReaderPrivate::parseNmtoken()
++ {
++ const signed char Init = 0;
++ const signed char NameF = 1;
++ const signed char Name = 2;
++ const signed char Done = 3;
++
++ const signed char InpNameCh = 0; // NameChar without InpNameBe
++ const signed char InpUnknown = 1;
++
++ static const signed char table[3][2] = {
++ /* InpNameCh InpUnknown */
++ { NameF, -1 }, // Init
++ { Name, Done }, // NameF
++ { Name, Done } // Name
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseNmtoken);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case Done:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseNmtoken, state);
++ return false;
++ }
++ if (determineNameChar(c) == NotName) {
++ input = InpUnknown;
++ } else {
++ input = InpNameCh;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case NameF:
++ nameClear();
++ nameAddC();
++ next();
++ break;
++ case Name:
++ nameAddC();
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Parse a Reference [67].
++
++ parseReference_charDataRead is set to true if the reference must not be
++ parsed. The character(s) which the reference mapped to are appended to
++ string. The head stands on the first character after the reference.
++
++ parseReference_charDataRead is set to false if the reference must be parsed.
++ The character(s) which the reference mapped to are inserted at the reference
++ position. The head stands on the first character of the replacement).
++ */
++ bool QXmlSimpleReaderPrivate::parseReference()
++ {
++ // temporary variables (only used in very local context, so they don't
++ // interfere with incremental parsing)
++ uint tmp;
++ bool ok;
++
++ const signed char Init = 0;
++ const signed char SRef = 1; // start of a reference
++ const signed char ChRef = 2; // parse CharRef
++ const signed char ChDec = 3; // parse CharRef decimal
++ const signed char ChHexS = 4; // start CharRef hexadecimal
++ const signed char ChHex = 5; // parse CharRef hexadecimal
++ const signed char Name = 6; // parse name
++ const signed char DoneD = 7; // done CharRef decimal
++ const signed char DoneH = 8; // done CharRef hexadecimal
++ const signed char DoneN = 9; // done EntityRef
++
++ const signed char InpAmp = 0; // &
++ const signed char InpSemi = 1; // ;
++ const signed char InpHash = 2; // #
++ const signed char InpX = 3; // x
++ const signed char InpNum = 4; // 0-9
++ const signed char InpHex = 5; // a-f A-F
++ const signed char InpUnknown = 6;
++
++ static const signed char table[8][7] = {
++ /* InpAmp InpSemi InpHash InpX InpNum InpHex InpUnknown */
++ { SRef, -1, -1, -1, -1, -1, -1 }, // Init
++ { -1, -1, ChRef, Name, Name, Name, Name }, // SRef
++ { -1, -1, -1, ChHexS, ChDec, -1, -1 }, // ChRef
++ { -1, DoneD, -1, -1, ChDec, -1, -1 }, // ChDec
++ { -1, -1, -1, -1, ChHex, ChHex, -1 }, // ChHexS
++ { -1, DoneH, -1, -1, ChHex, ChHex, -1 }, // ChHex
++ { -1, DoneN, -1, -1, -1, -1, -1 } // Name
++ };
++ static_assert(Init == ItemInitState);
++ signed char input;
++
++ if (parseStack == nullptr || parseStack->isEmpty())
++ parseReference_charDataRead = false;
++
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseReference);
++ if (state < Init)
++ return false;
++
++ for (;;) {
++ switch (state) {
++ case DoneD:
++ return true;
++ case DoneH:
++ return true;
++ case DoneN:
++ return true;
++ case -1:
++ // Error
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
++ return false;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseReference, state);
++ return false;
++ }
++ if (c.row()) {
++ input = InpUnknown;
++ } else if (c.cell() == '&') {
++ input = InpAmp;
++ } else if (c.cell() == ';') {
++ input = InpSemi;
++ } else if (c.cell() == '#') {
++ input = InpHash;
++ } else if (c.cell() == 'x') {
++ input = InpX;
++ } else if ('0' <= c.cell() && c.cell() <= '9') {
++ input = InpNum;
++ } else if ('a' <= c.cell() && c.cell() <= 'f') {
++ input = InpHex;
++ } else if ('A' <= c.cell() && c.cell() <= 'F') {
++ input = InpHex;
++ } else {
++ input = InpUnknown;
++ }
++ state = table[state][input];
++
++ switch (state) {
++ case SRef:
++ refClear();
++ next();
++ break;
++ case ChRef:
++ next();
++ break;
++ case ChDec:
++ refAddC();
++ next();
++ break;
++ case ChHexS:
++ next();
++ break;
++ case ChHex:
++ refAddC();
++ next();
++ break;
++ case Name:
++ // read the name into the ref
++ parseName_useRef = true;
++ if (!parseName()) {
++ parseFailed(&QXmlSimpleReaderPrivate::parseReference, state);
++ return false;
++ }
++ break;
++ case DoneD:
++ tmp = ref().toUInt(&ok, 10);
++ if (ok) {
++ if (tmp > 0xffff) {
++ stringAddC(QChar::highSurrogate(tmp));
++ stringAddC(QChar::lowSurrogate(tmp));
++ } else {
++ stringAddC(QChar(tmp));
++ }
++ } else {
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
++ return false;
++ }
++ parseReference_charDataRead = true;
++ next();
++ break;
++ case DoneH:
++ tmp = ref().toUInt(&ok, 16);
++ if (ok) {
++ if (tmp > 0xffff) {
++ stringAddC(QChar::highSurrogate(tmp));
++ stringAddC(QChar::lowSurrogate(tmp));
++ } else {
++ stringAddC(QChar(tmp));
++ }
++ } else {
++ reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
++ return false;
++ }
++ parseReference_charDataRead = true;
++ next();
++ break;
++ case DoneN:
++ if (!processReference())
++ return false;
++ next();
++ break;
++ }
++ }
++ return false;
++ }
++
++ /*
++ Helper function for parseReference()
++ */
++ bool QXmlSimpleReaderPrivate::processReference()
++ {
++ QString reference = ref();
++ if (reference == QLatin1String("amp")) {
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('m')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char(';'));
++ } else {
++ // Included or Included in literal
++ stringAddC(QLatin1Char('&'));
++ }
++ parseReference_charDataRead = true;
++ } else if (reference == QLatin1String("lt")) {
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('l')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
++ } else {
++ // Included or Included in literal
++ stringAddC(QLatin1Char('<'));
++ }
++ parseReference_charDataRead = true;
++ } else if (reference == QLatin1String("gt")) {
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('g')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
++ } else {
++ // Included or Included in literal
++ stringAddC(QLatin1Char('>'));
++ }
++ parseReference_charDataRead = true;
++ } else if (reference == QLatin1String("apos")) {
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('s')); stringAddC(QLatin1Char(';'));
++ } else {
++ // Included or Included in literal
++ stringAddC(QLatin1Char('\''));
++ }
++ parseReference_charDataRead = true;
++ } else if (reference == QLatin1String("quot")) {
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('q')); stringAddC(QLatin1Char('u')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
++ } else {
++ // Included or Included in literal
++ stringAddC(QLatin1Char('"'));
++ }
++ parseReference_charDataRead = true;
++ } else {
++ QMap<QString,QString>::Iterator it;
++ it = entities.find(reference);
++ if (it != entities.end()) {
++ // "Internal General"
++ switch (parseReference_context) {
++ case InContent:
++ // Included
++ if (!insertXmlRef(*it, reference, false, ExpansionCheck::GeneralEntity))
++ return false;
++ parseReference_charDataRead = false;
++ break;
++ case InAttributeValue:
++ // Included in literal
++ if (!insertXmlRef(*it, reference, true, ExpansionCheck::GeneralEntity))
++ return false;
++ parseReference_charDataRead = false;
++ break;
++ case InEntityValue:
++ {
++ // Bypassed
++ stringAddC(QLatin1Char('&'));
++ for (const QChar c : std::as_const(reference))
++ stringAddC(c);
++ stringAddC(QLatin1Char(';'));
++ parseReference_charDataRead = true;
++ }
++ break;
++ case InDTD:
++ // Forbidden
++ parseReference_charDataRead = false;
++ reportParseError(QLatin1String(XMLERR_INTERNALGENERALENTITYINDTD));
++ return false;
++ }
++ } else {
++ QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern;
++ itExtern = externEntities.find(reference);
++ if (itExtern == externEntities.end()) {
++ // entity not declared
++ // ### check this case for conformance
++ if (parseReference_context == InEntityValue) {
++ // Bypassed
++ stringAddC(QLatin1Char('&'));
++ for (const QChar c : std::as_const(reference))
++ stringAddC(c);
++ stringAddC(QLatin1Char(';'));
++ parseReference_charDataRead = true;
++ } else {
++ // if we have some char data read, report it now
++ if (parseReference_context == InContent) {
++ if (contentCharDataRead) {
++ if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
++ if (contentHnd != nullptr && !contentHnd->characters(string())) {
++ reportParseError(contentHnd->errorString());
++ return false;
++ }
++ }
++ stringClear();
++ contentCharDataRead = false;
++ }
++ }
++
++ if (contentHnd) {
++ skipped_entity_in_content = parseReference_context == InContent;
++ if (!contentHnd->skippedEntity(reference)) {
++ skipped_entity_in_content = false;
++ reportParseError(contentHnd->errorString());
++ return false; // error
++ }
++ skipped_entity_in_content = false;
++ }
++ }
++ } else if ((*itExtern).notation.isNull()) {
++ // "External Parsed General"
++ switch (parseReference_context) {
++ case InContent:
++ {
++ // Included if validating
++ bool skipIt = true;
++ if (entityRes) {
++ QXmlInputSource *ret = nullptr;
++ if (!entityRes->resolveEntity((*itExtern).publicId, (*itExtern).systemId, ret)) {
++ delete ret;
++ reportParseError(entityRes->errorString());
++ return false;
++ }
++ if (ret) {
++ QString xmlRefString;
++ QString buffer = ret->data();
++ while (!buffer.isEmpty()) {
++ xmlRefString += buffer;
++ ret->fetchData();
++ buffer = ret->data();
++ }
++
++ delete ret;
++ if (!stripTextDecl(xmlRefString)) {
++ reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL));
++ return false;
++ }
++ if (!insertXmlRef(xmlRefString, reference, false))
++ return false;
++ skipIt = false;
++ }
++ }
++ if (skipIt && contentHnd) {
++ skipped_entity_in_content = true;
++ if (!contentHnd->skippedEntity(reference)) {
++ skipped_entity_in_content = false;
++ reportParseError(contentHnd->errorString());
++ return false; // error
++ }
++ skipped_entity_in_content = false;
++ }
++ parseReference_charDataRead = false;
++ } break;
++ case InAttributeValue:
++ // Forbidden
++ parseReference_charDataRead = false;
++ reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINAV));
++ return false;
++ case InEntityValue:
++ {
++ // Bypassed
++ stringAddC(QLatin1Char('&'));
++ for (const QChar c : std::as_const(reference))
++ stringAddC(c);
++ stringAddC(QLatin1Char(';'));
++ parseReference_charDataRead = true;
++ }
++ break;
++ case InDTD:
++ // Forbidden
++ parseReference_charDataRead = false;
++ reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINDTD));
++ return false;
++ }
++ } else {
++ // "Unparsed"
++ // ### notify for "Occurs as Attribute Value" missing (but this is no reference, anyway)
++ // Forbidden
++ parseReference_charDataRead = false;
++ reportParseError(QLatin1String(XMLERR_UNPARSEDENTITYREFERENCE));
++ return false; // error
++ }
++ }
++ }
++ return true; // no error
++ }
++
++ /*
++ Parses over a simple string.
++
++ After the string was successfully parsed, the head is on the first
++ character after the string.
++ */
++ bool QXmlSimpleReaderPrivate::parseString()
++ {
++ const signed char InpCharExpected = 0; // the character that was expected
++ const signed char InpUnknown = 1;
++
++ signed char input;
++
++ if (parseStack == nullptr || parseStack->isEmpty())
++ Done = parseString_s.size();
++
++ // state in this function is the position in the parseString_s string.
++ // Note: it's fine to use int here, because parseString_s is only used
++ // for pre-defined constant strings, and each of them has <= 20 characters.
++ int state = tryUnwindParseStack(&QXmlSimpleReaderPrivate::parseString);
++ if (state < 0)
++ return false;
++
++ for (;;) {
++ if (state == Done) {
++ return true;
++ }
++
++ if (atEnd()) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::parseString, state);
++ return false;
++ }
++ if (c == parseString_s[(int)state]) {
++ input = InpCharExpected;
++ } else {
++ input = InpUnknown;
++ }
++ if (input == InpCharExpected) {
++ state++;
++ } else {
++ // Error
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
++ return false;
++ }
++
++ next();
++ }
++ return false;
++ }
++
++ /*
++ This private function inserts and reports an entity substitution. The
++ substituted string is \a data and the name of the entity reference is \a
++ name. If \a inLiteral is true, the entity is IncludedInLiteral (i.e., " and '
++ must be quoted. Otherwise they are not quoted. Unless \a check is
++ ExpansionCheck::None, the size of the substitution is checked against the
++ expansion limit.
++
++ This function returns \c false on error.
++ */
++ bool QXmlSimpleReaderPrivate::insertXmlRef(const QString &data, const QString &name, bool inLiteral,
++ ExpansionCheck check)
++ {
++ if (check != ExpansionCheck::None) {
++ QString errorMessage;
++ if (addToExpandedEntitySize(name, data, check, &errorMessage)) {
++ reportParseError(errorMessage);
++ return false;
++ }
++ }
++ if (inLiteral) {
++ QString tmp = data;
++ xmlRefStack.push(XmlRef(name, tmp.replace(QLatin1Char('\"'), QLatin1String("&quot;"))
++ .replace(QLatin1Char('\''), QLatin1String("&apos;")),
++ check));
++ } else {
++ xmlRefStack.push(XmlRef(name, data, check));
++ }
++ qsizetype n = qMax(parameterEntities.size(), entities.size());
++ if (xmlRefStack.size() > n+1) {
++ // recursive entities
++ reportParseError(QLatin1String(XMLERR_RECURSIVEENTITIES));
++ return false;
++ }
++ if (reportEntities && lexicalHnd) {
++ if (!lexicalHnd->startEntity(name)) {
++ reportParseError(lexicalHnd->errorString());
++ return false;
++ }
++ }
++ return true;
++ }
++
++ /*
++ This private function moves the cursor to the next character.
++ */
++ void QXmlSimpleReaderPrivate::next()
++ {
++ qsizetype count = xmlRefStack.size();
++ while (count != 0) {
++ if (xmlRefStack.top().isEmpty()) {
++ xmlRefStack.pop_back();
++ count--;
++ } else {
++ c = xmlRefStack.top().next();
++ return;
++ }
++ }
++
++ // the following could be written nicer, but since it is a time-critical
++ // function, rather optimize for speed
++ ushort uc = c.unicode();
++ c = inputSource->next();
++ // If we are not incremental parsing, we just skip over EndOfData chars to give the
++ // parser an uninterrupted stream of document chars.
++ if (c == QXmlInputSource::EndOfData && parseStack == nullptr)
++ c = inputSource->next();
++ if (uc == '\n') {
++ lineNr++;
++ columnNr = -1;
++ } else if (uc == '\r') {
++ if (c != QLatin1Char('\n')) {
++ lineNr++;
++ columnNr = -1;
++ }
++ }
++ ++columnNr;
++ }
++
++ /*
++ This private function moves the cursor to the next non-whitespace character.
++ This function does not move the cursor if the actual cursor position is a
++ non-whitespace character.
++
++ Returns \c false when you use incremental parsing and this function reaches EOF
++ with reading only whitespace characters. In this case it also populates the
++ parseStack with useful information. In all other cases, this function returns
++ true.
++ */
++ bool QXmlSimpleReaderPrivate::eat_ws()
++ {
++ while (!atEnd()) {
++ if (!is_S(c)) {
++ return true;
++ }
++ next();
++ }
++ if (parseStack != nullptr) {
++ unexpectedEof(&QXmlSimpleReaderPrivate::eat_ws, 0);
++ return false;
++ }
++ return true;
++ }
++
++ bool QXmlSimpleReaderPrivate::next_eat_ws()
++ {
++ next();
++ return eat_ws();
++ }
++
++ /*
++ This private function initializes the reader. \a i is the input source to
++ read the data from.
++ */
++ void QXmlSimpleReaderPrivate::init(const QXmlInputSource *i)
++ {
++ lineNr = 0;
++ columnNr = -1;
++ inputSource = const_cast<QXmlInputSource *>(i);
++ initData();
++
++ externParameterEntities.clear();
++ parameterEntities.clear();
++ externEntities.clear();
++ entities.clear();
++
++ clear(tags);
++
++ doctype.clear();
++ xmlVersion.clear();
++ encoding.clear();
++ standalone = QXmlSimpleReaderPrivate::Unknown;
++ error.clear();
++ }
++
++ /*
++ This private function initializes the XML data related variables. Especially,
++ it reads the data from the input source.
++ */
++ void QXmlSimpleReaderPrivate::initData()
++ {
++ c = QXmlInputSource::EndOfData;
++ xmlRefStack.clear();
++ next();
++ }
++
++ /*
++ Returns \c true if a entity with the name \a e exists,
++ otherwise returns \c false.
++ */
++ bool QXmlSimpleReaderPrivate::entityExist(const QString& e) const
++ {
++ if ( parameterEntities.find(e) == parameterEntities.end() &&
++ externParameterEntities.find(e) == externParameterEntities.end() &&
++ externEntities.find(e) == externEntities.end() &&
++ entities.find(e) == entities.end()) {
++ return false;
++ } else {
++ return true;
++ }
++ }
++
++ void QXmlSimpleReaderPrivate::reportParseError(const QString& error)
++ {
++ this->error = error;
++ if (errorHnd) {
++ if (this->error.isNull()) {
++ const QXmlParseException ex(QLatin1String(XMLERR_OK), reportedPosition(columnNr),
++ reportedPosition(lineNr), thisPublicId, thisSystemId);
++ errorHnd->fatalError(ex);
++ } else {
++ const QXmlParseException ex(this->error, reportedPosition(columnNr),
++ reportedPosition(lineNr), thisPublicId, thisSystemId);
++ errorHnd->fatalError(ex);
++ }
++ }
++ }
++
++ /*
++ This private function is called when a parsing function encounters an
++ unexpected EOF. It decides what to do (depending on incremental parsing or
++ not). \a where is a pointer to the function where the error occurred and \a
++ state is the parsing state in this function.
++ */
++ void QXmlSimpleReaderPrivate::unexpectedEof(ParseFunction where, int state)
++ {
++ if (parseStack == nullptr) {
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
++ } else {
++ if (c == QXmlInputSource::EndOfDocument) {
++ reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
++ } else {
++ pushParseState(where, state);
++ }
++ }
++ }
++
++ /*
++ This private function is called when a parse...() function returned false. It
++ determines if there was an error or if incremental parsing simply went out of
++ data and does the right thing for the case. \a where is a pointer to the
++ function where the error occurred and \a state is the parsing state in this
++ function.
++ */
++ void QXmlSimpleReaderPrivate::parseFailed(ParseFunction where, int state)
++ {
++ if (parseStack != nullptr && error.isNull()) {
++ pushParseState(where, state);
++ }
++ }
++
++ /*
++ This private function pushes the function pointer \a function and state \a
++ state to the parse stack. This is used when you are doing an incremental
++ parsing and reach the end of file too early.
++
++ Only call this function when d->parseStack!=0.
++ */
++ void QXmlSimpleReaderPrivate::pushParseState(ParseFunction function, int state)
++ {
++ QXmlSimpleReaderPrivate::ParseState ps;
++ ps.function = function;
++ ps.state = state;
++ parseStack->push(ps);
++ }
++
++ inline static void updateValue(QString &value, const QChar *array, int &arrayPos)
++ {
++ const auto sz = value.size();
++ value.resize(sz + arrayPos);
++ memcpy(value.data() + sz, array, arrayPos * sizeof(QChar));
++ arrayPos = 0;
++ }
++
++ // use buffers instead of QString::operator+= when single characters are read
++ const QString& QXmlSimpleReaderPrivate::string()
++ {
++ updateValue(stringValue, stringArray, stringArrayPos);
++ return stringValue;
++ }
++ const QString& QXmlSimpleReaderPrivate::name()
++ {
++ updateValue(nameValue, nameArray, nameArrayPos);
++ return nameValue;
++ }
++ const QString& QXmlSimpleReaderPrivate::ref()
++ {
++ updateValue(refValue, refArray, refArrayPos);
++ return refValue;
++ }
++
++ void QXmlSimpleReaderPrivate::stringAddC(QChar ch)
++ {
++ if (stringArrayPos == 256)
++ updateValue(stringValue, stringArray, stringArrayPos);
++ stringArray[stringArrayPos++] = ch;
++ }
++ void QXmlSimpleReaderPrivate::nameAddC(QChar ch)
++ {
++ if (nameArrayPos == 256)
++ updateValue(nameValue, nameArray, nameArrayPos);
++ nameArray[nameArrayPos++] = ch;
++ }
++ void QXmlSimpleReaderPrivate::refAddC(QChar ch)
++ {
++ if (refArrayPos == 256)
++ updateValue(refValue, refArray, refArrayPos);
++ refArray[refArrayPos++] = ch;
++ }
++
++ QT_END_NAMESPACE