diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/corelib/xml | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/corelib/xml')
-rw-r--r-- | src/corelib/xml/.gitignore | 1 | ||||
-rwxr-xr-x | src/corelib/xml/make-parser.sh | 15 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.cpp | 3849 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.g | 1846 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.h | 477 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream_p.h | 1962 | ||||
-rw-r--r-- | src/corelib/xml/qxmlutils.cpp | 390 | ||||
-rw-r--r-- | src/corelib/xml/qxmlutils_p.h | 92 | ||||
-rw-r--r-- | src/corelib/xml/xml.pri | 10 |
9 files changed, 8642 insertions, 0 deletions
diff --git a/src/corelib/xml/.gitignore b/src/corelib/xml/.gitignore new file mode 100644 index 0000000..89f9ac0 --- /dev/null +++ b/src/corelib/xml/.gitignore @@ -0,0 +1 @@ +out/ diff --git a/src/corelib/xml/make-parser.sh b/src/corelib/xml/make-parser.sh new file mode 100755 index 0000000..0c2ba12 --- /dev/null +++ b/src/corelib/xml/make-parser.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +me=$(dirname $0) +mkdir -p $me/out +(cd $me/out && ../../../../util/qlalr/qlalr --troll --no-debug --no-lines ../qxmlstream.g) + +for f in $me/out/*.h; do + n=$(basename $f) + p4 open $n + cp $f $n +done + +p4 revert -a ... +p4 diff -dub ... + diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp new file mode 100644 index 0000000..ff1a01f --- /dev/null +++ b/src/corelib/xml/qxmlstream.cpp @@ -0,0 +1,3849 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "QtCore/qxmlstream.h" + +#if defined(QT_BUILD_XML_LIB) && defined(Q_OS_MAC64) +// No need to define this in the 64-bit Mac libraries. +// Since Qt 4.4 and previous weren't supported in 64-bit, there are +// no QXmlStream* symbols to keep compatibility with +# define QT_NO_XMLSTREAM +#endif + +#ifndef QT_NO_XMLSTREAM + +#include "qxmlutils_p.h" +#include <qdebug.h> +#include <QFile> +#include <stdio.h> +#include <qtextcodec.h> +#include <qstack.h> +#include <qbuffer.h> +#ifndef QT_BOOTSTRAPPED +#include <QCoreApplication> +#else +// This specialization of Q_DECLARE_TR_FUNCTIONS is not in qcoreapplication.h, +// because that header depends on QObject being available, which is not the +// case for most bootstrapped applications. +#define Q_DECLARE_TR_FUNCTIONS(context) \ +public: \ + static inline QString tr(const char *sourceText, const char *comment = 0) \ + { Q_UNUSED(comment); return QString::fromLatin1(sourceText); } \ + static inline QString trUtf8(const char *sourceText, const char *comment = 0) \ + { Q_UNUSED(comment); return QString::fromLatin1(sourceText); } \ + static inline QString tr(const char *sourceText, const char*, int) \ + { return QString::fromLatin1(sourceText); } \ + static inline QString trUtf8(const char *sourceText, const char*, int) \ + { return QString::fromLatin1(sourceText); } \ +private: +#endif +QT_BEGIN_NAMESPACE + +#include "qxmlstream_p.h" + +/*! + \enum QXmlStreamReader::TokenType + + This enum specifies the type of token the reader just read. + + \value NoToken The reader has not yet read anything. + + \value Invalid An error has occurred, reported in error() and + errorString(). + + \value StartDocument The reader reports the XML version number in + documentVersion(), and the encoding as specified in the XML + document in documentEncoding(). If the document is declared + standalone, isStandaloneDocument() returns true; otherwise it + returns false. + + \value EndDocument The reader reports the end of the document. + + \value StartElement The reader reports the start of an element + with namespaceUri() and name(). Empty elements are also reported + as StartElement, followed directly by EndElement. The convenience + function readElementText() can be called to concatenate all + content until the corresponding EndElement. Attributes are + reported in attributes(), namespace declarations in + namespaceDeclarations(). + + \value EndElement The reader reports the end of an element with + namespaceUri() and name(). + + \value Characters The reader reports characters in text(). If the + characters are all white-space, isWhitespace() returns true. If + the characters stem from a CDATA section, isCDATA() returns true. + + \value Comment The reader reports a comment in text(). + + \value DTD The reader reports a DTD in text(), notation + declarations in notationDeclarations(), and entity declarations in + entityDeclarations(). Details of the DTD declaration are reported + in in dtdName(), dtdPublicId(), and dtdSystemId(). + + \value EntityReference The reader reports an entity reference that + could not be resolved. The name of the reference is reported in + name(), the replacement text in text(). + + \value ProcessingInstruction The reader reports a processing + instruction in processingInstructionTarget() and + processingInstructionData(). +*/ + +/*! + \enum QXmlStreamReader::Error + + This enum specifies different error cases + + \value NoError No error has occurred. + + \value CustomError A custom error has been raised with + raiseError() + + \value NotWellFormedError The parser internally raised an error + due to the read XML not being well-formed. + + \value PrematureEndOfDocumentError The input stream ended before a + well-formed XML document was parsed. Recovery from this error is + possible if more XML arrives in the stream, either by calling + addData() or by waiting for it to arrive on the device(). + + \value UnexpectedElementError The parser encountered an element + that was different to those it expected. + +*/ + +/*! + \class QXmlStreamEntityResolver + \reentrant + \since 4.4 + + \brief The QXmlStreamEntityResolver class provides an entity + resolver for a QXmlStreamReader. + + \ingroup xml-tools + */ + +/*! + Destroys the entity resolver. + */ +QXmlStreamEntityResolver::~QXmlStreamEntityResolver() +{ +} + +/*! \internal + +This function is a stub for later functionality. +*/ +QString QXmlStreamEntityResolver::resolveEntity(const QString& /*publicId*/, const QString& /*systemId*/) +{ + return QString(); +} + + +/*! + Resolves the undeclared entity \a name and returns its replacement + text. If the entity is also unknown to the entity resolver, it + returns an empty string. + + The default implementation always returns an empty string. +*/ + +QString QXmlStreamEntityResolver::resolveUndeclaredEntity(const QString &/*name*/) +{ + return QString(); +} + +#ifndef QT_NO_XMLSTREAMREADER + +QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(const QString &name) +{ + if (entityResolver) + return entityResolver->resolveUndeclaredEntity(name); + return QString(); +} + + + +/*! + \since 4.4 + + Makes \a resolver the new entityResolver(). + + The stream reader does \e not take ownership of the resolver. It's + the callers responsibility to ensure that the resolver is valid + during the entire life-time of the stream reader object, or until + another resolver or 0 is set. + + \sa entityResolver() + */ +void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver) +{ + Q_D(QXmlStreamReader); + d->entityResolver = resolver; +} + +/*! + \since 4.4 + + Returns the entity resolver, or 0 if there is no entity resolver. + + \sa setEntityResolver() + */ +QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const +{ + Q_D(const QXmlStreamReader); + return d->entityResolver; +} + + + +/*! + \class QXmlStreamReader + \reentrant + \since 4.3 + + \brief The QXmlStreamReader class provides a fast parser for reading + well-formed XML via a simple streaming API. + + \mainclass + \ingroup xml-tools + + QXmlStreamReader is a faster and more convenient replacement for + Qt's own SAX parser (see QXmlSimpleReader). In some cases it might + also be a faster and more convenient alternative for use in + applications that would otherwise use a DOM tree (see QDomDocument). + QXmlStreamReader reads data either from a QIODevice (see + setDevice()), or from a raw QByteArray (see addData()). + + Qt provides QXmlStreamWriter for writing XML. + + The basic concept of a stream reader is to report an XML document as + a stream of tokens, similar to SAX. The main difference between + QXmlStreamReader and SAX is \e how these XML tokens are reported. + With SAX, the application must provide handlers (callback functions) + that receive so-called XML \e events from the parser at the parser's + convenience. With QXmlStreamReader, the application code itself + drives the loop and pulls \e tokens from the reader, one after + another, as it needs them. This is done by calling readNext(), where + the reader reads from the input stream until it completes the next + token, at which point it returns the tokenType(). A set of + convenient functions including isStartElement() and text() can then + be used to examine the token to obtain information about what has + been read. The big advantage of this \e pulling approach is the + possibility to build recursive descent parsers with it, meaning you + can split your XML parsing code easily into different methods or + classes. This makes it easy to keep track of the application's own + state when parsing XML. + + A typical loop with QXmlStreamReader looks like this: + + \snippet doc/src/snippets/code/src_corelib_xml_qxmlstream.cpp 0 + + + QXmlStreamReader is a well-formed XML 1.0 parser that does \e not + include external parsed entities. As long as no error occurs, the + application code can thus be assured that the data provided by the + stream reader satisfies the W3C's criteria for well-formed XML. For + example, you can be certain that all tags are indeed nested and + closed properly, that references to internal entities have been + replaced with the correct replacement text, and that attributes have + been normalized or added according to the internal subset of the + DTD. + + If an error occurs while parsing, atEnd() and hasError() return + true, and error() returns the error that occurred. The functions + errorString(), lineNumber(), columnNumber(), and characterOffset() + are for constructing an appropriate error or warning message. To + simplify application code, QXmlStreamReader contains a raiseError() + mechanism that lets you raise custom errors that trigger the same + error handling described. + + The \l{QXmlStream Bookmarks Example} illustrates how to use the + recursive descent technique with a subclassed stream reader to read + an XML bookmark file (XBEL). + + \section1 Namespaces + + QXmlStream understands and resolves XML namespaces. E.g. in case of + a StartElement, namespaceUri() returns the namespace the element is + in, and name() returns the element's \e local name. The combination + of namespaceUri and name uniquely identifies an element. If a + namespace prefix was not declared in the XML entities parsed by the + reader, the namespaceUri is empty. + + If you parse XML data that does not utilize namespaces according to + the XML specification or doesn't use namespaces at all, you can use + the element's qualifiedName() instead. A qualified name is the + element's prefix() followed by colon followed by the element's local + name() - exactly like the element appears in the raw XML data. Since + the mapping namespaceUri to prefix is neither unique nor universal, + qualifiedName() should be avoided for namespace-compliant XML data. + + In order to parse standalone documents that do use undeclared + namespace prefixes, you can turn off namespace processing completely + with the \l namespaceProcessing property. + + \section1 Incremental parsing + + QXmlStreamReader is an incremental parser. It can handle the case + where the document can't be parsed all at once because it arrives in + chunks (e.g. from multiple files, or over a network connection). + When the reader runs out of data before the complete document has + been parsed, it reports a PrematureEndOfDocumentError. When more + data arrives, either because of a call to addData() or because more + data is available through the network device(), the reader recovers + from the PrematureEndOfDocumentError error and continues parsing the + new data with the next call to readNext(). + + For example, if you read data from the network using QHttp, you + would connect its \l{QHttp::readyRead()}{readyRead()} signal to a + custom slot. In this slot, you read all available data with + \l{QHttp::readAll()}{readAll()} and pass it to the XML stream reader + using addData(). Then you call your custom parsing function that + reads the XML events from the reader. + + \section1 Performance and memory consumption + + QXmlStreamReader is memory-conservative by design, since it doesn't + store the entire XML document tree in memory, but only the current + token at the time it is reported. In addition, QXmlStreamReader + avoids the many small string allocations that it normally takes to + map an XML document to a convenient and Qt-ish API. It does this by + reporting all string data as QStringRef rather than real QString + objects. QStringRef is a thin wrapper around QString substrings that + provides a subset of the QString API without the memory allocation + and reference-counting overhead. Calling + \l{QStringRef::toString()}{toString()} on any of those objects + returns an equivalent real QString object. + +*/ + + +/*! + Constructs a stream reader. + + \sa setDevice(), addData() + */ +QXmlStreamReader::QXmlStreamReader() + : d_ptr(new QXmlStreamReaderPrivate(this)) +{ +} + +/*! Creates a new stream reader that reads from \a device. + +\sa setDevice(), clear() + */ +QXmlStreamReader::QXmlStreamReader(QIODevice *device) + : d_ptr(new QXmlStreamReaderPrivate(this)) +{ + setDevice(device); +} + +/*! + Creates a new stream reader that reads from \a data. + + \sa addData(), clear(), setDevice() + */ +QXmlStreamReader::QXmlStreamReader(const QByteArray &data) + : d_ptr(new QXmlStreamReaderPrivate(this)) +{ + Q_D(QXmlStreamReader); + d->dataBuffer = data; +} + +/*! + Creates a new stream reader that reads from \a data. + + \sa addData(), clear(), setDevice() + */ +QXmlStreamReader::QXmlStreamReader(const QString &data) + : d_ptr(new QXmlStreamReaderPrivate(this)) +{ + Q_D(QXmlStreamReader); +#ifdef QT_NO_TEXTCODEC + d->dataBuffer = data.toLatin1(); +#else + d->dataBuffer = d->codec->fromUnicode(data); + d->decoder = d->codec->makeDecoder(); +#endif + d->lockEncoding = true; + +} + +/*! + Creates a new stream reader that reads from \a data. + + \sa addData(), clear(), setDevice() + */ +QXmlStreamReader::QXmlStreamReader(const char *data) + : d_ptr(new QXmlStreamReaderPrivate(this)) +{ + Q_D(QXmlStreamReader); + d->dataBuffer = QByteArray(data); +} + +/*! + Destructs the reader. + */ +QXmlStreamReader::~QXmlStreamReader() +{ + Q_D(QXmlStreamReader); + if (d->deleteDevice) + delete d->device; + delete d; +} + +/*! \fn bool QXmlStreamReader::hasError() const + Returns \c true if an error has occurred, otherwise \c false. + + \sa errorString(), error() + */ + +/*! + Sets the current device to \a device. Setting the device resets + the stream to its initial state. + + \sa device(), clear() +*/ +void QXmlStreamReader::setDevice(QIODevice *device) +{ + Q_D(QXmlStreamReader); + if (d->deleteDevice) { + delete d->device; + d->deleteDevice = false; + } + d->device = device; + d->init(); + +} + +/*! + Returns the current device associated with the QXmlStreamReader, + or 0 if no device has been assigned. + + \sa setDevice() +*/ +QIODevice *QXmlStreamReader::device() const +{ + Q_D(const QXmlStreamReader); + return d->device; +} + + +/*! + Adds more \a data for the reader to read. This function does + nothing if the reader has a device(). + + \sa readNext(), clear() + */ +void QXmlStreamReader::addData(const QByteArray &data) +{ + Q_D(QXmlStreamReader); + if (d->device) { + qWarning("QXmlStreamReader: addData() with device()"); + return; + } + d->dataBuffer += data; +} + +/*! + Adds more \a data for the reader to read. This function does + nothing if the reader has a device(). + + \sa readNext(), clear() + */ +void QXmlStreamReader::addData(const QString &data) +{ + Q_D(QXmlStreamReader); + d->lockEncoding = true; +#ifdef QT_NO_TEXTCODEC + addData(data.toLatin1()); +#else + addData(d->codec->fromUnicode(data)); +#endif +} + +/*! + Adds more \a data for the reader to read. This function does + nothing if the reader has a device(). + + \sa readNext(), clear() + */ +void QXmlStreamReader::addData(const char *data) +{ + addData(QByteArray(data)); +} + +/*! + Removes any device() or data from the reader and resets its + internal state to the initial state. + + \sa addData() + */ +void QXmlStreamReader::clear() +{ + Q_D(QXmlStreamReader); + d->init(); + if (d->device) { + if (d->deleteDevice) + delete d->device; + d->device = 0; + } +} + +/*! + Returns true if the reader has read until the end of the XML + document, or if an error() has occurred and reading has been + aborted. Otherwise, it returns false. + + When atEnd() and hasError() return true and error() returns + PrematureEndOfDocumentError, it means the XML has been well-formed + so far, but a complete XML document has not been parsed. The next + chunk of XML can be added with addData(), if the XML is being read + from a QByteArray, or by waiting for more data to arrive if the + XML is being read from a QIODevice. Either way, atEnd() will + return false once more adata is available. + + \sa hasError(), error(), device(), QIODevice::atEnd() + */ +bool QXmlStreamReader::atEnd() const +{ + Q_D(const QXmlStreamReader); + if (d->atEnd + && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError) + || (d->type == QXmlStreamReader::EndDocument))) { + if (d->device) + return d->device->atEnd(); + else + return !d->dataBuffer.size(); + } + return (d->atEnd || d->type == QXmlStreamReader::Invalid); +} + + +/*! + Reads the next token and returns its type. + + With one exception, once an error() is reported by readNext(), + further reading of the XML stream is not possible. Then atEnd() + returns true, hasError() returns true, and this function returns + QXmlStreamReader::Invalid. + + The exception is when error() return PrematureEndOfDocumentError. + This error is reported when the end of an otherwise well-formed + chunk of XML is reached, but the chunk doesn't represent a complete + XML document. In that case, parsing \e can be resumed by calling + addData() to add the next chunk of XML, when the stream is being + read from a QByteArray, or by waiting for more data to arrive when + the stream is being read from a device(). + + \sa tokenType(), tokenString() + */ +QXmlStreamReader::TokenType QXmlStreamReader::readNext() +{ + Q_D(QXmlStreamReader); + if (d->type != Invalid) { + if (!d->hasCheckedStartDocument) + if (!d->checkStartDocument()) + return d->type; // synthetic StartDocument or error + d->parse(); + if (d->atEnd && d->type != EndDocument && d->type != Invalid) + d->raiseError(PrematureEndOfDocumentError); + else if (!d->atEnd && d->type == EndDocument) + d->raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); + } else if (d->error == PrematureEndOfDocumentError) { + // resume error + d->type = NoToken; + d->atEnd = false; + d->token = -1; + return readNext(); + } + return d->type; +} + + +/*! + Returns the type of the current token. + + The current token can also be queried with the convenience functions + isStartDocument(), isEndDocument(), isStartElement(), + isEndElement(), isCharacters(), isComment(), isDTD(), + isEntityReference(), and isProcessingInstruction(). + + \sa tokenString() + */ +QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const +{ + Q_D(const QXmlStreamReader); + return d->type; +} + +/* + * Use the following Perl script to generate the error string index list: +===== PERL SCRIPT ==== +print "static const char QXmlStreamReader_tokenTypeString_string[] =\n"; +$counter = 0; +$i = 0; +while (<STDIN>) { + chomp; + print " \"$_\\0\"\n"; + $sizes[$i++] = $counter; + $counter += length 1 + $_; +} +print " \"\\0\";\n\nstatic const int QXmlStreamReader_tokenTypeString_indices[] = {\n "; +for ($j = 0; $j < $i; ++$j) { + printf "$sizes[$j], "; +} +print "0\n};\n"; +===== PERL SCRIPT ==== + + * The input data is as follows (copied from qxmlstream.h): +NoToken +Invalid +StartDocument +EndDocument +StartElement +EndElement +Characters +Comment +DTD +EntityReference +ProcessingInstruction +*/ +static const char QXmlStreamReader_tokenTypeString_string[] = + "NoToken\0" + "Invalid\0" + "StartDocument\0" + "EndDocument\0" + "StartElement\0" + "EndElement\0" + "Characters\0" + "Comment\0" + "DTD\0" + "EntityReference\0" + "ProcessingInstruction\0" + "\0"; + +static const int QXmlStreamReader_tokenTypeString_indices[] = { + 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 +}; + + +/*! + \property QXmlStreamReader::namespaceProcessing + the namespace-processing flag of the stream reader + + This property controls whether or not the stream reader processes + namespaces. If enabled, the reader processes namespaces, otherwise + it does not. + + By default, namespace-processing is enabled. +*/ + + +void QXmlStreamReader::setNamespaceProcessing(bool enable) +{ + Q_D(QXmlStreamReader); + d->namespaceProcessing = enable; +} + +bool QXmlStreamReader::namespaceProcessing() const +{ + Q_D(const QXmlStreamReader); + return d->namespaceProcessing; +} + +/*! Returns the reader's current token as string. + +\sa tokenType() +*/ +QString QXmlStreamReader::tokenString() const +{ + Q_D(const QXmlStreamReader); + return QLatin1String(QXmlStreamReader_tokenTypeString_string + + QXmlStreamReader_tokenTypeString_indices[d->type]); +} + +#endif // QT_NO_XMLSTREAMREADER + +QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack() +{ + tagStack.reserve(16); + tagStackStringStorage.reserve(32); + tagStackStringStorageSize = 0; + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + namespaceDeclaration.prefix = addToStringStorage(QLatin1String("xml")); + namespaceDeclaration.namespaceUri = addToStringStorage(QLatin1String("http://www.w3.org/XML/1998/namespace")); +} + +#ifndef QT_NO_XMLSTREAMREADER + +QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q) + :q_ptr(q) +{ + device = 0; + deleteDevice = false; +#ifndef QT_NO_TEXTCODEC + decoder = 0; +#endif + stack_size = 64; + sym_stack = 0; + state_stack = 0; + reallocateStack(); + entityResolver = 0; + init(); + entityHash.insert(QLatin1String("lt"), Entity::createLiteral(QLatin1String("<"))); + entityHash.insert(QLatin1String("gt"), Entity::createLiteral(QLatin1String(">"))); + entityHash.insert(QLatin1String("amp"), Entity::createLiteral(QLatin1String("&"))); + entityHash.insert(QLatin1String("apos"), Entity::createLiteral(QLatin1String("'"))); + entityHash.insert(QLatin1String("quot"), Entity::createLiteral(QLatin1String("\""))); +} + +void QXmlStreamReaderPrivate::init() +{ + tos = 0; + scanDtd = false; + token = -1; + token_char = 0; + isEmptyElement = false; + isWhitespace = true; + isCDATA = false; + standalone = false; + tos = 0; + resumeReduction = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + putStack.clear(); + putStack.reserve(32); + textBuffer.clear(); + textBuffer.reserve(256); + tagStack.clear(); + tagsDone = false; + attributes.clear(); + attributes.reserve(16); + lineNumber = lastLineStart = characterOffset = 0; + readBufferPos = 0; + nbytesread = 0; +#ifndef QT_NO_TEXTCODEC + codec = QTextCodec::codecForMib(106); // utf8 + delete decoder; + decoder = 0; +#endif + attributeStack.clear(); + attributeStack.reserve(16); + entityParser = 0; + hasCheckedStartDocument = false; + normalizeLiterals = false; + hasSeenTag = false; + atEnd = false; + inParseEntity = false; + referenceToUnparsedEntityDetected = false; + referenceToParameterEntityDetected = false; + hasExternalDtdSubset = false; + lockEncoding = false; + namespaceProcessing = true; + rawReadBuffer.clear(); + dataBuffer.clear(); + readBuffer.clear(); + + type = QXmlStreamReader::NoToken; + error = QXmlStreamReader::NoError; +} + +/* + Well-formed requires that we verify entity values. We do this with a + standard parser. + */ +void QXmlStreamReaderPrivate::parseEntity(const QString &value) +{ + Q_Q(QXmlStreamReader); + + if (value.isEmpty()) + return; + + + if (!entityParser) + entityParser = new QXmlStreamReaderPrivate(q); + else + entityParser->init(); + entityParser->inParseEntity = true; + entityParser->readBuffer = value; + entityParser->injectToken(PARSE_ENTITY); + while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid) + entityParser->parse(); + if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size()) + raiseWellFormedError(QXmlStream::tr("Invalid entity value.")); + +} + +inline void QXmlStreamReaderPrivate::reallocateStack() +{ + stack_size <<= 1; + sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); +} + + +QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate() +{ +#ifndef QT_NO_TEXTCODEC + delete decoder; +#endif + qFree(sym_stack); + qFree(state_stack); + delete entityParser; +} + + +inline uint QXmlStreamReaderPrivate::filterCarriageReturn() +{ + uint peekc = peekChar(); + if (peekc == '\n') { + if (putStack.size()) + putStack.pop(); + else + ++readBufferPos; + return peekc; + } + if (peekc == 0) { + putChar('\r'); + return 0; + } + return '\n'; +} + +/*! + \internal + If the end of the file is encountered, 0 is returned. + */ +inline uint QXmlStreamReaderPrivate::getChar() +{ + uint c; + if (putStack.size()) { + c = atEnd ? 0 : putStack.pop(); + } else { + if (readBufferPos < readBuffer.size()) + c = readBuffer.at(readBufferPos++).unicode(); + else + c = getChar_helper(); + } + + return c; +} + +inline uint QXmlStreamReaderPrivate::peekChar() +{ + uint c; + if (putStack.size()) { + c = putStack.top(); + } else if (readBufferPos < readBuffer.size()) { + c = readBuffer.at(readBufferPos).unicode(); + } else { + if ((c = getChar_helper())) + --readBufferPos; + } + + return c; +} + +/*! + \internal + + Scans characters until \a str is encountered, and validates the characters + as according to the Char[2] production and do the line-ending normalization. + If any character is invalid, false is returned, otherwise true upon success. + + If \a tokenToInject is not less than zero, injectToken() is called with + \a tokenToInject when \a str is found. + + If any error occurred, false is returned, otherwise true. + */ +bool QXmlStreamReaderPrivate::scanUntil(const char *str, short tokenToInject) +{ + int pos = textBuffer.size(); + int oldLineNumber = lineNumber; + + while (uint c = getChar()) { + /* First, we do the validation & normalization. */ + switch (c) { + case '\r': + if ((c = filterCarriageReturn()) == 0) + break; + // fall through + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + // fall through + case '\t': + textBuffer += QChar(c); + continue; + default: + if(c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > 0x10FFFF ) { + raiseWellFormedError(QXmlStream::tr("Invalid XML character.")); + lineNumber = oldLineNumber; + return false; + } + textBuffer += QChar(c); + } + + + /* Second, attempt to lookup str. */ + if (c == uint(*str)) { + if (!*(str + 1)) { + if (tokenToInject >= 0) + injectToken(tokenToInject); + return true; + } else { + if (scanString(str + 1, tokenToInject, false)) + return true; + } + } + } + putString(textBuffer, pos); + textBuffer.resize(pos); + lineNumber = oldLineNumber; + return false; +} + +bool QXmlStreamReaderPrivate::scanString(const char *str, short tokenToInject, bool requireSpace) +{ + int n = 0; + while (str[n]) { + ushort c = getChar(); + if (c != ushort(str[n])) { + if (c) + putChar(c); + while (n--) { + putChar(ushort(str[n])); + } + return false; + } + ++n; + } + for (int i = 0; i < n; ++i) + textBuffer += QChar(ushort(str[i])); + if (requireSpace) { + int s = fastScanSpace(); + if (!s || atEnd) { + int pos = textBuffer.size() - n - s; + putString(textBuffer, pos); + textBuffer.resize(pos); + return false; + } + } + if (tokenToInject >= 0) + injectToken(tokenToInject); + return true; +} + +bool QXmlStreamReaderPrivate::scanAfterLangleBang() +{ + switch (peekChar()) { + case '[': + return scanString(spell[CDATA_START], CDATA_START, false); + case 'D': + return scanString(spell[DOCTYPE], DOCTYPE); + case 'A': + return scanString(spell[ATTLIST], ATTLIST); + case 'N': + return scanString(spell[NOTATION], NOTATION); + case 'E': + if (scanString(spell[ELEMENT], ELEMENT)) + return true; + return scanString(spell[ENTITY], ENTITY); + + default: + ; + }; + return false; +} + +bool QXmlStreamReaderPrivate::scanPublicOrSystem() +{ + switch (peekChar()) { + case 'S': + return scanString(spell[SYSTEM], SYSTEM); + case 'P': + return scanString(spell[PUBLIC], PUBLIC); + default: + ; + } + return false; +} + +bool QXmlStreamReaderPrivate::scanNData() +{ + if (fastScanSpace()) { + if (scanString(spell[NDATA], NDATA)) + return true; + putChar(' '); + } + return false; +} + +bool QXmlStreamReaderPrivate::scanAfterDefaultDecl() +{ + switch (peekChar()) { + case 'R': + return scanString(spell[REQUIRED], REQUIRED, false); + case 'I': + return scanString(spell[IMPLIED], IMPLIED, false); + case 'F': + return scanString(spell[FIXED], FIXED, false); + default: + ; + } + return false; +} + +bool QXmlStreamReaderPrivate::scanAttType() +{ + switch (peekChar()) { + case 'C': + return scanString(spell[CDATA], CDATA); + case 'I': + if (scanString(spell[ID], ID)) + return true; + if (scanString(spell[IDREF], IDREF)) + return true; + return scanString(spell[IDREFS], IDREFS); + case 'E': + if (scanString(spell[ENTITY], ENTITY)) + return true; + return scanString(spell[ENTITIES], ENTITIES); + case 'N': + if (scanString(spell[NOTATION], NOTATION)) + return true; + if (scanString(spell[NMTOKEN], NMTOKEN)) + return true; + return scanString(spell[NMTOKENS], NMTOKENS); + default: + ; + } + return false; +} + +/*! + \internal + + Scan strings with quotes or apostrophes surround them. For instance, + attributes, the version and encoding field in the XML prolog and + entity declarations. + + If normalizeLiterals is set to true, the function also normalizes + whitespace. It is set to true when the first start tag is + encountered. + + */ +inline int QXmlStreamReaderPrivate::fastScanLiteralContent() +{ + int n = 0; + uint c; + while ((c = getChar())) { + switch (ushort(c)) { + case 0xfffe: + case 0xffff: + case 0: + /* The putChar() call is necessary so the parser re-gets + * the character from the input source, when raising an error. */ + putChar(c); + return n; + case '\r': + if (filterCarriageReturn() == 0) + return n; + // fall through + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + // fall through + case ' ': + case '\t': + if (normalizeLiterals) + textBuffer += QLatin1Char(' '); + else + textBuffer += QChar(c); + ++n; + break; + case '&': + case '<': + case '\"': + case '\'': + if (!(c & 0xff0000)) { + putChar(c); + return n; + } + // fall through + default: + textBuffer += QChar(c); + ++n; + } + } + return n; +} + +inline int QXmlStreamReaderPrivate::fastScanSpace() +{ + int n = 0; + ushort c; + while ((c = getChar())) { + switch (c) { + case '\r': + if ((c = filterCarriageReturn()) == 0) + return n; + // fall through + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + // fall through + case ' ': + case '\t': + textBuffer += QChar(c); + ++n; + break; + default: + putChar(c); + return n; + } + } + return n; +} + +/*! + \internal + + Used for text nodes essentially. That is, characters appearing + inside elements. + */ +inline int QXmlStreamReaderPrivate::fastScanContentCharList() +{ + int n = 0; + uint c; + while ((c = getChar())) { + switch (ushort(c)) { + case 0xfffe: + case 0xffff: + case 0: + putChar(c); + return n; + case ']': { + isWhitespace = false; + int pos = textBuffer.size(); + textBuffer += QChar(ushort(c)); + ++n; + while ((c = getChar()) == ']') { + textBuffer += QChar(ushort(c)); + ++n; + } + if (c == 0) { + putString(textBuffer, pos); + textBuffer.resize(pos); + } else if (c == '>' && textBuffer.at(textBuffer.size()-2) == QLatin1Char(']')) { + raiseWellFormedError(QXmlStream::tr("Sequence ']]>' not allowed in content.")); + } else { + putChar(c); + break; + } + return n; + } break; + case '\r': + if ((c = filterCarriageReturn()) == 0) + return n; + // fall through + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + // fall through + case ' ': + case '\t': + textBuffer += QChar(ushort(c)); + ++n; + break; + case '&': + case '<': + if (!(c & 0xff0000)) { + putChar(c); + return n; + } + // fall through + default: + if (c < 0x20) { + putChar(c); + return n; + } + isWhitespace = false; + textBuffer += QChar(ushort(c)); + ++n; + } + } + return n; +} + +inline int QXmlStreamReaderPrivate::fastScanName(int *prefix) +{ + int n = 0; + ushort c; + while ((c = getChar())) { + switch (c) { + case '\n': + case ' ': + case '\t': + case '\r': + case '&': + case '#': + case '\'': + case '\"': + case '<': + case '>': + case '[': + case ']': + case '=': + case '%': + case '/': + case ';': + case '?': + case '!': + case '^': + case '|': + case ',': + case '(': + case ')': + case '+': + case '*': + putChar(c); + if (prefix && *prefix == n+1) { + *prefix = 0; + putChar(':'); + --n; + } + return n; + case ':': + if (prefix) { + if (*prefix == 0) { + *prefix = n+2; + } else { // only one colon allowed according to the namespace spec. + putChar(c); + return n; + } + } else { + putChar(c); + return n; + } + // fall through + default: + textBuffer += QChar(c); + ++n; + } + } + + if (prefix) + *prefix = 0; + int pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); + return 0; +} + +enum NameChar { NameBeginning, NameNotBeginning, NotName }; + +static const char Begi = static_cast<char>(NameBeginning); +static const char NtBg = static_cast<char>(NameNotBeginning); +static const char NotN = static_cast<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 static_cast<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; +} + +inline int QXmlStreamReaderPrivate::fastScanNMTOKEN() +{ + int n = 0; + uint c; + while ((c = getChar())) { + if (fastDetermineNameChar(c) == NotName) { + putChar(c); + return n; + } else { + ++n; + textBuffer += QChar(c); + } + } + + int pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); + + return n; +} + +void QXmlStreamReaderPrivate::putString(const QString &s, int from) +{ + putStack.reserve(s.size()); + for (int i = s.size()-1; i >= from; --i) + putStack.rawPush() = s.at(i).unicode(); +} + +void QXmlStreamReaderPrivate::putStringLiteral(const QString &s) +{ + putStack.reserve(s.size()); + for (int i = s.size()-1; i >= 0; --i) + putStack.rawPush() = ((LETTER << 16) | s.at(i).unicode()); +} + +void QXmlStreamReaderPrivate::putReplacement(const QString &s) +{ + putStack.reserve(s.size()); + for (int i = s.size()-1; i >= 0; --i) { + ushort c = s.at(i).unicode(); + if (c == '\n' || c == '\r') + putStack.rawPush() = ((LETTER << 16) | c); + else + putStack.rawPush() = c; + } +} +void QXmlStreamReaderPrivate::putReplacementInAttributeValue(const QString &s) +{ + putStack.reserve(s.size()); + for (int i = s.size()-1; i >= 0; --i) { + ushort c = s.at(i).unicode(); + if (c == '&' || c == ';') + putStack.rawPush() = c; + else if (c == '\n' || c == '\r') + putStack.rawPush() = ' '; + else + putStack.rawPush() = ((LETTER << 16) | c); + } +} + +ushort QXmlStreamReaderPrivate::getChar_helper() +{ + const int BUFFER_SIZE = 8192; + characterOffset += readBufferPos; + readBufferPos = 0; + readBuffer.resize(0); +#ifndef QT_NO_TEXTCODEC + if (decoder) +#endif + nbytesread = 0; + if (device) { + rawReadBuffer.resize(BUFFER_SIZE); + int nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread); + nbytesread += qMax(nbytesreadOrMinus1, 0); + } else { + if (nbytesread) + rawReadBuffer += dataBuffer; + else + rawReadBuffer = dataBuffer; + nbytesread = rawReadBuffer.size(); + dataBuffer.clear(); + } + if (!nbytesread) { + atEnd = true; + return 0; + } + +#ifndef QT_NO_TEXTCODEC + if (!decoder) { + if (nbytesread < 4) { // the 4 is to cover 0xef 0xbb 0xbf plus + // one extra for the utf8 codec + atEnd = true; + return 0; + } + int mib = 106; // UTF-8 + + // look for byte order mark + uchar ch1 = rawReadBuffer.at(0); + uchar ch2 = rawReadBuffer.at(1); + uchar ch3 = rawReadBuffer.at(2); + uchar ch4 = rawReadBuffer.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 + else 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 + codec = QTextCodec::codecForMib(mib); + Q_ASSERT(codec); + decoder = codec->makeDecoder(); + } + + decoder->toUnicode(&readBuffer, rawReadBuffer.data(), nbytesread); + + if(lockEncoding && decoder->hasFailure()) { + raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); + readBuffer.clear(); + return 0; + } +#else + readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread); +#endif // QT_NO_TEXTCODEC + + readBuffer.reserve(1); // keep capacity when calling resize() next time + + if (readBufferPos < readBuffer.size()) { + ushort c = readBuffer.at(readBufferPos++).unicode(); + return c; + } + + atEnd = true; + return 0; +} + +QStringRef QXmlStreamReaderPrivate::namespaceForPrefix(const QStringRef &prefix) +{ + for (int j = namespaceDeclarations.size() - 1; j >= 0; --j) { + const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(j); + if (namespaceDeclaration.prefix == prefix) { + return namespaceDeclaration.namespaceUri; + } + } + +#if 1 + if (namespaceProcessing && !prefix.isEmpty()) + raiseWellFormedError(QXmlStream::tr("Namespace prefix '%1' not declared").arg(prefix.toString())); +#endif + + return QStringRef(); +} + +/* + uses namespaceForPrefix and builds the attribute vector + */ +void QXmlStreamReaderPrivate::resolveTag() +{ + int n = attributeStack.size(); + + if (namespaceProcessing) { + for (int a = 0; a < dtdAttributes.size(); ++a) { + DtdAttribute &dtdAttribute = dtdAttributes[a]; + if (!dtdAttribute.isNamespaceAttribute + || dtdAttribute.defaultValue.isNull() + || dtdAttribute.tagName != qualifiedName + || dtdAttribute.attributeQualifiedName.isNull()) + continue; + int i = 0; + while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName) + ++i; + if (i != n) + continue; + if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName == QLatin1String("xmlns")) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + namespaceDeclaration.prefix.clear(); + + const QStringRef ns(dtdAttribute.defaultValue); + if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || + ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + else + namespaceDeclaration.namespaceUri = ns; + } else if (dtdAttribute.attributePrefix == QLatin1String("xmlns")) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + QStringRef namespacePrefix = dtdAttribute.attributeName; + QStringRef namespaceUri = dtdAttribute.defaultValue; + if (((namespacePrefix == QLatin1String("xml")) + ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))) + || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") + || namespaceUri.isEmpty() + || namespacePrefix == QLatin1String("xmlns")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + + namespaceDeclaration.prefix = namespacePrefix; + namespaceDeclaration.namespaceUri = namespaceUri; + } + } + } + + tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix); + + attributes.resize(n); + + for (int i = 0; i < n; ++i) { + QXmlStreamAttribute &attribute = attributes[i]; + Attribute &attrib = attributeStack[i]; + QStringRef prefix(symPrefix(attrib.key)); + QStringRef name(symString(attrib.key)); + QStringRef qualifiedName(symName(attrib.key)); + QStringRef value(symString(attrib.value)); + + attribute.m_name = QXmlStreamStringRef(name); + attribute.m_qualifiedName = QXmlStreamStringRef(qualifiedName); + attribute.m_value = QXmlStreamStringRef(value); + + if (!prefix.isEmpty()) { + QStringRef attributeNamespaceUri = namespaceForPrefix(prefix); + attribute.m_namespaceUri = QXmlStreamStringRef(attributeNamespaceUri); + } + + for (int j = 0; j < i; ++j) { + if (attributes[j].name() == attribute.name() + && attributes[j].namespaceUri() == attribute.namespaceUri() + && (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName())) + raiseWellFormedError(QXmlStream::tr("Attribute redefined.")); + } + } + + for (int a = 0; a < dtdAttributes.size(); ++a) { + DtdAttribute &dtdAttribute = dtdAttributes[a]; + if (dtdAttribute.isNamespaceAttribute + || dtdAttribute.defaultValue.isNull() + || dtdAttribute.tagName != qualifiedName + || dtdAttribute.attributeQualifiedName.isNull()) + continue; + int i = 0; + while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName) + ++i; + if (i != n) + continue; + + + + QXmlStreamAttribute attribute; + attribute.m_name = QXmlStreamStringRef(dtdAttribute.attributeName); + attribute.m_qualifiedName = QXmlStreamStringRef(dtdAttribute.attributeQualifiedName); + attribute.m_value = QXmlStreamStringRef(dtdAttribute.defaultValue); + + if (!dtdAttribute.attributePrefix.isEmpty()) { + QStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix); + attribute.m_namespaceUri = QXmlStreamStringRef(attributeNamespaceUri); + } + attribute.m_isDefault = true; + attributes.append(attribute); + } + + attributeStack.clear(); +} + +void QXmlStreamReaderPrivate::resolvePublicNamespaces() +{ + const Tag &tag = tagStack.top(); + int n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize; + publicNamespaceDeclarations.resize(n); + for (int i = 0; i < n; ++i) { + const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i); + QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i]; + publicNamespaceDeclaration.m_prefix = QXmlStreamStringRef(namespaceDeclaration.prefix); + publicNamespaceDeclaration.m_namespaceUri = QXmlStreamStringRef(namespaceDeclaration.namespaceUri); + } +} + +void QXmlStreamReaderPrivate::resolveDtd() +{ + publicNotationDeclarations.resize(notationDeclarations.size()); + for (int i = 0; i < notationDeclarations.size(); ++i) { + const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i); + QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i]; + publicNotationDeclaration.m_name = QXmlStreamStringRef(notationDeclaration.name); + publicNotationDeclaration.m_systemId = QXmlStreamStringRef(notationDeclaration.systemId); + publicNotationDeclaration.m_publicId = QXmlStreamStringRef(notationDeclaration.publicId); + + } + notationDeclarations.clear(); + publicEntityDeclarations.resize(entityDeclarations.size()); + for (int i = 0; i < entityDeclarations.size(); ++i) { + const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i); + QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i]; + publicEntityDeclaration.m_name = QXmlStreamStringRef(entityDeclaration.name); + publicEntityDeclaration.m_notationName = QXmlStreamStringRef(entityDeclaration.notationName); + publicEntityDeclaration.m_systemId = QXmlStreamStringRef(entityDeclaration.systemId); + publicEntityDeclaration.m_publicId = QXmlStreamStringRef(entityDeclaration.publicId); + publicEntityDeclaration.m_value = QXmlStreamStringRef(entityDeclaration.value); + } + entityDeclarations.clear(); + parameterEntityHash.clear(); +} + +uint QXmlStreamReaderPrivate::resolveCharRef(int symbolIndex) +{ + bool ok = true; + uint s; + // ### add toXShort to QStringRef? + if (sym(symbolIndex).c == 'x') + s = symString(symbolIndex, 1).toString().toUInt(&ok, 16); + else + s = symString(symbolIndex).toString().toUInt(&ok, 10); + + ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff) + || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= 0x10ffff)); + + return ok ? s : 0; +} + + +void QXmlStreamReaderPrivate::checkPublicLiteral(const QStringRef &publicId) +{ +//#x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + + const ushort *data = reinterpret_cast<const ushort *>(publicId.constData()); + uchar c = 0; + int i; + for (i = publicId.size() - 1; i >= 0; --i) { + if (data[i] < 256) + switch ((c = data[i])) { + case ' ': case '\n': case '\r': case '-': case '(': case ')': + case '+': case ',': case '.': case '/': case ':': case '=': + case '?': case ';': case '!': case '*': case '#': case '@': + case '$': case '_': case '%': case '\'': case '\"': + continue; + default: + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9')) + continue; + } + break; + } + if (i >= 0) + raiseWellFormedError(QXmlStream::tr("Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c)))); +} + +/* + Checks whether the document starts with an xml declaration. If it + does, this function returns true; otherwise it sets up everything + for a synthetic start document event and returns false. + */ +bool QXmlStreamReaderPrivate::checkStartDocument() +{ + hasCheckedStartDocument = true; + + if (scanString(spell[XML], XML)) + return true; + + type = QXmlStreamReader::StartDocument; + if (atEnd) { + hasCheckedStartDocument = false; + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); + } + return false; +} + +void QXmlStreamReaderPrivate::startDocument() +{ + QString err; + if (documentVersion != QLatin1String("1.0")) { + if (documentVersion.toString().contains(QLatin1Char(' '))) + err = QXmlStream::tr("Invalid XML version string."); + else + err = QXmlStream::tr("Unsupported XML version."); + } + int n = attributeStack.size(); + + /* We use this bool to ensure that the pesudo attributes are in the + * proper order: + * + * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */ + bool hasStandalone = false; + + for (int i = 0; err.isNull() && i < n; ++i) { + Attribute &attrib = attributeStack[i]; + QStringRef prefix(symPrefix(attrib.key)); + QStringRef key(symString(attrib.key)); + QStringRef value(symString(attrib.value)); + + if (prefix.isEmpty() && key == QLatin1String("encoding")) { + const QString name(value.toString()); + documentEncoding = value; + + if(hasStandalone) + err = QXmlStream::tr("The standalone pseudo attribute must appear after the encoding."); + if(!QXmlUtils::isEncName(name)) + err = QXmlStream::tr("%1 is an invalid encoding name.").arg(name); + else { +#ifdef QT_NO_TEXTCODEC + readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread); +#else + QTextCodec *const newCodec = QTextCodec::codecForName(name.toLatin1()); + if (!newCodec) + err = QXmlStream::tr("Encoding %1 is unsupported").arg(name); + else if (newCodec != codec && !lockEncoding) { + codec = newCodec; + delete decoder; + decoder = codec->makeDecoder(); + decoder->toUnicode(&readBuffer, rawReadBuffer.data(), nbytesread); + } +#endif // QT_NO_TEXTCODEC + } + } else if (prefix.isEmpty() && key == QLatin1String("standalone")) { + hasStandalone = true; + if (value == QLatin1String("yes")) + standalone = true; + else if (value == QLatin1String("no")) + standalone = false; + else + err = QXmlStream::tr("Standalone accepts only yes or no."); + } else { + err = QXmlStream::tr("Invalid attribute in XML declaration."); + } + } + + if (!err.isNull()) + raiseWellFormedError(err); + attributeStack.clear(); +} + + +void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error, const QString& message) +{ + this->error = error; + errorString = message; + if (errorString.isNull()) { + if (error == QXmlStreamReader::PrematureEndOfDocumentError) + errorString = QXmlStream::tr("Premature end of document."); + else if (error == QXmlStreamReader::CustomError) + errorString = QXmlStream::tr("Invalid document."); + } + + type = QXmlStreamReader::Invalid; +} + +void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) +{ + raiseError(QXmlStreamReader::NotWellFormedError, message); +} + +void QXmlStreamReaderPrivate::parseError() +{ + + if (token == EOF_SYMBOL) { + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); + return; + } + const int nmax = 4; + QString error_message; + int ers = state_stack[tos]; + int nexpected = 0; + int expected[nmax]; + if (token != ERROR) + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) { + int k = t_action(ers, tk); + if (k <= 0) + continue; + if (spell[tk]) { + if (nexpected < nmax) + expected[nexpected++] = tk; + } + } + + error_message.clear (); + if (nexpected && nexpected < nmax) { + bool first = true; + + for (int s = 0; s < nexpected; ++s) { + if (first) + error_message += QXmlStream::tr ("Expected "); + else if (s == nexpected - 1) + error_message += QLatin1String (nexpected > 2 ? ", or " : " or "); + else + error_message += QLatin1String (", "); + + first = false; + error_message += QLatin1String("\'"); + error_message += QLatin1String (spell [expected[s]]); + error_message += QLatin1String("\'"); + } + error_message += QXmlStream::tr(", but got \'"); + error_message += QLatin1String(spell [token]); + error_message += QLatin1String("\'"); + } else { + error_message += QXmlStream::tr("Unexpected \'"); + error_message += QLatin1String(spell [token]); + error_message += QLatin1String("\'"); + } + error_message += QLatin1Char('.'); + + raiseWellFormedError(error_message); +} + +void QXmlStreamReaderPrivate::resume(int rule) { + resumeReduction = rule; + if (error == QXmlStreamReader::NoError) + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); +} + +/*! Returns the current line number, starting with 1. + +\sa columnNumber(), characterOffset() + */ +qint64 QXmlStreamReader::lineNumber() const +{ + Q_D(const QXmlStreamReader); + return d->lineNumber + 1; // in public we start with 1 +} + +/*! Returns the current column number, starting with 0. + +\sa lineNumber(), characterOffset() + */ +qint64 QXmlStreamReader::columnNumber() const +{ + Q_D(const QXmlStreamReader); + return d->characterOffset - d->lastLineStart + d->readBufferPos; +} + +/*! Returns the current character offset, starting with 0. + +\sa lineNumber(), columnNumber() +*/ +qint64 QXmlStreamReader::characterOffset() const +{ + Q_D(const QXmlStreamReader); + return d->characterOffset + d->readBufferPos; +} + + +/*! Returns the text of \l Characters, \l Comment, \l DTD, or + EntityReference. + */ +QStringRef QXmlStreamReader::text() const +{ + Q_D(const QXmlStreamReader); + return d->text; +} + + +/*! If the state() is \l DTD, this function returns the DTD's + notation declarations. Otherwise an empty vector is returned. + + The QXmlStreamNotationDeclarations class is defined to be a QVector + of QXmlStreamNotationDeclaration. + */ +QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations() const +{ + Q_D(const QXmlStreamReader); + if (d->notationDeclarations.size()) + const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd(); + return d->publicNotationDeclarations; +} + + +/*! If the state() is \l DTD, this function returns the DTD's + unparsed (external) entity declarations. Otherwise an empty vector is returned. + + The QXmlStreamEntityDeclarations class is defined to be a QVector + of QXmlStreamEntityDeclaration. + */ +QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations() const +{ + Q_D(const QXmlStreamReader); + if (d->entityDeclarations.size()) + const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd(); + return d->publicEntityDeclarations; +} + +/*! + \since 4.4 + + If the state() is \l DTD, this function returns the DTD's + name. Otherwise an empty string is returned. + + */ +QStringRef QXmlStreamReader::dtdName() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::DTD) + return d->dtdName; + return QStringRef(); +} + +/*! + \since 4.4 + + If the state() is \l DTD, this function returns the DTD's + public identifier. Otherwise an empty string is returned. + + */ +QStringRef QXmlStreamReader::dtdPublicId() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::DTD) + return d->dtdPublicId; + return QStringRef(); +} + +/*! + \since 4.4 + + If the state() is \l DTD, this function returns the DTD's + system identifier. Otherwise an empty string is returned. + + */ +QStringRef QXmlStreamReader::dtdSystemId() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::DTD) + return d->dtdSystemId; + return QStringRef(); +} + +/*! If the state() is \l StartElement, this function returns the + element's namespace declarations. Otherwise an empty vector is + returned. + + The QXmlStreamNamespaceDeclaration class is defined to be a QVector + of QXmlStreamNamespaceDeclaration. + + \sa addExtraNamespaceDeclaration(), addExtraNamespaceDeclarations() + */ +QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations() const +{ + Q_D(const QXmlStreamReader); + if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement) + const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces(); + return d->publicNamespaceDeclarations; +} + + +/*! + \since 4.4 + + Adds an \a extraNamespaceDeclaration. The declaration will be + valid for children of the current element, or - should the function + be called before any elements are read - for the entire XML + document. + + \sa namespaceDeclarations(), addExtraNamespaceDeclarations(), setNamespaceProcessing() + */ +void QXmlStreamReader::addExtraNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration) +{ + Q_D(QXmlStreamReader); + QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push(); + namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix()); + namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri()); +} + +/*! + \since 4.4 + + Adds a vector of declarations specified by \a extraNamespaceDeclarations. + + \sa namespaceDeclarations(), addExtraNamespaceDeclaration() + */ +void QXmlStreamReader::addExtraNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations) +{ + for (int i = 0; i < extraNamespaceDeclarations.size(); ++i) + addExtraNamespaceDeclaration(extraNamespaceDeclarations.at(i)); +} + + +/*! Convenience function to be called in case a StartElement was + read. Reads until the corresponding EndElement and returns all text + in-between. In case of no error, the current token (see tokenType()) + after having called this function is EndElement. + + The function concatenates text() when it reads either \l Characters + or EntityReference tokens, but skips ProcessingInstruction and \l + Comment. In case anything else is read before reaching EndElement, + the function returns what it read so far and raises an + UnexpectedElementError. If the current token is not StartElement, an + empty string is returned. + */ +QString QXmlStreamReader::readElementText() +{ + Q_D(QXmlStreamReader); + if (isStartElement()) { + QString result; + forever { + switch (readNext()) { + case Characters: + case EntityReference: + result.insert(result.size(), d->text.unicode(), d->text.size()); + break; + case EndElement: + return result; + case ProcessingInstruction: + case Comment: + break; + default: + if (!d->error) + d->raiseError(UnexpectedElementError, QXmlStream::tr("Expected character data.")); + return result; + } + } + } + return QString(); +} + +/*! Raises a custom error with an optional error \a message. + + \sa error(), errorString() + */ +void QXmlStreamReader::raiseError(const QString& message) +{ + Q_D(QXmlStreamReader); + d->raiseError(CustomError, message); +} + +/*! + Returns the error message that was set with raiseError(). + + \sa error(), lineNumber(), columnNumber(), characterOffset() + */ +QString QXmlStreamReader::errorString() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::Invalid) + return d->errorString; + return QString(); +} + +/*! Returns the type of the current error, or NoError if no error occurred. + + \sa errorString(), raiseError() + */ +QXmlStreamReader::Error QXmlStreamReader::error() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::Invalid) + return d->error; + return NoError; +} + +/*! + Returns the target of a ProcessingInstruction. + */ +QStringRef QXmlStreamReader::processingInstructionTarget() const +{ + Q_D(const QXmlStreamReader); + return d->processingInstructionTarget; +} + +/*! + Returns the data of a ProcessingInstruction. + */ +QStringRef QXmlStreamReader::processingInstructionData() const +{ + Q_D(const QXmlStreamReader); + return d->processingInstructionData; +} + + + +/*! + Returns the local name of a StartElement, EndElement, or an EntityReference. + + \sa namespaceUri(), qualifiedName() + */ +QStringRef QXmlStreamReader::name() const +{ + Q_D(const QXmlStreamReader); + return d->name; +} + +/*! + Returns the namespaceUri of a StartElement or EndElement. + + \sa name(), qualifiedName() + */ +QStringRef QXmlStreamReader::namespaceUri() const +{ + Q_D(const QXmlStreamReader); + return d->namespaceUri; +} + +/*! + Returns the qualified name of a StartElement or EndElement; + + A qualified name is the raw name of an element in the XML data. It + consists of the namespace prefix, followed by colon, followed by the + element's local name. Since the namespace prefix is not unique (the + same prefix can point to different namespaces and different prefixes + can point to the same namespace), you shouldn't use qualifiedName(), + but the resolved namespaceUri() and the attribute's local name(). + + \sa name(), prefix(), namespaceUri() + */ +QStringRef QXmlStreamReader::qualifiedName() const +{ + Q_D(const QXmlStreamReader); + return d->qualifiedName; +} + + + +/*! + \since 4.4 + + Returns the prefix of a StartElement or EndElement. + + \sa name(), qualifiedName() +*/ +QStringRef QXmlStreamReader::prefix() const +{ + Q_D(const QXmlStreamReader); + return d->prefix; +} + +/*! + Returns the attributes of a StartElement. + */ +QXmlStreamAttributes QXmlStreamReader::attributes() const +{ + Q_D(const QXmlStreamReader); + return d->attributes; +} + +#endif // QT_NO_XMLSTREAMREADER + +/*! + \class QXmlStreamAttribute + \since 4.3 + \reentrant + \brief The QXmlStreamAttribute class represents a single XML attribute + + \ingroup xml-tools + + An attribute consists of an optionally empty namespaceUri(), a + name(), a value(), and an isDefault() attribute. + + The raw XML attribute name is returned as qualifiedName(). +*/ + +/*! + Creates an empty attribute. + */ +QXmlStreamAttribute::QXmlStreamAttribute() +{ + m_isDefault = false; +} + +/*! + Destructs an attribute. + */ +QXmlStreamAttribute::~QXmlStreamAttribute() +{ +} + +/*! Constructs an attribute in the namespace described with \a + namespaceUri with \a name and value \a value. + */ +QXmlStreamAttribute::QXmlStreamAttribute(const QString &namespaceUri, const QString &name, const QString &value) +{ + m_namespaceUri = QXmlStreamStringRef(QStringRef(&namespaceUri)); + m_name = m_qualifiedName = QXmlStreamStringRef(QStringRef(&name)); + m_value = QXmlStreamStringRef(QStringRef(&value)); + m_namespaceUri = QXmlStreamStringRef(QStringRef(&namespaceUri)); +} + +/*! + Constructs an attribute with qualified name \a qualifiedName and value \a value. + */ +QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QString &value) +{ + int colon = qualifiedName.indexOf(QLatin1Char(':')); + m_name = QXmlStreamStringRef(QStringRef(&qualifiedName, + colon + 1, + qualifiedName.size() - (colon + 1))); + m_qualifiedName = QXmlStreamStringRef(QStringRef(&qualifiedName)); + m_value = QXmlStreamStringRef(QStringRef(&value)); +} + +/*! \fn QStringRef QXmlStreamAttribute::namespaceUri() const + + Returns the attribute's resolved namespaceUri, or an empty string + reference if the attribute does not have a defined namespace. + */ +/*! \fn QStringRef QXmlStreamAttribute::name() const + Returns the attribute's local name. + */ +/*! \fn QStringRef QXmlStreamAttribute::qualifiedName() const + Returns the attribute's qualified name. + + A qualified name is the raw name of an attribute in the XML + data. It consists of the namespace prefix(), followed by colon, + followed by the attribute's local name(). Since the namespace prefix + is not unique (the same prefix can point to different namespaces + and different prefixes can point to the same namespace), you + shouldn't use qualifiedName(), but the resolved namespaceUri() and + the attribute's local name(). + */ +/*! + \fn QStringRef QXmlStreamAttribute::prefix() const + \since 4.4 + Returns the attribute's namespace prefix. + + \sa name(), qualifiedName() + +*/ + +/*! \fn QStringRef QXmlStreamAttribute::value() const + Returns the attribute's value. + */ + +/*! \fn bool QXmlStreamAttribute::isDefault() const + + Returns true if the parser added this attribute with a default + value following an ATTLIST declaration in the DTD; otherwise + returns false. +*/ +/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &other) const + + Compares this attribute with \a other and returns true if they are + equal; otherwise returns false. + */ +/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &other) const + + Compares this attribute with \a other and returns true if they are + not equal; otherwise returns false. + */ + + +/*! + Creates a copy of \a other. + */ +QXmlStreamAttribute::QXmlStreamAttribute(const QXmlStreamAttribute &other) +{ + *this = other; +} + +/*! + Assigns \a other to this attribute. + */ +QXmlStreamAttribute& QXmlStreamAttribute::operator=(const QXmlStreamAttribute &other) +{ + m_name = other.m_name; + m_namespaceUri = other.m_namespaceUri; + m_qualifiedName = other.m_qualifiedName; + m_value = other.m_value; + m_isDefault = other.m_isDefault; + return *this; +} + + +/*! + \class QXmlStreamAttributes + \since 4.3 + \reentrant + \brief The QXmlStreamAttributes class represents a vector of QXmlStreamAttribute. + + Attributes are returned by a QXmlStreamReader in + \l{QXmlStreamReader::attributes()} {attributes()} when the reader + reports a \l {QXmlStreamReader::StartElement}{start element}. The + class can also be used with a QXmlStreamWriter as an argument to + \l {QXmlStreamWriter::writeAttributes()}{writeAttributes()}. + + The convenience function value() loops over the vector and returns + an attribute value for a given namespaceUri and an attribute's + name. + + New attributes can be added with append(). + + \ingroup xml-tools +*/ + +/*! + \fn void QXmlStreamAttributes::append(const QXmlStreamAttribute &attribute) + + Appends the given \a attribute to the end of the vector. + + \sa QVector::append() +*/ + + +/*! + \typedef QXmlStreamNotationDeclarations + \relates QXmlStreamNotationDeclaration + + Synonym for QVector<QXmlStreamNotationDeclaration>. +*/ + + +/*! + \class QXmlStreamNotationDeclaration + \since 4.3 + \reentrant + \brief The QXmlStreamNotationDeclaration class represents a DTD notation declaration. + + \ingroup xml-tools + + An notation declaration consists of a name(), a systemId(), and a publicId(). +*/ + +/*! + Creates an empty notation declaration. +*/ +QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration() +{ +} +/*! + Creates a copy of \a other. + */ +QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration(const QXmlStreamNotationDeclaration &other) +{ + *this = other; +} + +/*! + Assigns \a other to this notation declaration. + */ +QXmlStreamNotationDeclaration& QXmlStreamNotationDeclaration::operator=(const QXmlStreamNotationDeclaration &other) +{ + m_name = other.m_name; + m_systemId = other.m_systemId; + m_publicId = other.m_publicId; + return *this; +} + +/*! +Destructs this notation declaration. +*/ +QXmlStreamNotationDeclaration::~QXmlStreamNotationDeclaration() +{ +} + +/*! \fn QStringRef QXmlStreamNotationDeclaration::name() const + +Returns the notation name. +*/ +/*! \fn QStringRef QXmlStreamNotationDeclaration::systemId() const + +Returns the system identifier. +*/ +/*! \fn QStringRef QXmlStreamNotationDeclaration::publicId() const + +Returns the public identifier. +*/ + +/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &other) const + + Compares this notation declaration with \a other and returns true + if they are equal; otherwise returns false. + */ +/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &other) const + + Compares this notation declaration with \a other and returns true + if they are not equal; otherwise returns false. + */ + +/*! + \typedef QXmlStreamNamespaceDeclarations + \relates QXmlStreamNamespaceDeclaration + + Synonym for QVector<QXmlStreamNamespaceDeclaration>. +*/ + +/*! + \class QXmlStreamNamespaceDeclaration + \since 4.3 + \reentrant + \brief The QXmlStreamNamespaceDeclaration class represents a namespace declaration. + + \ingroup xml-tools + + An namespace declaration consists of a prefix() and a namespaceUri(). +*/ +/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &other) const + + Compares this namespace declaration with \a other and returns true + if they are equal; otherwise returns false. + */ +/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &other) const + + Compares this namespace declaration with \a other and returns true + if they are not equal; otherwise returns false. + */ + +/*! + Creates an empty namespace declaration. +*/ +QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration() +{ +} + +/*! + \since 4.4 + + Creates a namespace declaration with \a prefix and \a namespaceUri. +*/ +QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(const QString &prefix, const QString &namespaceUri) +{ + m_prefix = prefix; + m_namespaceUri = namespaceUri; +} + +/*! + Creates a copy of \a other. + */ +QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &other) +{ + *this = other; +} + +/*! + Assigns \a other to this namespace declaration. + */ +QXmlStreamNamespaceDeclaration& QXmlStreamNamespaceDeclaration::operator=(const QXmlStreamNamespaceDeclaration &other) +{ + m_prefix = other.m_prefix; + m_namespaceUri = other.m_namespaceUri; + return *this; +} +/*! +Destructs this namespace declaration. +*/ +QXmlStreamNamespaceDeclaration::~QXmlStreamNamespaceDeclaration() +{ +} + +/*! \fn QStringRef QXmlStreamNamespaceDeclaration::prefix() const + +Returns the prefix. +*/ +/*! \fn QStringRef QXmlStreamNamespaceDeclaration::namespaceUri() const + +Returns the namespaceUri. +*/ + + + + +/*! + \typedef QXmlStreamEntityDeclarations + \relates QXmlStreamEntityDeclaration + + Synonym for QVector<QXmlStreamEntityDeclaration>. +*/ + +/*! + \class QXmlStreamStringRef + \since 4.3 + \internal +*/ + +/*! + \class QXmlStreamEntityDeclaration + \since 4.3 + \reentrant + \brief The QXmlStreamEntityDeclaration class represents a DTD entity declaration. + + \ingroup xml-tools + + An entity declaration consists of a name(), a notationName(), a + systemId(), a publicId(), and a value(). +*/ + +/*! + Creates an empty entity declaration. +*/ +QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration() +{ +} + +/*! + Creates a copy of \a other. + */ +QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration(const QXmlStreamEntityDeclaration &other) +{ + *this = other; +} + +/*! + Assigns \a other to this entity declaration. + */ +QXmlStreamEntityDeclaration& QXmlStreamEntityDeclaration::operator=(const QXmlStreamEntityDeclaration &other) +{ + m_name = other.m_name; + m_notationName = other.m_notationName; + m_systemId = other.m_systemId; + m_publicId = other.m_publicId; + m_value = other.m_value; + return *this; +} + +/*! + Destructs this entity declaration. +*/ +QXmlStreamEntityDeclaration::~QXmlStreamEntityDeclaration() +{ +} + +/*! \fn QStringRef QXmlStreamEntityDeclaration::name() const + +Returns the entity name. +*/ +/*! \fn QStringRef QXmlStreamEntityDeclaration::notationName() const + +Returns the notation name. +*/ +/*! \fn QStringRef QXmlStreamEntityDeclaration::systemId() const + +Returns the system identifier. +*/ +/*! \fn QStringRef QXmlStreamEntityDeclaration::publicId() const + +Returns the public identifier. +*/ +/*! \fn QStringRef QXmlStreamEntityDeclaration::value() const + +Returns the entity's value. +*/ + +/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &other) const + + Compares this entity declaration with \a other and returns true if + they are equal; otherwise returns false. + */ +/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &other) const + + Compares this entity declaration with \a other and returns true if + they are not equal; otherwise returns false. + */ + +/*! Returns the value of the attribute \a name in the namespace + described with \a namespaceUri, or an empty string reference if the + attribute is not defined. The \a namespaceUri can be empty. + */ +QStringRef QXmlStreamAttributes::value(const QString &namespaceUri, const QString &name) const +{ + for (int i = 0; i < size(); ++i) { + const QXmlStreamAttribute &attribute = at(i); + if (attribute.name() == name && attribute.namespaceUri() == namespaceUri) + return attribute.value(); + } + return QStringRef(); +} + +/*!\overload + Returns the value of the attribute \a name in the namespace + described with \a namespaceUri, or an empty string reference if the + attribute is not defined. The \a namespaceUri can be empty. + */ +QStringRef QXmlStreamAttributes::value(const QString &namespaceUri, const QLatin1String &name) const +{ + for (int i = 0; i < size(); ++i) { + const QXmlStreamAttribute &attribute = at(i); + if (attribute.name() == name && attribute.namespaceUri() == namespaceUri) + return attribute.value(); + } + return QStringRef(); +} + +/*!\overload + Returns the value of the attribute \a name in the namespace + described with \a namespaceUri, or an empty string reference if the + attribute is not defined. The \a namespaceUri can be empty. + */ +QStringRef QXmlStreamAttributes::value(const QLatin1String &namespaceUri, const QLatin1String &name) const +{ + for (int i = 0; i < size(); ++i) { + const QXmlStreamAttribute &attribute = at(i); + if (attribute.name() == name && attribute.namespaceUri() == namespaceUri) + return attribute.value(); + } + return QStringRef(); +} + +/*!\overload + + Returns the value of the attribute with qualified name \a + qualifiedName , or an empty string reference if the attribute is not + defined. A qualified name is the raw name of an attribute in the XML + data. It consists of the namespace prefix, followed by colon, + followed by the attribute's local name. Since the namespace prefix + is not unique (the same prefix can point to different namespaces and + different prefixes can point to the same namespace), you shouldn't + use qualified names, but a resolved namespaceUri and the attribute's + local name. + */ +QStringRef QXmlStreamAttributes::value(const QString &qualifiedName) const +{ + for (int i = 0; i < size(); ++i) { + const QXmlStreamAttribute &attribute = at(i); + if (attribute.qualifiedName() == qualifiedName) + return attribute.value(); + } + return QStringRef(); +} + +/*!\overload + + Returns the value of the attribute with qualified name \a + qualifiedName , or an empty string reference if the attribute is not + defined. A qualified name is the raw name of an attribute in the XML + data. It consists of the namespace prefix, followed by colon, + followed by the attribute's local name. Since the namespace prefix + is not unique (the same prefix can point to different namespaces and + different prefixes can point to the same namespace), you shouldn't + use qualified names, but a resolved namespaceUri and the attribute's + local name. + */ +QStringRef QXmlStreamAttributes::value(const QLatin1String &qualifiedName) const +{ + for (int i = 0; i < size(); ++i) { + const QXmlStreamAttribute &attribute = at(i); + if (attribute.qualifiedName() == qualifiedName) + return attribute.value(); + } + return QStringRef(); +} + +/*!Appends a new attribute with \a name in the namespace + described with \a namespaceUri, and value \a value. The \a + namespaceUri can be empty. + */ +void QXmlStreamAttributes::append(const QString &namespaceUri, const QString &name, const QString &value) +{ + append(QXmlStreamAttribute(namespaceUri, name, value)); +} + +/*!\overload + Appends a new attribute with qualified name \a qualifiedName and + value \a value. + */ +void QXmlStreamAttributes::append(const QString &qualifiedName, const QString &value) +{ + append(QXmlStreamAttribute(qualifiedName, value)); +} + +#ifndef QT_NO_XMLSTREAMREADER + +/*! \fn bool QXmlStreamReader::isStartDocument() const + Returns true if tokenType() equals \l StartDocument; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isEndDocument() const + Returns true if tokenType() equals \l EndDocument; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isStartElement() const + Returns true if tokenType() equals \l StartElement; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isEndElement() const + Returns true if tokenType() equals \l EndElement; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isCharacters() const + Returns true if tokenType() equals \l Characters; otherwise returns false. + + \sa isWhitespace(), isCDATA() +*/ +/*! \fn bool QXmlStreamReader::isComment() const + Returns true if tokenType() equals \l Comment; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isDTD() const + Returns true if tokenType() equals \l DTD; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isEntityReference() const + Returns true if tokenType() equals \l EntityReference; otherwise returns false. +*/ +/*! \fn bool QXmlStreamReader::isProcessingInstruction() const + Returns true if tokenType() equals \l ProcessingInstruction; otherwise returns false. +*/ + +/*! Returns true if the reader reports characters that only consist + of white-space; otherwise returns false. + + \sa isCharacters(), text() +*/ +bool QXmlStreamReader::isWhitespace() const +{ + Q_D(const QXmlStreamReader); + return d->type == QXmlStreamReader::Characters && d->isWhitespace; +} + +/*! Returns true if the reader reports characters that stem from a + CDATA section; otherwise returns false. + + \sa isCharacters(), text() +*/ +bool QXmlStreamReader::isCDATA() const +{ + Q_D(const QXmlStreamReader); + return d->type == QXmlStreamReader::Characters && d->isCDATA; +} + + + +/*! + Returns true if this document has been declared standalone in the + XML declaration; otherwise returns false. + + If no XML declaration has been parsed, this function returns false. + */ +bool QXmlStreamReader::isStandaloneDocument() const +{ + Q_D(const QXmlStreamReader); + return d->standalone; +} + + +/*! + \since 4.4 + + If the state() is \l StartDocument, this function returns the + version string as specified in the XML declaration. + Otherwise an empty string is returned. + */ +QStringRef QXmlStreamReader::documentVersion() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::StartDocument) + return d->documentVersion; + return QStringRef(); +} + +/*! + \since 4.4 + + If the state() is \l StartDocument, this function returns the + encoding string as specified in the XML declaration. + Otherwise an empty string is returned. + */ +QStringRef QXmlStreamReader::documentEncoding() const +{ + Q_D(const QXmlStreamReader); + if (d->type == QXmlStreamReader::StartDocument) + return d->documentEncoding; + return QStringRef(); +} + +#endif // QT_NO_XMLSTREAMREADER + +/*! + \class QXmlStreamWriter + \since 4.3 + \reentrant + + \brief The QXmlStreamWriter class provides an XML writer with a + simple streaming API. + + \mainclass + \inmodule QtXml + \ingroup xml-tools + + QXmlStreamWriter is the counterpart to QXmlStreamReader for writing + XML. Like its related class, it operates on a QIODevice specified + with setDevice(). The API is simple and straightforward: for every + XML token or event you want to write, the writer provides a + specialized function. + + You start a document with writeStartDocument() and end it with + writeEndDocument(). This will implicitly close all remaining open + tags. + + Element tags are opened with writeStartElement() followed by + writeAttribute() or writeAttributes(), element content, and then + writeEndElement(). A shorter form writeEmptyElement() can be used + to write empty elements, followed by writeAttributes(). + + Element content consists of either characters, entity references or + nested elements. It is written with writeCharacters(), which also + takes care of escaping all forbidden characters and character + sequences, writeEntityReference(), or subsequent calls to + writeStartElement(). A convenience method writeTextElement() can be + used for writing terminal elements that contain nothing but text. + + The following abridged code snippet shows the basic use of the class + to write formatted XML with indentation: + + \snippet doc/src/snippets/qxmlstreamwriter/main.cpp start stream + \dots + \snippet doc/src/snippets/qxmlstreamwriter/main.cpp write element + \dots + \snippet doc/src/snippets/qxmlstreamwriter/main.cpp finish stream + + QXmlStreamWriter takes care of prefixing namespaces, all you have to + do is specify the \c namespaceUri when writing elements or + attributes. If you must conform to certain prefixes, you can force + the writer to use them by declaring the namespaces manually with + either writeNamespace() or writeDefaultNamespace(). Alternatively, + you can bypass the stream writer's namespace support and use + overloaded methods that take a qualified name instead. The namespace + \e http://www.w3.org/XML/1998/namespace is implicit and mapped to the + prefix \e xml. + + The stream writer can automatically format the generated XML data by + adding line-breaks and indentation to empty sections between + elements, making the XML data more readable for humans and easier to + work with for most source code management systems. The feature can + be turned on with the \l autoFormatting property, and customized + with the \l autoFormattingIndent property. + + Other functions are writeCDATA(), writeComment(), + writeProcessingInstruction(), and writeDTD(). Chaining of XML + streams is supported with writeCurrentToken(). + + By default, QXmlStreamWriter encodes XML in UTF-8. Different + encodings can be enforced using setCodec(). + + The \l{QXmlStream Bookmarks Example} illustrates how to use a + subclassed stream writer to write an XML bookmark file (XBEL) that + was previously read in by a QXmlStreamReader. + +*/ + +#ifndef QT_NO_XMLSTREAMWRITER + +class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack { + QXmlStreamWriter *q_ptr; + Q_DECLARE_PUBLIC(QXmlStreamWriter) +public: + QXmlStreamWriterPrivate(QXmlStreamWriter *q); + ~QXmlStreamWriterPrivate() { + if (deleteDevice) + delete device; +#ifndef QT_NO_TEXTCODEC + delete encoder; +#endif + } + + void write(const QStringRef &); + void write(const QString &); + void writeEscaped(const QString &, bool escapeWhitespace = false); + void write(const char *s); + bool finishStartElement(bool contents = true); + void writeStartElement(const QString &namespaceUri, const QString &name); + QIODevice *device; + QString *stringDevice; + uint deleteDevice :1; + uint inStartElement :1; + uint inEmptyElement :1; + uint lastWasStartElement :1; + uint wroteSomething :1; + uint autoFormatting :1; + QByteArray autoFormattingIndent; + NamespaceDeclaration emptyNamespace; + int lastNamespaceDeclaration; + +#ifndef QT_NO_TEXTCODEC + QTextCodec *codec; + QTextEncoder *encoder; +#endif + + NamespaceDeclaration &findNamespace(const QString &namespaceUri, bool writeDeclaration = false, bool noDefault = false); + void writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration); + + int namespacePrefixCount; + + void indent(int level); +}; + + +QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) + :autoFormattingIndent(4, ' ') +{ + q_ptr = q; + device = 0; + stringDevice = 0; + deleteDevice = false; +#ifndef QT_NO_TEXTCODEC + codec = QTextCodec::codecForMib(106); // utf8 + encoder = codec->makeEncoder(); + encoder->fromUnicode(QLatin1String("")); // no byte order mark for utf8 +#endif + inStartElement = inEmptyElement = false; + wroteSomething = false; + lastWasStartElement = false; + lastNamespaceDeclaration = 1; + autoFormatting = false; + namespacePrefixCount = 0; +} + +void QXmlStreamWriterPrivate::write(const QStringRef &s) +{ + if (device) { +#ifdef QT_NO_TEXTCODEC + device->write(s.toString().toLatin1(), s.size()); +#else + device->write(encoder->fromUnicode(s.constData(), s.size())); +#endif + } + else if (stringDevice) + s.appendTo(stringDevice); + else + qWarning("QXmlStreamWriter: No device"); +} + +void QXmlStreamWriterPrivate::write(const QString &s) +{ + if (device) { +#ifdef QT_NO_TEXTCODEC + device->write(s.toLatin1(), s.size()); +#else + device->write(encoder->fromUnicode(s)); +#endif + } + else if (stringDevice) + stringDevice->append(s); + else + qWarning("QXmlStreamWriter: No device"); +} + +void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespace) +{ + QString escaped; + escaped.reserve(s.size()); + for ( int i = 0; i < s.size(); ++i ) { + QChar c = s.at(i); + if (c.unicode() == '<' ) + escaped.append(QLatin1String("<")); + else if (c.unicode() == '>' ) + escaped.append(QLatin1String(">")); + else if (c.unicode() == '&' ) + escaped.append(QLatin1String("&")); + else if (c.unicode() == '\"' ) + escaped.append(QLatin1String(""")); + else if (escapeWhitespace && c.isSpace()) { + if (c.unicode() == '\n') + escaped.append(QLatin1String(" ")); + else if (c.unicode() == '\r') + escaped.append(QLatin1String(" ")); + else if (c.unicode() == '\t') + escaped.append(QLatin1String("	")); + else + escaped += c; + } else { + escaped += QChar(c); + } + } + if (device) { +#ifdef QT_NO_TEXTCODEC + device->write(escaped.toLatin1(), escaped.size()); +#else + device->write(encoder->fromUnicode(escaped)); +#endif + } + else if (stringDevice) + stringDevice->append(escaped); + else + qWarning("QXmlStreamWriter: No device"); +} + + +void QXmlStreamWriterPrivate::write(const char *s) +{ + if (device) { +#ifndef QT_NO_TEXTCODEC + if (codec->mibEnum() != 106) + device->write(encoder->fromUnicode(QLatin1String(s))); + else +#endif + device->write(s, strlen(s)); + } else if (stringDevice) { + stringDevice->append(QLatin1String(s)); + } else + qWarning("QXmlStreamWriter: No device"); +} + +void QXmlStreamWriterPrivate::writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration) { + if (namespaceDeclaration.prefix.isEmpty()) { + write(" xmlns=\""); + write(namespaceDeclaration.namespaceUri); + write("\""); + } else { + write(" xmlns:"); + write(namespaceDeclaration.prefix); + write("=\""); + write(namespaceDeclaration.namespaceUri); + write("\""); + } +} + +bool QXmlStreamWriterPrivate::finishStartElement(bool contents) +{ + bool hadSomethingWritten = wroteSomething; + wroteSomething = contents; + if (!inStartElement) + return hadSomethingWritten; + + if (inEmptyElement) { + write("/>"); + QXmlStreamWriterPrivate::Tag &tag = tagStack_pop(); + lastNamespaceDeclaration = tag.namespaceDeclarationsSize; + lastWasStartElement = false; + } else { + write(">"); + } + inStartElement = inEmptyElement = false; + lastNamespaceDeclaration = namespaceDeclarations.size(); + return hadSomethingWritten; +} + +QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(const QString &namespaceUri, bool writeDeclaration, bool noDefault) +{ + for (int j = namespaceDeclarations.size() - 1; j >= 0; --j) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations[j]; + if (namespaceDeclaration.namespaceUri == namespaceUri) { + if (!noDefault || !namespaceDeclaration.prefix.isEmpty()) + return namespaceDeclaration; + } + } + if (namespaceUri.isEmpty()) + return emptyNamespace; + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + if (namespaceUri.isEmpty()) { + namespaceDeclaration.prefix.clear(); + } else { + QString s; + int n = ++namespacePrefixCount; + forever { + s = QLatin1String("n") + QString::number(n++); + int j = namespaceDeclarations.size() - 2; + while (j >= 0 && namespaceDeclarations.at(j).prefix != s) + --j; + if (j < 0) + break; + } + namespaceDeclaration.prefix = addToStringStorage(s); + } + namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); + if (writeDeclaration) + writeNamespaceDeclaration(namespaceDeclaration); + return namespaceDeclaration; +} + + + +void QXmlStreamWriterPrivate::indent(int level) +{ + write("\n"); + for (int i = level; i > 0; --i) + write(autoFormattingIndent.constData()); +} + + +/*! + Constructs a stream writer. + + \sa setDevice() + */ +QXmlStreamWriter::QXmlStreamWriter() + : d_ptr(new QXmlStreamWriterPrivate(this)) +{ +} + +/*! + Constructs a stream writer that writes into \a device; + */ +QXmlStreamWriter::QXmlStreamWriter(QIODevice *device) + : d_ptr(new QXmlStreamWriterPrivate(this)) +{ + Q_D(QXmlStreamWriter); + d->device = device; +} + +/*! Constructs a stream writer that writes into \a array. This is the + same as creating an xml writer that operates on a QBuffer device + which in turn operates on \a array. + */ +QXmlStreamWriter::QXmlStreamWriter(QByteArray *array) + : d_ptr(new QXmlStreamWriterPrivate(this)) +{ + Q_D(QXmlStreamWriter); + d->device = new QBuffer(array); + d->device->open(QIODevice::WriteOnly); + d->deleteDevice = true; +} + + +/*! Constructs a stream writer that writes into \a string. + */ +QXmlStreamWriter::QXmlStreamWriter(QString *string) + : d_ptr(new QXmlStreamWriterPrivate(this)) +{ + Q_D(QXmlStreamWriter); + d->stringDevice = string; +} + +/*! + Destructor. +*/ +QXmlStreamWriter::~QXmlStreamWriter() +{ + Q_D(QXmlStreamWriter); + delete d; +} + + +/*! + Sets the current device to \a device. If you want the stream to + write into a QByteArray, you can create a QBuffer device. + + \sa device() +*/ +void QXmlStreamWriter::setDevice(QIODevice *device) +{ + Q_D(QXmlStreamWriter); + if (device == d->device) + return; + d->stringDevice = 0; + if (d->deleteDevice) { + delete d->device; + d->deleteDevice = false; + } + d->device = device; +} + +/*! + Returns the current device associated with the QXmlStreamWriter, + or 0 if no device has been assigned. + + \sa setDevice() +*/ +QIODevice *QXmlStreamWriter::device() const +{ + Q_D(const QXmlStreamWriter); + return d->device; +} + + +#ifndef QT_NO_TEXTCODEC +/*! + Sets the codec for this stream to \a codec. The codec is used for + encoding any data that is written. By default, QXmlStreamWriter + uses UTF-8. + + The encoding information is stored in the initial xml tag which + gets written when you call writeStartDocument(). Call this + function before calling writeStartDocument(). + + \sa codec() +*/ +void QXmlStreamWriter::setCodec(QTextCodec *codec) +{ + Q_D(QXmlStreamWriter); + if (codec) { + d->codec = codec; + delete d->encoder; + d->encoder = codec->makeEncoder(); + if (codec->mibEnum() == 106) + d->encoder->fromUnicode(QLatin1String("")); // no byte order mark for utf8 + } +} + +/*! + Sets the codec for this stream to the QTextCodec for the encoding + specified by \a codecName. Common values for \c codecName include + "ISO 8859-1", "UTF-8", and "UTF-16". If the encoding isn't + recognized, nothing happens. + + \sa QTextCodec::codecForName() +*/ +void QXmlStreamWriter::setCodec(const char *codecName) +{ + setCodec(QTextCodec::codecForName(codecName)); +} + +/*! + Returns the codec that is currently assigned to the stream. + + \sa setCodec() +*/ +QTextCodec *QXmlStreamWriter::codec() const +{ + Q_D(const QXmlStreamWriter); + return d->codec; +} +#endif // QT_NO_TEXTCODEC + +/*! + \property QXmlStreamWriter::autoFormatting + \since 4.4 + the auto-formatting flag of the stream writer + + This property controls whether or not the stream writer + automatically formats the generated XML data. If enabled, the + writer automatically adds line-breaks and indentation to empty + sections between elements (ignorable whitespace). The main purpose + of auto-formatting is to split the data into several lines, and to + increase readability for a human reader. The indentation depth can + be controlled through the \l autoFormattingIndent property. + + By default, auto-formatting is disabled. +*/ + +/*! + \since 4.4 + + Enables auto formatting if \a enable is \c true, otherwise + disables it. + + The default value is \c false. + */ +void QXmlStreamWriter::setAutoFormatting(bool enable) +{ + Q_D(QXmlStreamWriter); + d->autoFormatting = enable; +} + +/*! + \since 4.4 + + Returns \c true if auto formattting is enabled, otherwise \c false. + */ +bool QXmlStreamWriter::autoFormatting() const +{ + Q_D(const QXmlStreamWriter); + return d->autoFormatting; +} + +/*! + \property QXmlStreamWriter::autoFormattingIndent + \since 4.4 + + \brief the number of spaces or tabs used for indentation when + auto-formatting is enabled. Positive numbers indicate spaces, + negative numbers tabs. + + The default indentation is 4. + + \sa autoFormatting +*/ + + +void QXmlStreamWriter::setAutoFormattingIndent(int spacesOrTabs) +{ + Q_D(QXmlStreamWriter); + d->autoFormattingIndent = QByteArray(qAbs(spacesOrTabs), spacesOrTabs >= 0 ? ' ' : '\t'); +} + +int QXmlStreamWriter::autoFormattingIndent() const +{ + Q_D(const QXmlStreamWriter); + return d->autoFormattingIndent.count(' ') - d->autoFormattingIndent.count('\t'); +} + + +/*! + \overload + Writes an attribute with \a qualifiedName and \a value. + + + This function can only be called after writeStartElement() before + any content is written, or after writeEmptyElement(). + */ +void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(d->inStartElement); + Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1); + d->write(" "); + d->write(qualifiedName); + d->write("=\""); + d->writeEscaped(value, true); + d->write("\""); +} + +/*! Writes an attribute with \a name and \a value, prefixed for + the specified \a namespaceUri. If the namespace has not been + declared yet, QXmlStreamWriter will generate a namespace declaration + for it. + + This function can only be called after writeStartElement() before + any content is written, or after writeEmptyElement(). + */ +void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(d->inStartElement); + Q_ASSERT(!name.contains(QLatin1Char(':'))); + QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri, true, true); + d->write(" "); + if (!namespaceDeclaration.prefix.isEmpty()) { + d->write(namespaceDeclaration.prefix); + d->write(":"); + } + d->write(name); + d->write("=\""); + d->writeEscaped(value, true); + d->write("\""); +} + +/*! + \overload + + Writes the \a attribute. + + This function can only be called after writeStartElement() before + any content is written, or after writeEmptyElement(). + */ +void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute& attribute) +{ + if (attribute.namespaceUri().isEmpty()) + writeAttribute(attribute.qualifiedName().toString(), + attribute.value().toString()); + else + writeAttribute(attribute.namespaceUri().toString(), + attribute.name().toString(), + attribute.value().toString()); +} + + +/*! Writes the attribute vector \a attributes. If a namespace + referenced in an attribute not been declared yet, QXmlStreamWriter + will generate a namespace declaration for it. + + This function can only be called after writeStartElement() before + any content is written, or after writeEmptyElement(). + + \sa writeAttribute(), writeNamespace() + */ +void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes& attributes) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(d->inStartElement); + Q_UNUSED(d); + for (int i = 0; i < attributes.size(); ++i) + writeAttribute(attributes.at(i)); +} + + +/*! Writes \a text as CDATA section. If \a text contains the + forbidden character sequence "]]>", it is split into different CDATA + sections. + + This function mainly exists for completeness. Normally you should + not need use it, because writeCharacters() automatically escapes all + non-content characters. + */ +void QXmlStreamWriter::writeCDATA(const QString &text) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(); + QString copy(text); + copy.replace(QLatin1String("]]>"), QLatin1String("]]]]><![CDATA[>")); + d->write("<![CDATA["); + d->write(copy); + d->write("]]>"); +} + + +/*! Writes \a text. The characters "<", "&", and "\"" are escaped as entity + references "<", "&, and """. To avoid the forbidden sequence + "]]>", ">" is also escaped as ">". + + \sa writeEntityReference() + */ +void QXmlStreamWriter::writeCharacters(const QString &text) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(); + d->writeEscaped(text); +} + + +/*! Writes \a text as XML comment, where \a text must not contain the + forbidden sequence "--" or end with "-". Note that XML does not + provide any way to escape "-" in a comment. + */ +void QXmlStreamWriter::writeComment(const QString &text) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(!text.contains(QLatin1String("--")) && !text.endsWith(QLatin1Char('-'))); + if (!d->finishStartElement() && d->autoFormatting) + d->indent(d->tagStack.size()); + d->write("<!--"); + d->write(text); + d->write("-->"); +} + + +/*! Writes a DTD section. The \a dtd represents the entire + doctypedecl production from the XML 1.0 specification. + */ +void QXmlStreamWriter::writeDTD(const QString &dtd) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(); + if (d->autoFormatting) + d->write("\n"); + d->write(dtd); + if (d->autoFormatting) + d->write("\n"); +} + + + +/*! \overload + Writes an empty element with qualified name \a qualifiedName. + Subsequent calls to writeAttribute() will add attributes to this element. +*/ +void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1); + d->writeStartElement(QString(), qualifiedName); + d->inEmptyElement = true; +} + + +/*! Writes an empty element with \a name, prefixed for the specified + \a namespaceUri. If the namespace has not been declared, + QXmlStreamWriter will generate a namespace declaration for it. + Subsequent calls to writeAttribute() will add attributes to this element. + + \sa writeNamespace() + */ +void QXmlStreamWriter::writeEmptyElement(const QString &namespaceUri, const QString &name) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(!name.contains(QLatin1Char(':'))); + d->writeStartElement(namespaceUri, name); + d->inEmptyElement = true; +} + + +/*!\overload + Writes a text element with \a qualifiedName and \a text. + + + This is a convenience function equivalent to: + \snippet doc/src/snippets/code/src_corelib_xml_qxmlstream.cpp 1 + +*/ +void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text) +{ + writeStartElement(qualifiedName); + writeCharacters(text); + writeEndElement(); +} + +/*! Writes a text element with \a name, prefixed for the specified \a + namespaceUri, and \a text. If the namespace has not been + declared, QXmlStreamWriter will generate a namespace declaration + for it. + + + This is a convenience function equivalent to: + \snippet doc/src/snippets/code/src_corelib_xml_qxmlstream.cpp 2 + +*/ +void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text) +{ + writeStartElement(namespaceUri, name); + writeCharacters(text); + writeEndElement(); +} + + +/*! + Closes all remaining open start elements and writes a newline. + + \sa writeStartDocument() + */ +void QXmlStreamWriter::writeEndDocument() +{ + Q_D(QXmlStreamWriter); + while (d->tagStack.size()) + writeEndElement(); + d->write("\n"); +} + +/*! + Closes the previous start element. + + \sa writeStartElement() + */ +void QXmlStreamWriter::writeEndElement() +{ + Q_D(QXmlStreamWriter); + if (d->tagStack.isEmpty()) + return; + + // shortcut: if nothing was written, close as empty tag + if (d->inStartElement && !d->inEmptyElement) { + d->write("/>"); + d->lastWasStartElement = d->inStartElement = false; + QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop(); + d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize; + return; + } + + if (!d->finishStartElement(false) && !d->lastWasStartElement && d->autoFormatting) + d->indent(d->tagStack.size()-1); + if (d->tagStack.isEmpty()) + return; + d->lastWasStartElement = false; + QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop(); + d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize; + d->write("</"); + if (!tag.namespaceDeclaration.prefix.isEmpty()) { + d->write(tag.namespaceDeclaration.prefix); + d->write(":"); + } + d->write(tag.name); + d->write(">"); +} + + + +/*! + Writes the entity reference \a name to the stream, as "&\a{name};". + */ +void QXmlStreamWriter::writeEntityReference(const QString &name) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(); + d->write("&"); + d->write(name); + d->write(";"); +} + + +/*! Writes a namespace declaration for \a namespaceUri with \a + prefix. If \a prefix is empty, QXmlStreamWriter assigns a unique + prefix consisting of the letter 'n' followed by a number. + + If writeStartElement() or writeEmptyElement() was called, the + declaration applies to the current element; otherwise it applies to + the next child element. + + Note that the prefix \e xml is both predefined and reserved for + \e http://www.w3.org/XML/1998/namespace, which in turn cannot be + bound to any other prefix. The prefix \e xmlns and its URI + \e http://www.w3.org/2000/xmlns/ are used for the namespace mechanism + itself and thus completely forbidden in declarations. + + */ +void QXmlStreamWriter::writeNamespace(const QString &namespaceUri, const QString &prefix) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(!namespaceUri.isEmpty()); + Q_ASSERT(prefix != QLatin1String("xmlns")); + if (prefix.isEmpty()) { + d->findNamespace(namespaceUri, d->inStartElement); + } else { + Q_ASSERT(!((prefix == QLatin1String("xml")) ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))); + Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/")); + QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push(); + namespaceDeclaration.prefix = d->addToStringStorage(prefix); + namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri); + if (d->inStartElement) + d->writeNamespaceDeclaration(namespaceDeclaration); + } +} + + +/*! Writes a default namespace declaration for \a namespaceUri. + + If writeStartElement() or writeEmptyElement() was called, the + declaration applies to the current element; otherwise it applies to + the next child element. + + Note that the namespaces \e http://www.w3.org/XML/1998/namespace + (bound to \e xmlns) and \e http://www.w3.org/2000/xmlns/ (bound to + \e xml) by definition cannot be declared as default. + */ +void QXmlStreamWriter::writeDefaultNamespace(const QString &namespaceUri) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/XML/1998/namespace")); + Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/")); + QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push(); + namespaceDeclaration.prefix.clear(); + namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri); + if (d->inStartElement) + d->writeNamespaceDeclaration(namespaceDeclaration); +} + + +/*! + Writes an XML processing instruction with \a target and \a data, + where \a data must not contain the sequence "?>". + */ +void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const QString &data) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(!data.contains(QLatin1String("?>"))); + d->finishStartElement(); + d->write("<?"); + d->write(target); + if (!data.isNull()) { + d->write(" "); + d->write(data); + } + d->write("?>"); +} + + + +/*!\overload + + Writes a document start with XML version number "1.0". This also + writes the encoding information. + + \sa writeEndDocument(), setCodec() + \since 4.5 + */ +void QXmlStreamWriter::writeStartDocument() +{ + writeStartDocument(QLatin1String("1.0")); +} + + +/*! + Writes a document start with the XML version number \a version. + + \sa writeEndDocument() + */ +void QXmlStreamWriter::writeStartDocument(const QString &version) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(false); + d->write("<?xml version=\""); + d->write(version); + if (d->device) { // stringDevice does not get any encoding + d->write("\" encoding=\""); +#ifdef QT_NO_TEXTCODEC + d->write("iso-8859-1"); +#else + d->write(d->codec->name().constData()); +#endif + } + d->write("\"?>"); +} + +/*! Writes a document start with the XML version number \a version + and a standalone attribute \a standalone. + + \sa writeEndDocument() + \since 4.5 + */ +void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone) +{ + Q_D(QXmlStreamWriter); + d->finishStartElement(false); + d->write("<?xml version=\""); + d->write(version); + if (d->device) { // stringDevice does not get any encoding + d->write("\" encoding=\""); +#ifdef QT_NO_TEXTCODEC + d->write("iso-8859-1"); +#else + d->write(d->codec->name().constData()); +#endif + } + d->write("\" standalone=\""); + d->write(standalone ? "yes" : "no"); + d->write("\"?>"); +} + + +/*!\overload + + Writes a start element with \a qualifiedName. Subsequent calls to + writeAttribute() will add attributes to this element. + + \sa writeEndElement(), writeEmptyElement() + */ +void QXmlStreamWriter::writeStartElement(const QString &qualifiedName) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1); + d->writeStartElement(QString(), qualifiedName); +} + + +/*! Writes a start element with \a name, prefixed for the specified + \a namespaceUri. If the namespace has not been declared yet, + QXmlStreamWriter will generate a namespace declaration for + it. Subsequent calls to writeAttribute() will add attributes to this + element. + + \sa writeNamespace(), writeEndElement(), writeEmptyElement() + */ +void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name) +{ + Q_D(QXmlStreamWriter); + Q_ASSERT(!name.contains(QLatin1Char(':'))); + d->writeStartElement(namespaceUri, name); +} + +void QXmlStreamWriterPrivate::writeStartElement(const QString &namespaceUri, const QString &name) +{ + if (!finishStartElement(false) && autoFormatting) + indent(tagStack.size()); + + Tag &tag = tagStack_push(); + tag.name = addToStringStorage(name); + tag.namespaceDeclaration = findNamespace(namespaceUri); + write("<"); + if (!tag.namespaceDeclaration.prefix.isEmpty()) { + write(tag.namespaceDeclaration.prefix); + write(":"); + } + write(tag.name); + inStartElement = lastWasStartElement = true; + + for (int i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i) + writeNamespaceDeclaration(namespaceDeclarations[i]); + tag.namespaceDeclarationsSize = lastNamespaceDeclaration; +} + +#ifndef QT_NO_XMLSTREAMREADER +/*! Writes the current state of the \a reader. All possible valid + states are supported. + + The purpose of this function is to support chained processing of XML data. + + \sa QXmlStreamReader::tokenType() + */ +void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader) +{ + switch (reader.tokenType()) { + case QXmlStreamReader::NoToken: + break; + case QXmlStreamReader::StartDocument: + writeStartDocument(); + break; + case QXmlStreamReader::EndDocument: + writeEndDocument(); + break; + case QXmlStreamReader::StartElement: { + QXmlStreamNamespaceDeclarations namespaceDeclarations = reader.namespaceDeclarations(); + for (int i = 0; i < namespaceDeclarations.size(); ++i) { + const QXmlStreamNamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(i); + writeNamespace(namespaceDeclaration.namespaceUri().toString(), + namespaceDeclaration.prefix().toString()); + } + writeStartElement(reader.namespaceUri().toString(), reader.name().toString()); + writeAttributes(reader.attributes()); + } break; + case QXmlStreamReader::EndElement: + writeEndElement(); + break; + case QXmlStreamReader::Characters: + if (reader.isCDATA()) + writeCDATA(reader.text().toString()); + else + writeCharacters(reader.text().toString()); + break; + case QXmlStreamReader::Comment: + writeComment(reader.text().toString()); + break; + case QXmlStreamReader::DTD: + writeDTD(reader.text().toString()); + break; + case QXmlStreamReader::EntityReference: + writeEntityReference(reader.name().toString()); + break; + case QXmlStreamReader::ProcessingInstruction: + writeProcessingInstruction(reader.processingInstructionTarget().toString(), + reader.processingInstructionData().toString()); + break; + default: + Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid); + qWarning("QXmlStreamWriter: writeCurrentToken() with invalid state."); + break; + } +} + +/*! + \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const + \since 4.5 + + Returns true if this QXmlStreamAttributes has an attribute whose + qualified name is \a qualifiedName; otherwise returns false. + + Note that this is not namespace aware. For instance, if this + QXmlStreamAttributes contains an attribute whose lexical name is "xlink:href" + this doesn't tell that an attribute named \c href in the XLink namespace is + present, since the \c xlink prefix can be bound to any namespace. Use the + overload that takes a namespace URI and a local name as parameter, for + namespace aware code. +*/ + +/*! + \fn bool QXmlStreamAttributes::hasAttribute(const QLatin1String &qualifiedName) const + \overload + \since 4.5 +*/ + +/*! + \fn bool QXmlStreamAttributes::hasAttribute(const QString &namespaceUri, + const QString &name) const + \overload + \since 4.5 + + Returns true if this QXmlStreamAttributes has an attribute whose + namespace URI and name correspond to \a namespaceUri and \a name; + otherwise returns false. +*/ + +#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMWRITER + +QT_END_NAMESPACE + +#endif // QT_NO_XMLSTREAM diff --git a/src/corelib/xml/qxmlstream.g b/src/corelib/xml/qxmlstream.g new file mode 100644 index 0000000..d5e64a6 --- /dev/null +++ b/src/corelib/xml/qxmlstream.g @@ -0,0 +1,1846 @@ +---------------------------------------------------------------------------- +-- +-- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +-- Contact: Qt Software Information (qt-info@nokia.com) +-- +-- This file is part of the QtCore module of the Qt Toolkit. +-- +-- $QT_BEGIN_LICENSE:LGPL$ +-- No Commercial Usage +-- This file contains pre-release code and may not be distributed. +-- You may use this file in accordance with the terms and conditions +-- contained in the either Technology Preview License Agreement or the +-- Beta Release License Agreement. +-- +-- GNU Lesser General Public License Usage +-- Alternatively, this file may be used under the terms of the GNU Lesser +-- General Public License version 2.1 as published by the Free Software +-- Foundation and appearing in the file LICENSE.LGPL included in the +-- packaging of this file. Please review the following information to +-- ensure the GNU Lesser General Public License version 2.1 requirements +-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +-- +-- In addition, as a special exception, Nokia gives you certain +-- additional rights. These rights are described in the Nokia Qt LGPL +-- Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +-- package. +-- +-- GNU General Public License Usage +-- Alternatively, this file may be used under the terms of the GNU +-- General Public License version 3.0 as published by the Free Software +-- Foundation and appearing in the file LICENSE.GPL included in the +-- packaging of this file. Please review the following information to +-- ensure the GNU General Public License version 3.0 requirements will be +-- met: http://www.gnu.org/copyleft/gpl.html. +-- +-- If you are unsure which license is appropriate for your use, please +-- contact the sales department at qt-sales@nokia.com. +-- $QT_END_LICENSE$ +-- +-- This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +-- WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- +---------------------------------------------------------------------------- + +%parser QXmlStreamReader_Table + +%merged_output qxmlstream_p.h + +%token NOTOKEN +%token SPACE " " +%token LANGLE "<" +%token RANGLE ">" +%token AMPERSAND "&" +%token HASH "#" +%token QUOTE "\'" +%token DBLQUOTE "\"" +%token LBRACK "[" +%token RBRACK "]" +%token LPAREN "(" +%token RPAREN ")" +%token PIPE "|" +%token EQ "=" +%token PERCENT "%" +%token SLASH "/" +%token COLON ":" +%token SEMICOLON ";" +%token COMMA "," +%token DASH "-" +%token PLUS "+" +%token STAR "*" +%token DOT "." +%token QUESTIONMARK "?" +%token BANG "!" +%token LETTER "[a-zA-Z]" +%token DIGIT "[0-9]" + +-- after langle_bang +%token CDATA_START "[CDATA[" +%token DOCTYPE "DOCTYPE" +%token ELEMENT "ELEMENT" +%token ATTLIST "ATTLIST" +%token ENTITY "ENTITY" +%token NOTATION "NOTATION" + +-- entity decl +%token SYSTEM "SYSTEM" +%token PUBLIC "PUBLIC" +%token NDATA "NDATA" + +-- default decl +%token REQUIRED "REQUIRED" +%token IMPLIED "IMPLIED" +%token FIXED "FIXED" + +-- conent spec +%token EMPTY "EMPTY" +%token ANY "ANY" +%token PCDATA "PCDATA" + +-- error +%token ERROR + +-- entities +%token PARSE_ENTITY +%token ENTITY_DONE +%token UNRESOLVED_ENTITY + +-- att type +%token CDATA "CDATA" +%token ID "ID" +%token IDREF "IDREF" +%token IDREFS "IDREFS" +%token ENTITY "ENTITY" +%token ENTITIES "ENTITIES" +%token NMTOKEN "NMTOKEN" +%token NMTOKENS "NMTOKENS" + +-- xml declaration +%token XML "<?xml" +%token VERSION "version" + +%nonassoc SHIFT_THERE +%nonassoc AMPERSAND + BANG + COLON + COMMA + DASH + DBLQUOTE + DIGIT + DOT + ENTITY_DONE + EQ + HASH + LBRACK + LETTER + LPAREN + PERCENT + PIPE + PLUS + QUESTIONMARK + QUOTE + RANGLE + RBRACK + RPAREN + SEMICOLON + SLASH + SPACE + STAR + +%start document + +/. +template <typename T> class QXmlStreamSimpleStack { + T *data; + int tos, cap; +public: + inline QXmlStreamSimpleStack():data(0), tos(-1), cap(0){} + inline ~QXmlStreamSimpleStack(){ if (data) qFree(data); } + + inline void reserve(int extraCapacity) { + if (tos + extraCapacity + 1 > cap) { + cap = qMax(tos + extraCapacity + 1, cap << 1 ); + data = reinterpret_cast<T *>(qRealloc(data, cap * sizeof(T))); + } + } + + inline T &push() { reserve(1); return data[++tos]; } + inline T &rawPush() { return data[++tos]; } + inline const T &top() const { return data[tos]; } + inline T &top() { return data[tos]; } + inline T &pop() { return data[tos--]; } + inline T &operator[](int index) { return data[index]; } + inline const T &at(int index) const { return data[index]; } + inline int size() const { return tos + 1; } + inline void resize(int s) { tos = s - 1; } + inline bool isEmpty() const { return tos < 0; } + inline void clear() { tos = -1; } +}; + + +class QXmlStream +{ + Q_DECLARE_TR_FUNCTIONS(QXmlStream) +}; + +class QXmlStreamPrivateTagStack { +public: + struct NamespaceDeclaration + { + QStringRef prefix; + QStringRef namespaceUri; + }; + + struct Tag + { + QStringRef name; + QStringRef qualifiedName; + NamespaceDeclaration namespaceDeclaration; + int tagStackStringStorageSize; + int namespaceDeclarationsSize; + }; + + + QXmlStreamPrivateTagStack(); + QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations; + QString tagStackStringStorage; + int tagStackStringStorageSize; + bool tagsDone; + + inline QStringRef addToStringStorage(const QStringRef &s) { + int pos = tagStackStringStorageSize; + int sz = s.size(); + if (pos != tagStackStringStorage.size()) + tagStackStringStorage.resize(pos); + tagStackStringStorage.insert(pos, s.unicode(), sz); + tagStackStringStorageSize += sz; + return QStringRef(&tagStackStringStorage, pos, sz); + } + inline QStringRef addToStringStorage(const QString &s) { + int pos = tagStackStringStorageSize; + int sz = s.size(); + if (pos != tagStackStringStorage.size()) + tagStackStringStorage.resize(pos); + tagStackStringStorage.insert(pos, s.unicode(), sz); + tagStackStringStorageSize += sz; + return QStringRef(&tagStackStringStorage, pos, sz); + } + + QXmlStreamSimpleStack<Tag> tagStack; + + + inline Tag &tagStack_pop() { + Tag& tag = tagStack.pop(); + tagStackStringStorageSize = tag.tagStackStringStorageSize; + namespaceDeclarations.resize(tag.namespaceDeclarationsSize); + tagsDone = tagStack.isEmpty(); + return tag; + } + inline Tag &tagStack_push() { + Tag &tag = tagStack.push(); + tag.tagStackStringStorageSize = tagStackStringStorageSize; + tag.namespaceDeclarationsSize = namespaceDeclarations.size(); + return tag; + } +}; + + +class QXmlStreamEntityResolver; + +class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{ + QXmlStreamReader *q_ptr; + Q_DECLARE_PUBLIC(QXmlStreamReader) +public: + QXmlStreamReaderPrivate(QXmlStreamReader *q); + ~QXmlStreamReaderPrivate(); + void init(); + + QByteArray rawReadBuffer; + QByteArray dataBuffer; + uchar firstByte; + qint64 nbytesread; + QString readBuffer; + int readBufferPos; + QXmlStreamSimpleStack<uint> putStack; + struct Entity { + Entity(const QString& str = QString()) + :value(str), external(false), unparsed(false), literal(false), + hasBeenParsed(false), isCurrentlyReferenced(false){} + static inline Entity createLiteral(const QString &entity) + { Entity result(entity); result.literal = result.hasBeenParsed = true; return result; } + QString value; + uint external : 1; + uint unparsed : 1; + uint literal : 1; + uint hasBeenParsed : 1; + uint isCurrentlyReferenced : 1; + }; + QHash<QString, Entity> entityHash; + QHash<QString, Entity> parameterEntityHash; + QXmlStreamSimpleStack<Entity *>entityReferenceStack; + inline bool referenceEntity(Entity &entity) { + if (entity.isCurrentlyReferenced) { + raiseWellFormedError(QXmlStream::tr("Recursive entity detected.")); + return false; + } + entity.isCurrentlyReferenced = true; + entityReferenceStack.push() = &entity; + injectToken(ENTITY_DONE); + return true; + } + + + QIODevice *device; + bool deleteDevice; +#ifndef QT_NO_TEXTCODEC + QTextCodec *codec; + QTextDecoder *decoder; +#endif + bool atEnd; + + /*! + \sa setType() + */ + QXmlStreamReader::TokenType type; + QXmlStreamReader::Error error; + QString errorString; + QString unresolvedEntity; + + qint64 lineNumber, lastLineStart, characterOffset; + + + void write(const QString &); + void write(const char *); + + + QXmlStreamAttributes attributes; + QStringRef namespaceForPrefix(const QStringRef &prefix); + void resolveTag(); + void resolvePublicNamespaces(); + void resolveDtd(); + uint resolveCharRef(int symbolIndex); + bool checkStartDocument(); + void startDocument(); + void parseError(); + void checkPublicLiteral(const QStringRef &publicId); + + bool scanDtd; + QStringRef lastAttributeValue; + bool lastAttributeIsCData; + struct DtdAttribute { + QStringRef tagName; + QStringRef attributeQualifiedName; + QStringRef attributePrefix; + QStringRef attributeName; + QStringRef defaultValue; + bool isCDATA; + bool isNamespaceAttribute; + }; + QXmlStreamSimpleStack<DtdAttribute> dtdAttributes; + struct NotationDeclaration { + QStringRef name; + QStringRef publicId; + QStringRef systemId; + }; + QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations; + QXmlStreamNotationDeclarations publicNotationDeclarations; + QXmlStreamNamespaceDeclarations publicNamespaceDeclarations; + + struct EntityDeclaration { + QStringRef name; + QStringRef notationName; + QStringRef publicId; + QStringRef systemId; + QStringRef value; + bool parameter; + bool external; + inline void clear() { + name.clear(); + notationName.clear(); + publicId.clear(); + systemId.clear(); + value.clear(); + parameter = external = false; + } + }; + QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations; + QXmlStreamEntityDeclarations publicEntityDeclarations; + + QStringRef text; + + QStringRef prefix, namespaceUri, qualifiedName, name; + QStringRef processingInstructionTarget, processingInstructionData; + QStringRef dtdName, dtdPublicId, dtdSystemId; + QStringRef documentVersion, documentEncoding; + uint isEmptyElement : 1; + uint isWhitespace : 1; + uint isCDATA : 1; + uint standalone : 1; + uint hasCheckedStartDocument : 1; + uint normalizeLiterals : 1; + uint hasSeenTag : 1; + uint inParseEntity : 1; + uint referenceToUnparsedEntityDetected : 1; + uint referenceToParameterEntityDetected : 1; + uint hasExternalDtdSubset : 1; + uint lockEncoding : 1; + uint namespaceProcessing : 1; + + int resumeReduction; + void resume(int rule); + + inline bool entitiesMustBeDeclared() const { + return (!inParseEntity + && (standalone + || (!referenceToUnparsedEntityDetected + && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25 + && !hasExternalDtdSubset))); + } + + // qlalr parser + int tos; + int stack_size; + struct Value { + int pos; + int len; + int prefix; + ushort c; + }; + + Value *sym_stack; + int *state_stack; + inline void reallocateStack(); + inline Value &sym(int index) const + { return sym_stack[tos + index - 1]; } + QString textBuffer; + inline void clearTextBuffer() { + if (!scanDtd) { + textBuffer.resize(0); + textBuffer.reserve(256); + } + } + struct Attribute { + Value key; + Value value; + }; + QXmlStreamSimpleStack<Attribute> attributeStack; + + inline QStringRef symString(int index) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); + } + inline QStringRef symName(int index) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos, symbol.len); + } + inline QStringRef symString(int index, int offset) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset); + } + inline QStringRef symPrefix(int index) { + const Value &symbol = sym(index); + if (symbol.prefix) + return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); + return QStringRef(); + } + inline QStringRef symString(const Value &symbol) { + return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); + } + inline QStringRef symName(const Value &symbol) { + return QStringRef(&textBuffer, symbol.pos, symbol.len); + } + inline QStringRef symPrefix(const Value &symbol) { + if (symbol.prefix) + return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); + return QStringRef(); + } + + inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; } + + + short token; + ushort token_char; + + uint filterCarriageReturn(); + inline uint getChar(); + inline uint peekChar(); + inline void putChar(uint c) { putStack.push() = c; } + inline void putChar(QChar c) { putStack.push() = c.unicode(); } + void putString(const QString &s, int from = 0); + void putStringLiteral(const QString &s); + void putReplacement(const QString &s); + void putReplacementInAttributeValue(const QString &s); + ushort getChar_helper(); + + bool scanUntil(const char *str, short tokenToInject = -1); + bool scanString(const char *str, short tokenToInject, bool requireSpace = true); + inline void injectToken(ushort tokenToInject) { + putChar(int(tokenToInject) << 16); + } + + QString resolveUndeclaredEntity(const QString &name); + void parseEntity(const QString &value); + QXmlStreamReaderPrivate *entityParser; + + bool scanAfterLangleBang(); + bool scanPublicOrSystem(); + bool scanNData(); + bool scanAfterDefaultDecl(); + bool scanAttType(); + + + // scan optimization functions. Not strictly necessary but LALR is + // not very well suited for scanning fast + int fastScanLiteralContent(); + int fastScanSpace(); + int fastScanContentCharList(); + int fastScanName(int *prefix = 0); + inline int fastScanNMTOKEN(); + + + bool parse(); + inline void consumeRule(int); + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); + + QXmlStreamEntityResolver *entityResolver; + +private: + /*! \internal + Never assign to variable type directly. Instead use this function. + + This prevents errors from being ignored. + */ + inline void setType(const QXmlStreamReader::TokenType t) + { + if(type != QXmlStreamReader::Invalid) + type = t; + } +}; + +bool QXmlStreamReaderPrivate::parse() +{ + // cleanup currently reported token + + switch (type) { + case QXmlStreamReader::StartElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + if (publicNamespaceDeclarations.size()) + publicNamespaceDeclarations.clear(); + if (attributes.size()) + attributes.resize(0); + if (isEmptyElement) { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + isEmptyElement = false; + return true; + } + clearTextBuffer(); + break; + case QXmlStreamReader::EndElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::DTD: + publicNotationDeclarations.clear(); + publicEntityDeclarations.clear(); + dtdName.clear(); + dtdPublicId.clear(); + dtdSystemId.clear(); + // fall through + case QXmlStreamReader::Comment: + case QXmlStreamReader::Characters: + isCDATA = false; + isWhitespace = true; + text.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::EntityReference: + text.clear(); + name.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::ProcessingInstruction: + processingInstructionTarget.clear(); + processingInstructionData.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + break; + case QXmlStreamReader::StartDocument: + lockEncoding = true; + documentVersion.clear(); + documentEncoding.clear(); +#ifndef QT_NO_TEXTCODEC + if(decoder->hasFailure()) { + raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); + readBuffer.clear(); + return false; + } +#endif + // fall through + default: + clearTextBuffer(); + ; + } + + setType(QXmlStreamReader::NoToken); + + + // the main parse loop + int act, r; + + if (resumeReduction) { + act = state_stack[tos-1]; + r = resumeReduction; + resumeReduction = 0; + goto ResumeReduction; + } + + act = state_stack[tos]; + + forever { + if (token == -1 && - TERMINAL_COUNT != action_index[act]) { + uint cu = getChar(); + token = NOTOKEN; + token_char = cu; + if (cu & 0xff0000) { + token = cu >> 16; + } else switch (token_char) { + case 0xfffe: + case 0xffff: + token = ERROR; + break; + case '\r': + token = SPACE; + if (cu == '\r') { + if ((token_char = filterCarriageReturn())) { + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + break; + } + } else { + break; + } + // fall through + case '\0': { + token = EOF_SYMBOL; + if (!tagsDone && !inParseEntity) { + int a = t_action(act, token); + if (a < 0) { + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); + return false; + } + } + + } break; + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + case ' ': + case '\t': + token = SPACE; + break; + case '&': + token = AMPERSAND; + break; + case '#': + token = HASH; + break; + case '\'': + token = QUOTE; + break; + case '\"': + token = DBLQUOTE; + break; + case '<': + token = LANGLE; + break; + case '>': + token = RANGLE; + break; + case '[': + token = LBRACK; + break; + case ']': + token = RBRACK; + break; + case '(': + token = LPAREN; + break; + case ')': + token = RPAREN; + break; + case '|': + token = PIPE; + break; + case '=': + token = EQ; + break; + case '%': + token = PERCENT; + break; + case '/': + token = SLASH; + break; + case ':': + token = COLON; + break; + case ';': + token = SEMICOLON; + break; + case ',': + token = COMMA; + break; + case '-': + token = DASH; + break; + case '+': + token = PLUS; + break; + case '*': + token = STAR; + break; + case '.': + token = DOT; + break; + case '?': + token = QUESTIONMARK; + break; + case '!': + token = BANG; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token = DIGIT; + break; + default: + if (cu < 0x20) + token = NOTOKEN; + else + token = LETTER; + break; + } + } + + act = t_action (act, token); + if (act == ACCEPT_STATE) { + // reset the parser in case someone resumes (process instructions can follow a valid document) + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return true; + } else if (act > 0) { + if (++tos == stack_size) + reallocateStack(); + + Value &val = sym_stack[tos]; + val.c = token_char; + val.pos = textBuffer.size(); + val.prefix = 0; + val.len = 1; + if (token_char) + textBuffer += QChar(token_char); + + state_stack[tos] = act; + token = -1; + + + } else if (act < 0) { + r = - act - 1; + +#if defined (QLALR_DEBUG) + int ridx = rule_index[r]; + printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]); + ++ridx; + for (int i = ridx; i < ridx + rhs[r]; ++i) { + int symbol = rule_info[i]; + if (const char *name = spell[symbol]) + printf (" %s", name); + else + printf (" #%d", symbol); + } + printf ("\n"); +#endif + + tos -= rhs[r]; + act = state_stack[tos++]; + ResumeReduction: + switch (r) { +./ + +document ::= PARSE_ENTITY content; +/. + case $rule_number: + setType(QXmlStreamReader::EndDocument); + break; +./ + +document ::= prolog; +/. + case $rule_number: + if (type != QXmlStreamReader::Invalid) { + if (hasSeenTag || inParseEntity) { + setType(QXmlStreamReader::EndDocument); + } else { + raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected.")); + // reset the parser + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return false; + } + } + break; +./ + + +prolog ::= prolog stag content etag; +prolog ::= prolog empty_element_tag; +prolog ::= prolog comment; +prolog ::= prolog xml_decl; +prolog ::= prolog processing_instruction; +prolog ::= prolog doctype_decl; +prolog ::= prolog SPACE; +prolog ::=; + +entity_done ::= ENTITY_DONE; +/. + case $rule_number: + entityReferenceStack.pop()->isCurrentlyReferenced = false; + clearSym(); + break; +./ + + +xml_decl_start ::= XML; +/. + case $rule_number: + if (!scanString(spell[VERSION], VERSION, false) && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +xml_decl ::= xml_decl_start VERSION space_opt EQ space_opt literal attribute_list_opt QUESTIONMARK RANGLE; +/. + case $rule_number: + setType(QXmlStreamReader::StartDocument); + documentVersion = symString(6); + startDocument(); + break; +./ + +external_id ::= SYSTEM literal; +/. + case $rule_number: + hasExternalDtdSubset = true; + dtdSystemId = symString(2); + break; +./ +external_id ::= PUBLIC public_literal space literal; +/. + case $rule_number: + checkPublicLiteral(symString(2)); + dtdPublicId = symString(2); + dtdSystemId = symString(4); + hasExternalDtdSubset = true; + break; +./ +external_id ::=; + +doctype_decl_start ::= langle_bang DOCTYPE qname space; +/. + case $rule_number: + if (!scanPublicOrSystem() && atEnd) { + resume($rule_number); + return false; + } + dtdName = symString(3); + break; +./ + +doctype_decl ::= langle_bang DOCTYPE qname RANGLE; +/. + case $rule_number:./ +doctype_decl ::= langle_bang DOCTYPE qname markup space_opt RANGLE; +/. + case $rule_number: + dtdName = symString(3); + // fall through +./ +doctype_decl ::= doctype_decl_start external_id space_opt markup space_opt RANGLE; +/. + case $rule_number:./ +doctype_decl ::= doctype_decl_start external_id space_opt RANGLE; +/. + case $rule_number: + setType(QXmlStreamReader::DTD); + text = &textBuffer; + break; +./ + +markup_start ::= LBRACK; +/. + case $rule_number: + scanDtd = true; + break; +./ + +markup ::= markup_start markup_list RBRACK; +/. + case $rule_number: + scanDtd = false; + break; +./ + + +markup_list ::= markup_decl | space | pereference; +markup_list ::= markup_list markup_decl | markup_list space | markup_list pereference; + +markup_decl ::= element_decl | attlist_decl | entity_decl | entity_done | notation_decl | processing_instruction | comment; + + +element_decl_start ::= langle_bang ELEMENT qname space; +/. + case $rule_number: + if (!scanString(spell[EMPTY], EMPTY, false) + && !scanString(spell[ANY], ANY, false) + && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +element_decl ::= element_decl_start content_spec space_opt RANGLE; + + +content_spec ::= EMPTY | ANY | mixed | children; + +pcdata_start ::= HASH; +/. + case $rule_number: + if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +pcdata ::= pcdata_start PCDATA; + +questionmark_or_star_or_plus_opt ::= QUESTIONMARK | STAR | PLUS; +questionmark_or_star_or_plus_opt ::=; + +cp ::= qname questionmark_or_star_or_plus_opt | choice_or_seq questionmark_or_star_or_plus_opt; + +cp_pipe_or_comma_list ::= cp space_opt; +cp_pipe_or_comma_list ::= cp space_opt PIPE space_opt cp_pipe_list space_opt; +cp_pipe_or_comma_list ::= cp space_opt COMMA space_opt cp_comma_list space_opt; +cp_pipe_list ::= cp | cp_pipe_list space_opt PIPE space_opt cp; +cp_comma_list ::= cp | cp_comma_list space_opt COMMA space_opt cp; + + +name_pipe_list ::= PIPE space_opt qname; +name_pipe_list ::= name_pipe_list space_opt PIPE space_opt qname; + +star_opt ::= | STAR; + +mixed ::= LPAREN space_opt pcdata space_opt RPAREN star_opt; +mixed ::= LPAREN space_opt pcdata space_opt name_pipe_list space_opt RPAREN STAR; + +choice_or_seq ::= LPAREN space_opt cp_pipe_or_comma_list RPAREN; + +children ::= choice_or_seq questionmark_or_star_or_plus_opt; + + +nmtoken_pipe_list ::= nmtoken; +nmtoken_pipe_list ::= nmtoken_pipe_list space_opt PIPE space_opt nmtoken; + + +att_type ::= CDATA; +/. + case $rule_number: { + lastAttributeIsCData = true; + } break; +./ +att_type ::= ID | IDREF | IDREFS | ENTITY | ENTITIES | NMTOKEN | NMTOKENS; +att_type ::= LPAREN space_opt nmtoken_pipe_list space_opt RPAREN space; +att_type ::= NOTATION LPAREN space_opt nmtoken_pipe_list space_opt RPAREN space; + + +default_declhash ::= HASH; +/. + case $rule_number: + if (!scanAfterDefaultDecl() && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +default_decl ::= default_declhash REQUIRED; +default_decl ::= default_declhash IMPLIED; +default_decl ::= attribute_value; +default_decl ::= default_declhash FIXED space attribute_value; +attdef_start ::= space qname space; +/. + case $rule_number: + sym(1) = sym(2); + lastAttributeValue.clear(); + lastAttributeIsCData = false; + if (!scanAttType() && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +attdef ::= attdef_start att_type default_decl; +/. + case $rule_number: { + DtdAttribute &dtdAttribute = dtdAttributes.push(); + dtdAttribute.tagName.clear(); + dtdAttribute.isCDATA = lastAttributeIsCData; + dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1)); + dtdAttribute.attributeName = addToStringStorage(symString(1)); + dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1)); + dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns") + || (dtdAttribute.attributePrefix.isEmpty() + && dtdAttribute.attributeName == QLatin1String("xmlns"))); + if (lastAttributeValue.isNull()) { + dtdAttribute.defaultValue.clear(); + } else { + if (dtdAttribute.isCDATA) + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue); + else + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified()); + + } + } break; +./ + +attdef_list ::= attdef; +attdef_list ::= attdef_list attdef; + +attlist_decl ::= langle_bang ATTLIST qname space_opt RANGLE; +attlist_decl ::= langle_bang ATTLIST qname attdef_list space_opt RANGLE; +/. + case $rule_number: { + if (referenceToUnparsedEntityDetected && !standalone) + break; + int n = dtdAttributes.size(); + QStringRef tagName = addToStringStorage(symName(3)); + while (n--) { + DtdAttribute &dtdAttribute = dtdAttributes[n]; + if (!dtdAttribute.tagName.isNull()) + break; + dtdAttribute.tagName = tagName; + for (int i = 0; i < n; ++i) { + if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName) + && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) { + dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it + break; + } + } + } + } break; +./ + +entity_decl_start ::= langle_bang ENTITY name space; +/. + case $rule_number: { + if (!scanPublicOrSystem() && atEnd) { + resume($rule_number); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(3); + } break; +./ + +entity_decl_start ::= langle_bang ENTITY PERCENT space name space; +/. + case $rule_number: { + if (!scanPublicOrSystem() && atEnd) { + resume($rule_number); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(5); + entityDeclaration.parameter = true; + } break; +./ + +entity_decl_external ::= entity_decl_start SYSTEM literal; +/. + case $rule_number: { + if (!scanNData() && atEnd) { + resume($rule_number); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.systemId = symString(3); + entityDeclaration.external = true; + } break; +./ + +entity_decl_external ::= entity_decl_start PUBLIC public_literal space literal; +/. + case $rule_number: { + if (!scanNData() && atEnd) { + resume($rule_number); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + checkPublicLiteral((entityDeclaration.publicId = symString(3))); + entityDeclaration.systemId = symString(5); + entityDeclaration.external = true; + } break; +./ + +entity_decl ::= entity_decl_external NDATA name space_opt RANGLE; +/. + case $rule_number: { + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.notationName = symString(3); + if (entityDeclaration.parameter) + raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); + } + //fall through +./ + +entity_decl ::= entity_decl_external space_opt RANGLE; +/. + case $rule_number:./ + +entity_decl ::= entity_decl_start entity_value space_opt RANGLE; +/. + case $rule_number: { + if (referenceToUnparsedEntityDetected && !standalone) { + entityDeclarations.pop(); + break; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + if (!entityDeclaration.external) + entityDeclaration.value = symString(2); + QString entityName = entityDeclaration.name.toString(); + QHash<QString, Entity> &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash; + if (!hash.contains(entityName)) { + Entity entity(entityDeclaration.value.toString()); + entity.unparsed = (!entityDeclaration.notationName.isNull()); + entity.external = entityDeclaration.external; + hash.insert(entityName, entity); + } + } break; +./ + + +processing_instruction ::= LANGLE QUESTIONMARK name space; +/. + case $rule_number: { + setType(QXmlStreamReader::ProcessingInstruction); + int pos = sym(4).pos + sym(4).len; + processingInstructionTarget = symString(3); + if (scanUntil("?>")) { + processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); + const QString piTarget(processingInstructionTarget.toString()); + if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) { + raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document.")); + } + else if(!QXmlUtils::isNCName(piTarget)) + raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget)); + } else if (type != QXmlStreamReader::Invalid){ + resume($rule_number); + return false; + } + } break; +./ + +processing_instruction ::= LANGLE QUESTIONMARK name QUESTIONMARK RANGLE; +/. + case $rule_number: + setType(QXmlStreamReader::ProcessingInstruction); + processingInstructionTarget = symString(3); + if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive)) + raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); + break; +./ + + +langle_bang ::= LANGLE BANG; +/. + case $rule_number: + if (!scanAfterLangleBang() && atEnd) { + resume($rule_number); + return false; + } + break; +./ + +comment_start ::= langle_bang DASH DASH; +/. + case $rule_number: + if (!scanUntil("--")) { + resume($rule_number); + return false; + } + break; +./ + +comment ::= comment_start RANGLE; +/. + case $rule_number: { + setType(QXmlStreamReader::Comment); + int pos = sym(1).pos + 4; + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } break; +./ + + +cdata ::= langle_bang CDATA_START; +/. + case $rule_number: { + setType(QXmlStreamReader::Characters); + isCDATA = true; + isWhitespace = false; + int pos = sym(2).pos; + if (scanUntil("]]>", -1)) { + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } else { + resume($rule_number); + return false; + } + } break; +./ + +notation_decl_start ::= langle_bang NOTATION name space; +/. + case $rule_number: { + if (!scanPublicOrSystem() && atEnd) { + resume($rule_number); + return false; + } + NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); + notationDeclaration.name = symString(3); + } break; +./ + +notation_decl ::= notation_decl_start SYSTEM literal space_opt RANGLE; +/. + case $rule_number: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId = symString(3); + notationDeclaration.publicId.clear(); + } break; +./ + +notation_decl ::= notation_decl_start PUBLIC public_literal space_opt RANGLE; +/. + case $rule_number: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId.clear(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + } break; +./ + +notation_decl ::= notation_decl_start PUBLIC public_literal space literal space_opt RANGLE; +/. + case $rule_number: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + notationDeclaration.systemId = symString(5); + } break; +./ + + + +content_char ::= RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | PERCENT | SLASH | COLON | SEMICOLON | COMMA | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG | QUOTE | DBLQUOTE | LETTER | DIGIT; + +scan_content_char ::= content_char; +/. + case $rule_number: + isWhitespace = false; + // fall through +./ + +scan_content_char ::= SPACE; +/. + case $rule_number: + sym(1).len += fastScanContentCharList(); + if (atEnd && !inParseEntity) { + resume($rule_number); + return false; + } + break; +./ + +content_char_list ::= content_char_list char_ref; +content_char_list ::= content_char_list entity_ref; +content_char_list ::= content_char_list entity_done; +content_char_list ::= content_char_list scan_content_char; +content_char_list ::= char_ref; +content_char_list ::= entity_ref; +content_char_list ::= entity_done; +content_char_list ::= scan_content_char; + + +character_content ::= content_char_list %prec SHIFT_THERE; +/. + case $rule_number: + if (!textBuffer.isEmpty()) { + setType(QXmlStreamReader::Characters); + text = &textBuffer; + } + break; +./ + +literal ::= QUOTE QUOTE; +/. + case $rule_number:./ +literal ::= DBLQUOTE DBLQUOTE; +/. + case $rule_number: + clearSym(); + break; +./ +literal ::= QUOTE literal_content_with_dblquote QUOTE; +/. + case $rule_number:./ +literal ::= DBLQUOTE literal_content_with_quote DBLQUOTE; +/. + case $rule_number: + sym(1) = sym(2); + break; +./ + +literal_content_with_dblquote ::= literal_content_with_dblquote literal_content; +/. + case $rule_number:./ +literal_content_with_quote ::= literal_content_with_quote literal_content; +/. + case $rule_number:./ +literal_content_with_dblquote ::= literal_content_with_dblquote DBLQUOTE; +/. + case $rule_number:./ +literal_content_with_quote ::= literal_content_with_quote QUOTE; +/. + case $rule_number: + sym(1).len += sym(2).len; + break; +./ +literal_content_with_dblquote ::= literal_content; +literal_content_with_quote ::= literal_content; +literal_content_with_dblquote ::= DBLQUOTE; +literal_content_with_quote ::= QUOTE; + +literal_content_start ::= LETTER | DIGIT | RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | PERCENT | SLASH | COLON | SEMICOLON | COMMA | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG; + +literal_content_start ::= SPACE; +/. + case $rule_number: + if (normalizeLiterals) + textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); + break; +./ + +literal_content ::= literal_content_start; +/. + case $rule_number: + sym(1).len += fastScanLiteralContent(); + if (atEnd) { + resume($rule_number); + return false; + } + break; +./ + + +public_literal ::= literal; +/. + case $rule_number: { + if (!QXmlUtils::isPublicID(symString(1).toString())) { + raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString())); + resume($rule_number); + return false; + } + } break; +./ + +entity_value ::= QUOTE QUOTE; +/. + case $rule_number:./ +entity_value ::= DBLQUOTE DBLQUOTE; +/. + case $rule_number: + clearSym(); + break; +./ + +entity_value ::= QUOTE entity_value_content_with_dblquote QUOTE; +/. + case $rule_number:./ +entity_value ::= DBLQUOTE entity_value_content_with_quote DBLQUOTE; +/. + case $rule_number: + sym(1) = sym(2); + break; +./ + +entity_value_content_with_dblquote ::= entity_value_content_with_dblquote entity_value_content; +/. + case $rule_number:./ +entity_value_content_with_quote ::= entity_value_content_with_quote entity_value_content; +/. + case $rule_number:./ +entity_value_content_with_dblquote ::= entity_value_content_with_dblquote DBLQUOTE; +/. + case $rule_number:./ +entity_value_content_with_quote ::= entity_value_content_with_quote QUOTE; +/. + case $rule_number: + sym(1).len += sym(2).len; + break; +./ +entity_value_content_with_dblquote ::= entity_value_content; +entity_value_content_with_quote ::= entity_value_content; +entity_value_content_with_dblquote ::= DBLQUOTE; +entity_value_content_with_quote ::= QUOTE; + +entity_value_content ::= LETTER | DIGIT | LANGLE | RANGLE | HASH | LBRACK | RBRACK | LPAREN | RPAREN | PIPE | EQ | SLASH | COLON | SEMICOLON | COMMA | SPACE | DASH | PLUS | STAR | DOT | QUESTIONMARK | BANG; +entity_value_content ::= char_ref | entity_ref_in_entity_value | entity_done; + + +attribute_value ::= QUOTE QUOTE; +/. + case $rule_number:./ +attribute_value ::= DBLQUOTE DBLQUOTE; +/. + case $rule_number: + clearSym(); + break; +./ +attribute_value ::= QUOTE attribute_value_content_with_dblquote QUOTE; +/. + case $rule_number:./ +attribute_value ::= DBLQUOTE attribute_value_content_with_quote DBLQUOTE; +/. + case $rule_number: + sym(1) = sym(2); + lastAttributeValue = symString(1); + break; +./ + +attribute_value_content_with_dblquote ::= attribute_value_content_with_dblquote attribute_value_content; +/. + case $rule_number:./ +attribute_value_content_with_quote ::= attribute_value_content_with_quote attribute_value_content; +/. + case $rule_number:./ +attribute_value_content_with_dblquote ::= attribute_value_content_with_dblquote DBLQUOTE; +/. + case $rule_number:./ +attribute_value_content_with_quote ::= attribute_value_content_with_quote QUOTE; +/. + case $rule_number: + sym(1).len += sym(2).len; + break; +./ +attribute_value_content_with_dblquote ::= attribute_value_content | DBLQUOTE; +attribute_value_content_with_quote ::= attribute_value_content | QUOTE; + +attribute_value_content ::= literal_content | char_ref | entity_ref_in_attribute_value | entity_done; + +attribute ::= qname space_opt EQ space_opt attribute_value; +/. + case $rule_number: { + QStringRef prefix = symPrefix(1); + if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + namespaceDeclaration.prefix.clear(); + + const QStringRef ns(symString(5)); + if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || + ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + else + namespaceDeclaration.namespaceUri = addToStringStorage(ns); + } else { + Attribute &attribute = attributeStack.push(); + attribute.key = sym(1); + attribute.value = sym(5); + + QStringRef attributeQualifiedName = symName(1); + bool normalize = false; + for (int a = 0; a < dtdAttributes.size(); ++a) { + DtdAttribute &dtdAttribute = dtdAttributes[a]; + if (!dtdAttribute.isCDATA + && dtdAttribute.tagName == qualifiedName + && dtdAttribute.attributeQualifiedName == attributeQualifiedName + ) { + normalize = true; + break; + } + } + if (normalize) { + // normalize attribute value (simplify and trim) + int pos = textBuffer.size(); + int n = 0; + bool wasSpace = true; + for (int i = 0; i < attribute.value.len; ++i) { + QChar c = textBuffer.at(attribute.value.pos + i); + if (c.unicode() == ' ') { + if (wasSpace) + continue; + wasSpace = true; + } else { + wasSpace = false; + } + textBuffer += textBuffer.at(attribute.value.pos + i); + ++n; + } + if (wasSpace) + while (n && textBuffer.at(pos + n - 1).unicode() == ' ') + --n; + attribute.value.pos = pos; + attribute.value.len = n; + } + if (prefix == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + QStringRef namespacePrefix = symString(attribute.key); + QStringRef namespaceUri = symString(attribute.value); + attributeStack.pop(); + if ((namespacePrefix == QLatin1String("xml") + ^ namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")) + || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") + || namespaceUri.isEmpty() + || namespacePrefix == QLatin1String("xmlns")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + + namespaceDeclaration.prefix = addToStringStorage(namespacePrefix); + namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); + } + } + } break; +./ + + + +attribute_list_opt ::= | space | space attribute_list space_opt; +attribute_list ::= attribute | attribute_list space attribute; + +stag_start ::= LANGLE qname; +/. + case $rule_number: { + normalizeLiterals = true; + Tag &tag = tagStack_push(); + prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2)); + name = tag.name = addToStringStorage(symString(2)); + qualifiedName = tag.qualifiedName = addToStringStorage(symName(2)); + if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name)) + raiseWellFormedError(QXmlStream::tr("Invalid XML name.")); + } break; +./ + + +empty_element_tag ::= stag_start attribute_list_opt SLASH RANGLE; +/. + case $rule_number: + isEmptyElement = true; + // fall through +./ + + +stag ::= stag_start attribute_list_opt RANGLE; +/. + case $rule_number: + setType(QXmlStreamReader::StartElement); + resolveTag(); + if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) + raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); + hasSeenTag = true; + break; +./ + + +etag ::= LANGLE SLASH qname space_opt RANGLE; +/. + case $rule_number: { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + if (qualifiedName != symName(3)) + raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); + } break; +./ + + +unresolved_entity ::= UNRESOLVED_ENTITY; +/. + case $rule_number: + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); + break; + } + setType(QXmlStreamReader::EntityReference); + name = &unresolvedEntity; + break; +./ + +entity_ref ::= AMPERSAND name SEMICOLON; +/. + case $rule_number: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (entityHash.contains(reference)) { + Entity &entity = entityHash[reference]; + if (entity.unparsed) { + raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference)); + } else { + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacement(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + + injectToken(UNRESOLVED_ENTITY); + unresolvedEntity = symString(2).toString(); + textBuffer.chop(2 + sym(2).len); + clearSym(); + + } break; +./ + +pereference ::= PERCENT name SEMICOLON; +/. + case $rule_number: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (parameterEntityHash.contains(reference)) { + referenceToParameterEntityDetected = true; + Entity &entity = parameterEntityHash[reference]; + if (entity.unparsed || entity.external) { + referenceToUnparsedEntityDetected = true; + } else { + if (referenceEntity(entity)) + putString(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + } else if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString())); + } + } break; +./ + + + +entity_ref_in_entity_value ::= AMPERSAND name SEMICOLON; +/. + case $rule_number: + sym(1).len += sym(2).len + 1; + break; +./ + +entity_ref_in_attribute_value ::= AMPERSAND name SEMICOLON; +/. + case $rule_number: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (entityHash.contains(reference)) { + Entity &entity = entityHash[reference]; + if (entity.unparsed || entity.value.isNull()) { + raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference)); + break; + } + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacementInAttributeValue(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference)); + } + } break; +./ + +char_ref ::= AMPERSAND HASH char_ref_value SEMICOLON; +/. + case $rule_number: { + if (uint s = resolveCharRef(3)) { + if (s >= 0xffff) + putStringLiteral(QString::fromUcs4(&s, 1)); + else + putChar((LETTER << 16) | s); + + textBuffer.chop(3 + sym(3).len); + clearSym(); + } else { + raiseWellFormedError(QXmlStream::tr("Invalid character reference.")); + } + } break; +./ + + +char_ref_value ::= LETTER | DIGIT; +char_ref_value ::= char_ref_value LETTER; +/. + case $rule_number:./ +char_ref_value ::= char_ref_value DIGIT; +/. + case $rule_number: + sym(1).len += sym(2).len; + break; +./ + + +content ::= content character_content; +content ::= content stag content etag; +content ::= content empty_element_tag; +content ::= content comment; +content ::= content cdata; +content ::= content xml_decl; +content ::= content processing_instruction; +content ::= content doctype_decl; +content ::= content unresolved_entity; +content ::= ; + + +space ::= SPACE; +/. + case $rule_number: + sym(1).len += fastScanSpace(); + if (atEnd) { + resume($rule_number); + return false; + } + break; +./ + + +space_opt ::=; +space_opt ::= space; + +qname ::= LETTER; +/. + case $rule_number: { + sym(1).len += fastScanName(&sym(1).prefix); + if (atEnd) { + resume($rule_number); + return false; + } + } break; +./ + +name ::= LETTER; +/. + case $rule_number: + sym(1).len += fastScanName(); + if (atEnd) { + resume($rule_number); + return false; + } + break; +./ + +nmtoken ::= LETTER; +/. + case $rule_number:./ +nmtoken ::= DIGIT; +/. + case $rule_number:./ +nmtoken ::= DOT; +/. + case $rule_number:./ +nmtoken ::= DASH; +/. + case $rule_number:./ +nmtoken ::= COLON; +/. + case $rule_number: + sym(1).len += fastScanNMTOKEN(); + if (atEnd) { + resume($rule_number); + return false; + } + + break; +./ + + +/. + default: + ; + } // switch + act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT); + if (type != QXmlStreamReader::NoToken) + return true; + } else { + parseError(); + break; + } + } + return false; +} +./ diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h new file mode 100644 index 0000000..2ba7972 --- /dev/null +++ b/src/corelib/xml/qxmlstream.h @@ -0,0 +1,477 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSTREAM_H +#define QXMLSTREAM_H + +#include <QtCore/QIODevice> + +#ifndef QT_NO_XMLSTREAM + +#include <QtCore/QString> +#include <QtCore/QVector> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +// QXmlStream* was originally in the QtXml module +// since we've moved it to QtCore in Qt 4.4.0, we need to +// keep binary compatibility +// +// The list of supported platforms is in: +// http://qtsoftware.com/developer/notes/supported_platforms +// +// These platforms do not support symbol moving nor duplication +// (because duplicate symbols cause warnings when linking): +// Apple MacOS X (Mach-O executable format) +// special case: 64-bit on Mac wasn't supported before 4.5.0 +// IBM AIX (XCOFF executable format) +// +// These platforms do not support symbol moving but allow it to be duplicated: +// Microsoft Windows (COFF PE executable format) +// special case: Windows CE wasn't supported before 4.4.0 +// +// These platforms support symbol moving: +// HP HP-UX (PA-RISC2.0 shared executables) +// HP HP-UXi (ELF executable format) +// FreeBSD (ELF executable format) +// Linux (ELF executable format) +// SGI IRIX (ELF executable format) +// Sun Solaris (ELF executable format) +// +// Other platforms are supported through community contributions only. +// We are taking the optimist scenario here to avoid creating more +// symbols to be supported. + +#if defined(Q_OS_MAC32) || defined(Q_OS_AIX) +# if !defined QT_BUILD_XML_LIB +# define Q_XMLSTREAM_RENAME_SYMBOLS +# endif +#endif + +#if defined QT_BUILD_XML_LIB +# define Q_XMLSTREAM_EXPORT Q_XML_EXPORT +#else +# define Q_XMLSTREAM_EXPORT Q_CORE_EXPORT +#endif + +#if defined Q_XMLSTREAM_RENAME_SYMBOLS +// don't worry, we'll undef and change to typedef at the bottom of the file +# define QXmlStreamAttribute QCoreXmlStreamAttribute +# define QXmlStreamAttributes QCoreXmlStreamAttributes +# define QXmlStreamEntityDeclaration QCoreXmlStreamEntityDeclaration +# define QXmlStreamEntityDeclarations QCoreXmlStreamEntityDeclarations +# define QXmlStreamEntityResolver QCoreXmlStreamEntityResolver +# define QXmlStreamNamespaceDeclaration QCoreXmlStreamNamespaceDeclaration +# define QXmlStreamNamespaceDeclarations QCoreXmlStreamNamespaceDeclarations +# define QXmlStreamNotationDeclaration QCoreXmlStreamNotationDeclaration +# define QXmlStreamNotationDeclarations QCoreXmlStreamNotationDeclarations +# define QXmlStreamReader QCoreXmlStreamReader +# define QXmlStreamStringRef QCoreXmlStreamStringRef +# define QXmlStreamWriter QCoreXmlStreamWriter +#endif + +class Q_XMLSTREAM_EXPORT QXmlStreamStringRef { + QString m_string; + int m_position, m_size; +public: + inline QXmlStreamStringRef():m_position(0), m_size(0){} + inline QXmlStreamStringRef(const QStringRef &aString) + :m_string(aString.string()?*aString.string():QString()), m_position(aString.position()), m_size(aString.size()){} + inline QXmlStreamStringRef(const QString &aString):m_string(aString), m_position(0), m_size(aString.size()){} + inline ~QXmlStreamStringRef(){} + inline void clear() { m_string.clear(); m_position = m_size = 0; } + inline operator QStringRef() const { return QStringRef(&m_string, m_position, m_size); } + inline const QString *string() const { return &m_string; } + inline int position() const { return m_position; } + inline int size() const { return m_size; } +}; + + +class QXmlStreamReaderPrivate; +class QXmlStreamAttributes; +class Q_XMLSTREAM_EXPORT QXmlStreamAttribute { + QXmlStreamStringRef m_name, m_namespaceUri, m_qualifiedName, m_value; + void *reserved; + uint m_isDefault : 1; + friend class QXmlStreamReaderPrivate; + friend class QXmlStreamAttributes; +public: + QXmlStreamAttribute(); + QXmlStreamAttribute(const QString &qualifiedName, const QString &value); + QXmlStreamAttribute(const QString &namespaceUri, const QString &name, const QString &value); + QXmlStreamAttribute(const QXmlStreamAttribute &); + QXmlStreamAttribute& operator=(const QXmlStreamAttribute &); + ~QXmlStreamAttribute(); + inline QStringRef namespaceUri() const { return m_namespaceUri; } + inline QStringRef name() const { return m_name; } + inline QStringRef qualifiedName() const { return m_qualifiedName; } + inline QStringRef prefix() const { + return QStringRef(m_qualifiedName.string(), + m_qualifiedName.position(), + qMax(0, m_qualifiedName.size() - m_name.size() - 1)); + } + inline QStringRef value() const { return m_value; } + inline bool isDefault() const { return m_isDefault; } + inline bool operator==(const QXmlStreamAttribute &other) const { + return (value() == other.value() + && (namespaceUri().isNull() ? (qualifiedName() == other.qualifiedName()) + : (namespaceUri() == other.namespaceUri() && name() == other.name()))); + } + inline bool operator!=(const QXmlStreamAttribute &other) const + { return !operator==(other); } +}; + +Q_DECLARE_TYPEINFO(QXmlStreamAttribute, Q_MOVABLE_TYPE); + +class Q_XMLSTREAM_EXPORT QXmlStreamAttributes : public QVector<QXmlStreamAttribute> +{ +public: + QStringRef value(const QString &namespaceUri, const QString &name) const; + QStringRef value(const QString &namespaceUri, const QLatin1String &name) const; + QStringRef value(const QLatin1String &namespaceUri, const QLatin1String &name) const; + QStringRef value(const QString &qualifiedName) const; + QStringRef value(const QLatin1String &qualifiedName) const; + void append(const QString &namespaceUri, const QString &name, const QString &value); + void append(const QString &qualifiedName, const QString &value); + + inline bool hasAttribute(const QString &qualifiedName) const + { + return !value(qualifiedName).isNull(); + } + + inline bool hasAttribute(const QLatin1String &qualifiedName) const + { + return !value(qualifiedName).isNull(); + } + + inline bool hasAttribute(const QString &namespaceUri, const QString &name) const + { + return !value(namespaceUri, name).isNull(); + } + +#if !defined(Q_NO_USING_KEYWORD) + using QVector<QXmlStreamAttribute>::append; +#else + inline void append(const QXmlStreamAttribute &attribute) + { QVector<QXmlStreamAttribute>::append(attribute); } +#endif +}; + +class Q_XMLSTREAM_EXPORT QXmlStreamNamespaceDeclaration { + QXmlStreamStringRef m_prefix, m_namespaceUri; + void *reserved; + + friend class QXmlStreamReaderPrivate; +public: + QXmlStreamNamespaceDeclaration(); + QXmlStreamNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &); + QXmlStreamNamespaceDeclaration(const QString &prefix, const QString &namespaceUri); + ~QXmlStreamNamespaceDeclaration(); + QXmlStreamNamespaceDeclaration& operator=(const QXmlStreamNamespaceDeclaration &); + inline QStringRef prefix() const { return m_prefix; } + inline QStringRef namespaceUri() const { return m_namespaceUri; } + inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const { + return (prefix() == other.prefix() && namespaceUri() == other.namespaceUri()); + } + inline bool operator!=(const QXmlStreamNamespaceDeclaration &other) const + { return !operator==(other); } +}; + +Q_DECLARE_TYPEINFO(QXmlStreamNamespaceDeclaration, Q_MOVABLE_TYPE); +typedef QVector<QXmlStreamNamespaceDeclaration> QXmlStreamNamespaceDeclarations; + +class Q_XMLSTREAM_EXPORT QXmlStreamNotationDeclaration { + QXmlStreamStringRef m_name, m_systemId, m_publicId; + void *reserved; + + friend class QXmlStreamReaderPrivate; +public: + QXmlStreamNotationDeclaration(); + ~QXmlStreamNotationDeclaration(); + QXmlStreamNotationDeclaration(const QXmlStreamNotationDeclaration &); + QXmlStreamNotationDeclaration& operator=(const QXmlStreamNotationDeclaration &); + inline QStringRef name() const { return m_name; } + inline QStringRef systemId() const { return m_systemId; } + inline QStringRef publicId() const { return m_publicId; } + inline bool operator==(const QXmlStreamNotationDeclaration &other) const { + return (name() == other.name() && systemId() == other.systemId() + && publicId() == other.publicId()); + } + inline bool operator!=(const QXmlStreamNotationDeclaration &other) const + { return !operator==(other); } +}; + +Q_DECLARE_TYPEINFO(QXmlStreamNotationDeclaration, Q_MOVABLE_TYPE); +typedef QVector<QXmlStreamNotationDeclaration> QXmlStreamNotationDeclarations; + +class Q_XMLSTREAM_EXPORT QXmlStreamEntityDeclaration { + QXmlStreamStringRef m_name, m_notationName, m_systemId, m_publicId, m_value; + void *reserved; + + friend class QXmlStreamReaderPrivate; +public: + QXmlStreamEntityDeclaration(); + ~QXmlStreamEntityDeclaration(); + QXmlStreamEntityDeclaration(const QXmlStreamEntityDeclaration &); + QXmlStreamEntityDeclaration& operator=(const QXmlStreamEntityDeclaration &); + inline QStringRef name() const { return m_name; } + inline QStringRef notationName() const { return m_notationName; } + inline QStringRef systemId() const { return m_systemId; } + inline QStringRef publicId() const { return m_publicId; } + inline QStringRef value() const { return m_value; } + inline bool operator==(const QXmlStreamEntityDeclaration &other) const { + return (name() == other.name() + && notationName() == other.notationName() + && systemId() == other.systemId() + && publicId() == other.publicId() + && value() == other.value()); + } + inline bool operator!=(const QXmlStreamEntityDeclaration &other) const + { return !operator==(other); } +}; + +Q_DECLARE_TYPEINFO(QXmlStreamEntityDeclaration, Q_MOVABLE_TYPE); +typedef QVector<QXmlStreamEntityDeclaration> QXmlStreamEntityDeclarations; + + +class Q_XMLSTREAM_EXPORT QXmlStreamEntityResolver +{ +public: + virtual ~QXmlStreamEntityResolver(); + virtual QString resolveEntity(const QString& publicId, const QString& systemId); + virtual QString resolveUndeclaredEntity(const QString &name); +}; + +#ifndef QT_NO_XMLSTREAMREADER +class Q_XMLSTREAM_EXPORT QXmlStreamReader { + QDOC_PROPERTY(bool namespaceProcessing READ namespaceProcessing WRITE setNamespaceProcessing) +public: + enum TokenType { + NoToken = 0, + Invalid, + StartDocument, + EndDocument, + StartElement, + EndElement, + Characters, + Comment, + DTD, + EntityReference, + ProcessingInstruction + }; + + + QXmlStreamReader(); + QXmlStreamReader(QIODevice *device); + QXmlStreamReader(const QByteArray &data); + QXmlStreamReader(const QString &data); + QXmlStreamReader(const char * data); + ~QXmlStreamReader(); + + void setDevice(QIODevice *device); + QIODevice *device() const; + void addData(const QByteArray &data); + void addData(const QString &data); + void addData(const char *data); + void clear(); + + + bool atEnd() const; + TokenType readNext(); + + TokenType tokenType() const; + QString tokenString() const; + + void setNamespaceProcessing(bool); + bool namespaceProcessing() const; + + inline bool isStartDocument() const { return tokenType() == StartDocument; } + inline bool isEndDocument() const { return tokenType() == EndDocument; } + inline bool isStartElement() const { return tokenType() == StartElement; } + inline bool isEndElement() const { return tokenType() == EndElement; } + inline bool isCharacters() const { return tokenType() == Characters; } + bool isWhitespace() const; + bool isCDATA() const; + inline bool isComment() const { return tokenType() == Comment; } + inline bool isDTD() const { return tokenType() == DTD; } + inline bool isEntityReference() const { return tokenType() == EntityReference; } + inline bool isProcessingInstruction() const { return tokenType() == ProcessingInstruction; } + + bool isStandaloneDocument() const; + QStringRef documentVersion() const; + QStringRef documentEncoding() const; + + qint64 lineNumber() const; + qint64 columnNumber() const; + qint64 characterOffset() const; + + QXmlStreamAttributes attributes() const; + QString readElementText(); + + QStringRef name() const; + QStringRef namespaceUri() const; + QStringRef qualifiedName() const; + QStringRef prefix() const; + + QStringRef processingInstructionTarget() const; + QStringRef processingInstructionData() const; + + QStringRef text() const; + + QXmlStreamNamespaceDeclarations namespaceDeclarations() const; + void addExtraNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaraction); + void addExtraNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &extraNamespaceDeclaractions); + QXmlStreamNotationDeclarations notationDeclarations() const; + QXmlStreamEntityDeclarations entityDeclarations() const; + QStringRef dtdName() const; + QStringRef dtdPublicId() const; + QStringRef dtdSystemId() const; + + + enum Error { + NoError, + UnexpectedElementError, + CustomError, + NotWellFormedError, + PrematureEndOfDocumentError + }; + void raiseError(const QString& message = QString()); + QString errorString() const; + Error error() const; + + inline bool hasError() const + { + return error() != NoError; + } + + void setEntityResolver(QXmlStreamEntityResolver *resolver); + QXmlStreamEntityResolver *entityResolver() const; + +private: + Q_DISABLE_COPY(QXmlStreamReader) + Q_DECLARE_PRIVATE(QXmlStreamReader) + QXmlStreamReaderPrivate *d_ptr; + +}; +#endif // QT_NO_XMLSTREAMREADER + +#ifndef QT_NO_XMLSTREAMWRITER + +class QXmlStreamWriterPrivate; + +class Q_XMLSTREAM_EXPORT QXmlStreamWriter +{ + QDOC_PROPERTY(bool autoFormatting READ autoFormatting WRITE setAutoFormatting) + QDOC_PROPERTY(int autoFormattingIndent READ autoFormattingIndent WRITE setAutoFormattingIndent) +public: + QXmlStreamWriter(); + QXmlStreamWriter(QIODevice *device); + QXmlStreamWriter(QByteArray *array); + QXmlStreamWriter(QString *string); + ~QXmlStreamWriter(); + + void setDevice(QIODevice *device); + QIODevice *device() const; + +#ifndef QT_NO_TEXTCODEC + void setCodec(QTextCodec *codec); + void setCodec(const char *codecName); + QTextCodec *codec() const; +#endif + + void setAutoFormatting(bool); + bool autoFormatting() const; + + void setAutoFormattingIndent(int spacesOrTabs); + int autoFormattingIndent() const; + + void writeAttribute(const QString &qualifiedName, const QString &value); + void writeAttribute(const QString &namespaceUri, const QString &name, const QString &value); + void writeAttribute(const QXmlStreamAttribute& attribute); + void writeAttributes(const QXmlStreamAttributes& attributes); + + void writeCDATA(const QString &text); + void writeCharacters(const QString &text); + void writeComment(const QString &text); + + void writeDTD(const QString &dtd); + + void writeEmptyElement(const QString &qualifiedName); + void writeEmptyElement(const QString &namespaceUri, const QString &name); + + void writeTextElement(const QString &qualifiedName, const QString &text); + void writeTextElement(const QString &namespaceUri, const QString &name, const QString &text); + + void writeEndDocument(); + void writeEndElement(); + + void writeEntityReference(const QString &name); + void writeNamespace(const QString &namespaceUri, const QString &prefix = QString()); + void writeDefaultNamespace(const QString &namespaceUri); + void writeProcessingInstruction(const QString &target, const QString &data = QString()); + + void writeStartDocument(); + void writeStartDocument(const QString &version); + void writeStartDocument(const QString &version, bool standalone); + void writeStartElement(const QString &qualifiedName); + void writeStartElement(const QString &namespaceUri, const QString &name); + +#ifndef QT_NO_XMLSTREAMREADER + void writeCurrentToken(const QXmlStreamReader &reader); +#endif + +private: + Q_DISABLE_COPY(QXmlStreamWriter) + Q_DECLARE_PRIVATE(QXmlStreamWriter) + QXmlStreamWriterPrivate *d_ptr; +}; +#endif // QT_NO_XMLSTREAMWRITER + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_XMLSTREAM +#endif // QXMLSTREAM_H diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h new file mode 100644 index 0000000..201f0c1 --- /dev/null +++ b/src/corelib/xml/qxmlstream_p.h @@ -0,0 +1,1962 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QXMLSTREAM_P_H +#define QXMLSTREAM_P_H + +class QXmlStreamReader_Table +{ +public: + enum { + EOF_SYMBOL = 0, + AMPERSAND = 5, + ANY = 41, + ATTLIST = 31, + BANG = 25, + CDATA = 47, + CDATA_START = 28, + COLON = 17, + COMMA = 19, + DASH = 20, + DBLQUOTE = 8, + DIGIT = 27, + DOCTYPE = 29, + DOT = 23, + ELEMENT = 30, + EMPTY = 40, + ENTITIES = 51, + ENTITY = 32, + ENTITY_DONE = 45, + EQ = 14, + ERROR = 43, + FIXED = 39, + HASH = 6, + ID = 48, + IDREF = 49, + IDREFS = 50, + IMPLIED = 38, + LANGLE = 3, + LBRACK = 9, + LETTER = 26, + LPAREN = 11, + NDATA = 36, + NMTOKEN = 52, + NMTOKENS = 53, + NOTATION = 33, + NOTOKEN = 1, + PARSE_ENTITY = 44, + PCDATA = 42, + PERCENT = 15, + PIPE = 13, + PLUS = 21, + PUBLIC = 35, + QUESTIONMARK = 24, + QUOTE = 7, + RANGLE = 4, + RBRACK = 10, + REQUIRED = 37, + RPAREN = 12, + SEMICOLON = 18, + SHIFT_THERE = 56, + SLASH = 16, + SPACE = 2, + STAR = 22, + SYSTEM = 34, + UNRESOLVED_ENTITY = 46, + VERSION = 55, + XML = 54, + + ACCEPT_STATE = 416, + RULE_COUNT = 269, + STATE_COUNT = 427, + TERMINAL_COUNT = 57, + NON_TERMINAL_COUNT = 84, + + GOTO_INDEX_OFFSET = 427, + GOTO_INFO_OFFSET = 1017, + GOTO_CHECK_OFFSET = 1017 + }; + + static const char *const spell []; + static const int lhs []; + static const int rhs []; + static const int goto_default []; + static const int action_default []; + static const int action_index []; + static const int action_info []; + static const int action_check []; + + static inline int nt_action (int state, int nt) + { + const int *const goto_index = &action_index [GOTO_INDEX_OFFSET]; + const int *const goto_check = &action_check [GOTO_CHECK_OFFSET]; + + const int yyn = goto_index [state] + nt; + + if (yyn < 0 || goto_check [yyn] != nt) + return goto_default [nt]; + + const int *const goto_info = &action_info [GOTO_INFO_OFFSET]; + return goto_info [yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +const char *const QXmlStreamReader_Table::spell [] = { + "end of file", 0, " ", "<", ">", "&", "#", "\'", "\"", "[", + "]", "(", ")", "|", "=", "%", "/", ":", ";", ",", + "-", "+", "*", ".", "?", "!", "[a-zA-Z]", "[0-9]", "[CDATA[", "DOCTYPE", + "ELEMENT", "ATTLIST", "ENTITY", "NOTATION", "SYSTEM", "PUBLIC", "NDATA", "REQUIRED", "IMPLIED", "FIXED", + "EMPTY", "ANY", "PCDATA", 0, 0, 0, 0, "CDATA", "ID", "IDREF", + "IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", "<?xml", "version", 0}; + +const int QXmlStreamReader_Table::lhs [] = { + 57, 57, 59, 59, 59, 59, 59, 59, 59, 59, + 67, 68, 64, 72, 72, 72, 75, 66, 66, 66, + 66, 79, 78, 80, 80, 80, 80, 80, 80, 81, + 81, 81, 81, 81, 81, 81, 87, 83, 88, 88, + 88, 88, 91, 92, 93, 93, 93, 93, 94, 94, + 96, 96, 96, 97, 97, 98, 98, 99, 99, 100, + 100, 89, 89, 95, 90, 101, 101, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 104, 105, 105, + 105, 105, 107, 108, 109, 109, 84, 84, 110, 110, + 112, 112, 85, 85, 85, 65, 65, 76, 114, 63, + 115, 116, 86, 86, 86, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 118, 118, + 119, 119, 119, 119, 119, 119, 119, 119, 122, 70, + 70, 70, 70, 123, 124, 123, 124, 123, 124, 123, + 124, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 125, 73, 113, 113, 113, 113, 127, + 128, 127, 128, 127, 128, 127, 128, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 106, 106, 106, 106, 131, 132, 131, 132, + 131, 131, 132, 132, 133, 133, 133, 133, 135, 71, + 71, 71, 136, 136, 137, 62, 60, 61, 138, 121, + 82, 130, 134, 120, 139, 139, 139, 139, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 74, 69, + 69, 77, 111, 102, 102, 102, 102, 102, 140}; + +const int QXmlStreamReader_Table:: rhs[] = { + 2, 1, 4, 2, 2, 2, 2, 2, 2, 0, + 1, 1, 9, 2, 4, 0, 4, 4, 6, 6, + 4, 1, 3, 1, 1, 1, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 0, 2, 2, + 2, 6, 6, 1, 5, 1, 5, 3, 5, 0, + 1, 6, 8, 4, 2, 1, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 6, 7, 1, 2, 2, + 1, 4, 3, 3, 1, 2, 5, 6, 4, 6, + 3, 5, 5, 3, 4, 4, 5, 2, 3, 2, + 2, 4, 5, 5, 7, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, + 2, 3, 3, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 3, 3, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 3, 3, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, + 1, 3, 1, 3, 2, 4, 3, 5, 1, 3, + 3, 3, 3, 4, 1, 1, 2, 2, 2, 4, + 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2}; + +const int QXmlStreamReader_Table::action_default [] = { + 10, 258, 0, 2, 1, 0, 124, 116, 118, 119, + 126, 128, 122, 11, 113, 107, 0, 108, 127, 110, + 114, 112, 120, 123, 125, 106, 109, 111, 117, 115, + 130, 121, 239, 12, 253, 135, 249, 252, 0, 129, + 139, 256, 16, 251, 137, 136, 0, 255, 138, 258, + 230, 257, 254, 0, 0, 263, 0, 246, 245, 0, + 248, 247, 244, 240, 98, 262, 0, 235, 0, 0, + 259, 96, 97, 100, 0, 131, 133, 132, 134, 0, + 0, 260, 0, 0, 175, 0, 172, 164, 166, 167, + 141, 153, 170, 161, 155, 156, 152, 158, 162, 160, + 168, 171, 151, 154, 157, 159, 165, 163, 173, 169, + 149, 174, 0, 143, 147, 145, 150, 140, 148, 0, + 146, 142, 144, 0, 15, 14, 261, 0, 22, 21, + 260, 0, 0, 20, 0, 0, 31, 36, 30, 0, + 32, 260, 0, 33, 0, 24, 0, 34, 0, 26, + 35, 25, 0, 241, 40, 39, 260, 42, 48, 260, + 41, 0, 43, 260, 48, 260, 0, 260, 0, 48, + 0, 47, 45, 46, 50, 51, 260, 260, 0, 56, + 260, 53, 260, 0, 57, 0, 54, 260, 52, 260, + 0, 55, 64, 0, 260, 60, 260, 0, 58, 61, + 62, 0, 260, 0, 0, 59, 63, 44, 49, 65, + 0, 38, 0, 0, 260, 0, 93, 94, 0, 0, + 0, 0, 260, 0, 209, 200, 202, 204, 177, 189, + 207, 198, 192, 190, 193, 188, 195, 197, 205, 208, + 187, 191, 194, 196, 201, 199, 203, 206, 210, 212, + 211, 185, 0, 0, 242, 179, 183, 181, 0, 0, + 92, 186, 176, 184, 0, 182, 178, 180, 91, 0, + 95, 0, 0, 0, 0, 0, 260, 85, 260, 0, + 261, 0, 86, 0, 88, 68, 73, 72, 69, 70, + 71, 260, 74, 75, 0, 0, 0, 268, 267, 265, + 266, 264, 66, 260, 0, 260, 0, 0, 67, 76, + 260, 0, 260, 0, 0, 77, 0, 78, 0, 81, + 84, 0, 0, 214, 224, 223, 0, 226, 228, 227, + 225, 0, 243, 216, 220, 218, 222, 213, 221, 0, + 219, 215, 217, 0, 80, 79, 0, 82, 0, 83, + 87, 99, 0, 37, 0, 0, 0, 0, 90, 89, + 0, 102, 23, 27, 29, 28, 0, 0, 260, 261, + 0, 260, 0, 105, 104, 260, 0, 103, 101, 0, + 0, 18, 260, 17, 0, 19, 0, 0, 250, 0, + 260, 0, 238, 0, 231, 237, 0, 236, 233, 260, + 260, 261, 232, 234, 0, 260, 0, 229, 260, 0, + 260, 0, 230, 0, 0, 13, 269, 9, 5, 8, + 4, 0, 7, 258, 6, 0, 3}; + +const int QXmlStreamReader_Table::goto_default [] = { + 2, 4, 3, 49, 388, 43, 37, 52, 47, 41, + 249, 53, 127, 84, 393, 81, 85, 126, 42, 46, + 169, 130, 131, 146, 145, 149, 138, 136, 140, 147, + 139, 159, 160, 157, 168, 167, 209, 165, 164, 166, + 187, 180, 196, 200, 303, 302, 295, 321, 320, 319, + 279, 277, 278, 142, 56, 141, 222, 38, 34, 148, + 39, 48, 40, 248, 45, 36, 119, 112, 330, 111, + 264, 252, 251, 250, 339, 326, 325, 329, 398, 399, + 50, 51, 59, 0}; + +const int QXmlStreamReader_Table::action_index [] = { + -21, -57, 33, 119, 960, 70, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, 105, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, 40, -57, + 795, -57, 47, -57, -57, -57, 107, -57, -57, -57, + 84, -57, -57, -38, 80, -57, 12, -57, -57, 97, + -57, -57, -57, -57, -57, -57, 13, -57, 56, 34, + -57, -57, -57, -57, 51, -57, -57, -57, -57, 53, + 57, 84, 300, 255, -57, 84, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, 355, -57, -57, -57, -57, -57, -57, 326, + -57, -57, -57, 48, -57, -57, -57, 50, -57, -57, + 84, 155, 32, -57, 38, 22, -57, -57, -57, 115, + -57, 35, 156, -57, 173, -57, 245, -57, 44, -57, + -57, -57, 16, -57, -57, -57, 29, -57, 116, 29, + -57, 133, -57, 29, 129, 84, 15, 29, -22, 121, + 74, -57, -57, -57, -57, 82, 29, 29, 88, -57, + 29, 7, 29, 86, -57, 83, -57, 27, 19, 26, + 94, -57, -57, 106, 29, 3, 29, -8, -57, -57, + -57, 104, 29, -6, -7, -57, -57, -57, -57, -57, + 17, -57, -2, 11, 29, 18, -57, -57, 850, 65, + 465, 67, 84, 135, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, 630, 24, -57, -57, -57, -57, 84, 76, + -57, -57, -57, -57, 740, -57, -57, -57, -57, 39, + -57, 23, 21, 14, 78, 22, 84, -57, 84, 184, + 20, 31, -57, 41, -57, -57, -57, -57, -57, -57, + -57, 84, -57, -57, 36, 126, 162, -57, -57, -57, + -57, -57, -57, 29, 79, 29, 29, 160, -57, -57, + 29, 145, 29, 75, 29, -57, 575, -57, 410, -57, + -57, 110, 64, -57, -57, -57, 685, -57, -57, -57, + -57, -17, -57, -57, -57, -57, -57, -57, -57, 520, + -57, -57, -57, 29, -57, -57, 61, -57, 29, -57, + -57, -57, 29, -57, 29, 29, -15, 29, -57, -57, + 29, -57, -57, -57, -57, -57, 95, 43, 29, 45, + 9, 29, 10, -57, -57, 29, 2, -57, -57, -24, + 190, -57, 29, -57, 1, -57, 905, 150, -57, -26, + 29, 0, -57, 109, -26, -57, 8, -57, -57, 29, + 29, -19, -57, -57, -11, 29, 59, -57, 29, -5, + 29, 103, 29, -16, 6, -57, -57, -57, -57, -57, + -57, 69, -57, -57, -57, 905, -57, + + -84, -84, -84, 204, 75, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, 7, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + 101, -84, -84, -84, -84, -84, -84, -84, -84, 64, + 54, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, 68, -84, 30, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + 32, -84, -16, -7, -84, 42, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, 45, -84, -84, -84, -84, -84, -84, 44, + -84, -84, -84, 33, -84, -84, -84, -84, -84, -84, + 36, 108, -84, -84, -84, 69, -84, -84, -84, 62, + -84, 63, -84, -84, -84, -84, 118, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -2, -84, -84, -10, + -84, -84, -84, 25, -21, 11, -84, 20, -84, -25, + -84, -84, -84, -84, -84, -84, 1, 2, -36, -84, + -9, -84, 5, -13, -84, -8, -84, 6, -84, 8, + 12, -84, -84, -84, 23, -84, 4, -1, -84, -84, + -84, -84, 0, -84, -14, -84, -84, -84, -84, -84, + -84, -84, 55, -84, 58, -84, -84, -84, -84, 53, + 47, 123, 67, 66, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -15, -84, -84, -84, -84, -84, 41, 40, + -84, -84, -84, -84, -46, -84, -84, -84, -84, -84, + -84, 35, -84, 34, 37, 18, 70, -84, 89, -84, + 43, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, 48, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, 31, -84, 29, 27, 17, -84, -84, + 38, 24, 39, -84, 49, -84, 71, -84, 93, -84, + -84, -84, -12, -84, -84, -84, 94, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, 78, + -84, -84, -84, 50, -84, -84, 46, -84, 56, -84, + -84, -84, 60, -84, 61, 59, 51, 57, -84, -84, + 14, -84, -84, -84, -84, -84, -11, -6, 72, -5, + -84, -3, -84, -84, -84, 52, -84, -84, -84, -20, + 77, -84, 21, -84, -84, -84, 76, 16, -84, 19, + 26, -84, -84, -84, 10, -84, -84, -84, -84, 80, + 13, 73, -84, -84, -84, 22, -27, -84, 9, -84, + 28, 15, 82, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, 3, -84, 98, -84}; + +const int QXmlStreamReader_Table::action_info [] = { + 65, 332, 65, 405, 392, 385, 377, 65, 414, 410, + 415, 55, 397, 374, 373, 217, 206, 408, 65, 65, + 207, 211, 216, 1, 55, 199, 182, 192, 70, 70, + 63, 70, 189, 416, 153, 350, 133, 70, 72, 55, + 65, 351, 254, 270, 73, 284, 65, 310, 55, 65, + 83, 82, 83, 82, 129, 83, 82, 54, 70, 128, + 83, 82, 66, 64, 83, 82, 318, 316, 318, 316, + 54, 212, 83, 82, 83, 82, 54, 55, 367, 366, + 69, 80, 79, 83, 82, 163, 70, 314, 305, 272, + 55, 306, 305, 354, 163, 177, 55, 163, 379, 163, + 65, 176, 83, 82, 55, 163, 58, 57, 0, 65, + 83, 82, 65, 395, 65, 62, 203, 202, 195, 194, + 65, 417, 16, 61, 60, 396, 156, 272, 0, 66, + 64, 65, 317, 318, 316, 378, 379, 171, 173, 162, + 172, 54, 171, 173, 163, 172, 0, 345, 344, 343, + 171, 173, 0, 172, 0, 155, 154, 70, 134, 65, + 0, 55, 297, 220, 218, 298, 389, 0, 300, 0, + 135, 301, 299, 33, 66, 64, 65, 297, 0, 297, + 298, 0, 298, 300, 0, 300, 301, 299, 301, 299, + 221, 219, 70, 272, 381, 291, 0, 0, 0, 128, + 13, 0, 0, 273, 271, 274, 275, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 287, 294, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 285, 288, 289, 290, 286, 292, 293, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 70, 134, 0, + 0, 0, 0, 0, 0, 362, 0, 108, 0, 103, + 135, 94, 117, 116, 95, 104, 97, 105, 99, 93, + 98, 107, 87, 106, 88, 89, 100, 109, 92, 101, + 86, 96, 91, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 103, 0, 94, 102, 90, 95, + 104, 97, 105, 99, 93, 98, 107, 87, 106, 88, + 89, 100, 109, 92, 101, 86, 96, 91, 108, 0, + 103, 0, 94, 121, 120, 95, 104, 97, 105, 99, + 93, 98, 107, 87, 106, 88, 89, 100, 109, 92, + 101, 86, 96, 91, 0, 0, 0, 108, 0, 103, + 0, 94, 114, 113, 95, 104, 97, 105, 99, 93, + 98, 107, 87, 106, 88, 89, 100, 109, 92, 101, + 86, 96, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 103, 322, 94, 337, 336, 95, + 104, 97, 105, 99, 93, 98, 107, 87, 106, 88, + 89, 100, 109, 92, 101, 86, 96, 91, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 246, 233, 241, + 223, 232, 262, 261, 234, 242, 236, 243, 237, 231, + 0, 245, 225, 244, 226, 227, 238, 247, 230, 239, + 224, 235, 229, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 103, 322, 94, 341, 340, 95, + 104, 97, 105, 99, 93, 98, 107, 87, 106, 88, + 89, 100, 109, 92, 101, 86, 96, 91, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 103, + 322, 94, 324, 323, 95, 104, 97, 105, 99, 93, + 98, 107, 87, 106, 88, 89, 100, 109, 92, 101, + 86, 96, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 246, 233, 241, 223, 232, 256, 255, 234, + 242, 236, 243, 237, 231, 0, 245, 225, 244, 226, + 227, 238, 247, 230, 239, 224, 235, 229, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 103, + 322, 94, 334, 333, 95, 104, 97, 105, 99, 93, + 98, 107, 87, 106, 88, 89, 100, 109, 92, 101, + 86, 96, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 246, 233, 241, 223, 232, 266, 265, 234, + 242, 236, 243, 237, 231, 0, 245, 225, 244, 226, + 227, 238, 247, 230, 239, 224, 235, 229, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 0, 25, + 74, 15, 24, 10, 17, 26, 19, 27, 21, 14, + 20, 29, 7, 28, 8, 9, 22, 31, 12, 23, + 6, 18, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 246, 233, 241, 223, 232, 240, 228, 234, + 242, 236, 243, 237, 231, 0, 245, 225, 244, 226, + 227, 238, 247, 230, 239, 224, 235, 229, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 387, 25, + 5, 15, 24, 10, 17, 26, 19, 27, 21, 14, + 20, 29, 7, 28, 8, 9, 22, 31, 12, 23, + 6, 18, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 32, 0, 0, 0, 0, 0, 0, 0, 33, + 0, 0, 30, 16, 25, 5, 15, 24, 10, 17, + 26, 19, 27, 21, 14, 20, 29, 7, 28, 8, + 9, 22, 31, 12, 23, 6, 18, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 32, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, + + 380, 179, 210, 181, 425, 368, 205, 375, 371, 372, + 161, 208, 204, 178, 185, 174, 201, 183, 188, 198, + 190, 409, 407, 175, 184, 404, 267, 67, 412, 186, + 400, 361, 193, 384, 406, 197, 67, 170, 391, 390, + 411, 307, 331, 304, 309, 125, 124, 71, 132, 191, + 311, 313, 110, 260, 352, 276, 0, 257, 259, 123, + 296, 118, 308, 348, 376, 386, 315, 346, 312, 258, + 215, 394, 360, 349, 358, 213, 359, 353, 356, 269, + 0, 328, 281, 0, 370, 44, 44, 280, 328, 369, + 0, 355, 402, 400, 383, 347, 413, 401, 382, 394, + 158, 283, 426, 328, 328, 357, 280, 0, 44, 214, + 0, 76, 122, 115, 137, 0, 150, 0, 143, 263, + 253, 0, 68, 152, 137, 151, 150, 144, 143, 0, + 0, 0, 0, 0, 327, 365, 268, 144, 35, 35, + 282, 327, 363, 364, 0, 0, 0, 0, 0, 0, + 0, 403, 0, 0, 342, 0, 327, 327, 0, 0, + 0, 35, 78, 0, 75, 77, 0, 0, 0, 338, + 335, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 423, 0, 420, + 418, 424, 422, 419, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 421, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + +const int QXmlStreamReader_Table::action_check [] = { + 26, 18, 26, 14, 4, 4, 4, 26, 24, 14, + 4, 26, 4, 4, 4, 4, 22, 55, 26, 26, + 42, 4, 4, 44, 26, 22, 19, 12, 2, 2, + 18, 2, 13, 0, 18, 4, 4, 2, 4, 26, + 26, 20, 18, 4, 4, 4, 26, 11, 26, 26, + 7, 8, 7, 8, 4, 7, 8, 6, 2, 9, + 7, 8, 24, 25, 7, 8, 7, 8, 7, 8, + 6, 36, 7, 8, 7, 8, 6, 26, 34, 35, + 24, 34, 35, 7, 8, 11, 2, 12, 13, 20, + 26, 12, 13, 15, 11, 13, 26, 11, 29, 11, + 26, 19, 7, 8, 26, 11, 26, 27, -1, 26, + 7, 8, 26, 4, 26, 18, 12, 13, 12, 13, + 26, 2, 3, 26, 27, 16, 11, 20, -1, 24, + 25, 26, 6, 7, 8, 28, 29, 21, 22, 6, + 24, 6, 21, 22, 11, 24, -1, 37, 38, 39, + 21, 22, -1, 24, -1, 40, 41, 2, 3, 26, + -1, 26, 17, 7, 8, 20, 16, -1, 23, -1, + 15, 26, 27, 54, 24, 25, 26, 17, -1, 17, + 20, -1, 20, 23, -1, 23, 26, 27, 26, 27, + 34, 35, 2, 20, 4, 11, -1, -1, -1, 9, + 45, -1, -1, 30, 31, 32, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 32, 33, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 47, 48, 49, 50, 51, 52, 53, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, 3, -1, + -1, -1, -1, -1, -1, 10, -1, 2, -1, 4, + 15, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, -1, 4, -1, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 2, -1, + 4, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, -1, -1, -1, 2, -1, 4, + -1, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, -1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + -1, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, -1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, -1, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, -1, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, -1, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, -1, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, -1, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, -1, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, 46, -1, -1, -1, -1, -1, -1, -1, 54, + -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 45, 46, -1, -1, -1, + -1, -1, -1, -1, 54, -1, -1, + + 20, 37, 12, 12, 1, 16, 20, 13, 13, 12, + 12, 36, 12, 12, 12, 36, 12, 12, 12, 20, + 12, 12, 49, 12, 37, 12, 72, 20, 13, 37, + 20, 17, 12, 12, 12, 12, 20, 12, 12, 20, + 12, 12, 54, 12, 17, 13, 13, 17, 12, 37, + 12, 12, 68, 13, 20, 20, -1, 72, 17, 17, + 12, 68, 45, 20, 12, 1, 17, 17, 44, 16, + 12, 17, 54, 17, 17, 12, 17, 17, 17, 12, + -1, 10, 12, -1, 12, 10, 10, 17, 10, 17, + -1, 54, 12, 20, 17, 49, 14, 17, 21, 17, + 38, 12, 4, 10, 10, 54, 17, -1, 10, 54, + -1, 10, 68, 68, 6, -1, 8, -1, 10, 72, + 54, -1, 54, 54, 6, 17, 8, 19, 10, -1, + -1, -1, -1, -1, 63, 17, 13, 19, 63, 63, + 51, 63, 24, 25, -1, -1, -1, -1, -1, -1, + -1, 78, -1, -1, 76, -1, 63, 63, -1, -1, + -1, 63, 61, -1, 63, 64, -1, -1, -1, 76, + 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3, -1, 5, + 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; + + +template <typename T> class QXmlStreamSimpleStack { + T *data; + int tos, cap; +public: + inline QXmlStreamSimpleStack():data(0), tos(-1), cap(0){} + inline ~QXmlStreamSimpleStack(){ if (data) qFree(data); } + + inline void reserve(int extraCapacity) { + if (tos + extraCapacity + 1 > cap) { + cap = qMax(tos + extraCapacity + 1, cap << 1 ); + data = reinterpret_cast<T *>(qRealloc(data, cap * sizeof(T))); + } + } + + inline T &push() { reserve(1); return data[++tos]; } + inline T &rawPush() { return data[++tos]; } + inline const T &top() const { return data[tos]; } + inline T &top() { return data[tos]; } + inline T &pop() { return data[tos--]; } + inline T &operator[](int index) { return data[index]; } + inline const T &at(int index) const { return data[index]; } + inline int size() const { return tos + 1; } + inline void resize(int s) { tos = s - 1; } + inline bool isEmpty() const { return tos < 0; } + inline void clear() { tos = -1; } +}; + + +class QXmlStream +{ + Q_DECLARE_TR_FUNCTIONS(QXmlStream) +}; + +class QXmlStreamPrivateTagStack { +public: + struct NamespaceDeclaration + { + QStringRef prefix; + QStringRef namespaceUri; + }; + + struct Tag + { + QStringRef name; + QStringRef qualifiedName; + NamespaceDeclaration namespaceDeclaration; + int tagStackStringStorageSize; + int namespaceDeclarationsSize; + }; + + + QXmlStreamPrivateTagStack(); + QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations; + QString tagStackStringStorage; + int tagStackStringStorageSize; + bool tagsDone; + + inline QStringRef addToStringStorage(const QStringRef &s) { + int pos = tagStackStringStorageSize; + int sz = s.size(); + if (pos != tagStackStringStorage.size()) + tagStackStringStorage.resize(pos); + tagStackStringStorage.insert(pos, s.unicode(), sz); + tagStackStringStorageSize += sz; + return QStringRef(&tagStackStringStorage, pos, sz); + } + inline QStringRef addToStringStorage(const QString &s) { + int pos = tagStackStringStorageSize; + int sz = s.size(); + if (pos != tagStackStringStorage.size()) + tagStackStringStorage.resize(pos); + tagStackStringStorage.insert(pos, s.unicode(), sz); + tagStackStringStorageSize += sz; + return QStringRef(&tagStackStringStorage, pos, sz); + } + + QXmlStreamSimpleStack<Tag> tagStack; + + + inline Tag &tagStack_pop() { + Tag& tag = tagStack.pop(); + tagStackStringStorageSize = tag.tagStackStringStorageSize; + namespaceDeclarations.resize(tag.namespaceDeclarationsSize); + tagsDone = tagStack.isEmpty(); + return tag; + } + inline Tag &tagStack_push() { + Tag &tag = tagStack.push(); + tag.tagStackStringStorageSize = tagStackStringStorageSize; + tag.namespaceDeclarationsSize = namespaceDeclarations.size(); + return tag; + } +}; + + +class QXmlStreamEntityResolver; + +class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{ + QXmlStreamReader *q_ptr; + Q_DECLARE_PUBLIC(QXmlStreamReader) +public: + QXmlStreamReaderPrivate(QXmlStreamReader *q); + ~QXmlStreamReaderPrivate(); + void init(); + + QByteArray rawReadBuffer; + QByteArray dataBuffer; + uchar firstByte; + qint64 nbytesread; + QString readBuffer; + int readBufferPos; + QXmlStreamSimpleStack<uint> putStack; + struct Entity { + Entity(const QString& str = QString()) + :value(str), external(false), unparsed(false), literal(false), + hasBeenParsed(false), isCurrentlyReferenced(false){} + static inline Entity createLiteral(const QString &entity) + { Entity result(entity); result.literal = result.hasBeenParsed = true; return result; } + QString value; + uint external : 1; + uint unparsed : 1; + uint literal : 1; + uint hasBeenParsed : 1; + uint isCurrentlyReferenced : 1; + }; + QHash<QString, Entity> entityHash; + QHash<QString, Entity> parameterEntityHash; + QXmlStreamSimpleStack<Entity *>entityReferenceStack; + inline bool referenceEntity(Entity &entity) { + if (entity.isCurrentlyReferenced) { + raiseWellFormedError(QXmlStream::tr("Recursive entity detected.")); + return false; + } + entity.isCurrentlyReferenced = true; + entityReferenceStack.push() = &entity; + injectToken(ENTITY_DONE); + return true; + } + + + QIODevice *device; + bool deleteDevice; +#ifndef QT_NO_TEXTCODEC + QTextCodec *codec; + QTextDecoder *decoder; +#endif + bool atEnd; + + /*! + \sa setType() + */ + QXmlStreamReader::TokenType type; + QXmlStreamReader::Error error; + QString errorString; + QString unresolvedEntity; + + qint64 lineNumber, lastLineStart, characterOffset; + + + void write(const QString &); + void write(const char *); + + + QXmlStreamAttributes attributes; + QStringRef namespaceForPrefix(const QStringRef &prefix); + void resolveTag(); + void resolvePublicNamespaces(); + void resolveDtd(); + uint resolveCharRef(int symbolIndex); + bool checkStartDocument(); + void startDocument(); + void parseError(); + void checkPublicLiteral(const QStringRef &publicId); + + bool scanDtd; + QStringRef lastAttributeValue; + bool lastAttributeIsCData; + struct DtdAttribute { + QStringRef tagName; + QStringRef attributeQualifiedName; + QStringRef attributePrefix; + QStringRef attributeName; + QStringRef defaultValue; + bool isCDATA; + bool isNamespaceAttribute; + }; + QXmlStreamSimpleStack<DtdAttribute> dtdAttributes; + struct NotationDeclaration { + QStringRef name; + QStringRef publicId; + QStringRef systemId; + }; + QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations; + QXmlStreamNotationDeclarations publicNotationDeclarations; + QXmlStreamNamespaceDeclarations publicNamespaceDeclarations; + + struct EntityDeclaration { + QStringRef name; + QStringRef notationName; + QStringRef publicId; + QStringRef systemId; + QStringRef value; + bool parameter; + bool external; + inline void clear() { + name.clear(); + notationName.clear(); + publicId.clear(); + systemId.clear(); + value.clear(); + parameter = external = false; + } + }; + QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations; + QXmlStreamEntityDeclarations publicEntityDeclarations; + + QStringRef text; + + QStringRef prefix, namespaceUri, qualifiedName, name; + QStringRef processingInstructionTarget, processingInstructionData; + QStringRef dtdName, dtdPublicId, dtdSystemId; + QStringRef documentVersion, documentEncoding; + uint isEmptyElement : 1; + uint isWhitespace : 1; + uint isCDATA : 1; + uint standalone : 1; + uint hasCheckedStartDocument : 1; + uint normalizeLiterals : 1; + uint hasSeenTag : 1; + uint inParseEntity : 1; + uint referenceToUnparsedEntityDetected : 1; + uint referenceToParameterEntityDetected : 1; + uint hasExternalDtdSubset : 1; + uint lockEncoding : 1; + uint namespaceProcessing : 1; + + int resumeReduction; + void resume(int rule); + + inline bool entitiesMustBeDeclared() const { + return (!inParseEntity + && (standalone + || (!referenceToUnparsedEntityDetected + && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25 + && !hasExternalDtdSubset))); + } + + // qlalr parser + int tos; + int stack_size; + struct Value { + int pos; + int len; + int prefix; + ushort c; + }; + + Value *sym_stack; + int *state_stack; + inline void reallocateStack(); + inline Value &sym(int index) const + { return sym_stack[tos + index - 1]; } + QString textBuffer; + inline void clearTextBuffer() { + if (!scanDtd) { + textBuffer.resize(0); + textBuffer.reserve(256); + } + } + struct Attribute { + Value key; + Value value; + }; + QXmlStreamSimpleStack<Attribute> attributeStack; + + inline QStringRef symString(int index) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); + } + inline QStringRef symName(int index) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos, symbol.len); + } + inline QStringRef symString(int index, int offset) { + const Value &symbol = sym(index); + return QStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset); + } + inline QStringRef symPrefix(int index) { + const Value &symbol = sym(index); + if (symbol.prefix) + return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); + return QStringRef(); + } + inline QStringRef symString(const Value &symbol) { + return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix); + } + inline QStringRef symName(const Value &symbol) { + return QStringRef(&textBuffer, symbol.pos, symbol.len); + } + inline QStringRef symPrefix(const Value &symbol) { + if (symbol.prefix) + return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1); + return QStringRef(); + } + + inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; } + + + short token; + ushort token_char; + + uint filterCarriageReturn(); + inline uint getChar(); + inline uint peekChar(); + inline void putChar(uint c) { putStack.push() = c; } + inline void putChar(QChar c) { putStack.push() = c.unicode(); } + void putString(const QString &s, int from = 0); + void putStringLiteral(const QString &s); + void putReplacement(const QString &s); + void putReplacementInAttributeValue(const QString &s); + ushort getChar_helper(); + + bool scanUntil(const char *str, short tokenToInject = -1); + bool scanString(const char *str, short tokenToInject, bool requireSpace = true); + inline void injectToken(ushort tokenToInject) { + putChar(int(tokenToInject) << 16); + } + + QString resolveUndeclaredEntity(const QString &name); + void parseEntity(const QString &value); + QXmlStreamReaderPrivate *entityParser; + + bool scanAfterLangleBang(); + bool scanPublicOrSystem(); + bool scanNData(); + bool scanAfterDefaultDecl(); + bool scanAttType(); + + + // scan optimization functions. Not strictly necessary but LALR is + // not very well suited for scanning fast + int fastScanLiteralContent(); + int fastScanSpace(); + int fastScanContentCharList(); + int fastScanName(int *prefix = 0); + inline int fastScanNMTOKEN(); + + + bool parse(); + inline void consumeRule(int); + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); + + QXmlStreamEntityResolver *entityResolver; + +private: + /*! \internal + Never assign to variable type directly. Instead use this function. + + This prevents errors from being ignored. + */ + inline void setType(const QXmlStreamReader::TokenType t) + { + if(type != QXmlStreamReader::Invalid) + type = t; + } +}; + +bool QXmlStreamReaderPrivate::parse() +{ + // cleanup currently reported token + + switch (type) { + case QXmlStreamReader::StartElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + if (publicNamespaceDeclarations.size()) + publicNamespaceDeclarations.clear(); + if (attributes.size()) + attributes.resize(0); + if (isEmptyElement) { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + isEmptyElement = false; + return true; + } + clearTextBuffer(); + break; + case QXmlStreamReader::EndElement: + name.clear(); + prefix.clear(); + qualifiedName.clear(); + namespaceUri.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::DTD: + publicNotationDeclarations.clear(); + publicEntityDeclarations.clear(); + dtdName.clear(); + dtdPublicId.clear(); + dtdSystemId.clear(); + // fall through + case QXmlStreamReader::Comment: + case QXmlStreamReader::Characters: + isCDATA = false; + isWhitespace = true; + text.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::EntityReference: + text.clear(); + name.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::ProcessingInstruction: + processingInstructionTarget.clear(); + processingInstructionData.clear(); + clearTextBuffer(); + break; + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + break; + case QXmlStreamReader::StartDocument: + lockEncoding = true; + documentVersion.clear(); + documentEncoding.clear(); +#ifndef QT_NO_TEXTCODEC + if(decoder->hasFailure()) { + raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content.")); + readBuffer.clear(); + return false; + } +#endif + // fall through + default: + clearTextBuffer(); + ; + } + + setType(QXmlStreamReader::NoToken); + + + // the main parse loop + int act, r; + + if (resumeReduction) { + act = state_stack[tos-1]; + r = resumeReduction; + resumeReduction = 0; + goto ResumeReduction; + } + + act = state_stack[tos]; + + forever { + if (token == -1 && - TERMINAL_COUNT != action_index[act]) { + uint cu = getChar(); + token = NOTOKEN; + token_char = cu; + if (cu & 0xff0000) { + token = cu >> 16; + } else switch (token_char) { + case 0xfffe: + case 0xffff: + token = ERROR; + break; + case '\r': + token = SPACE; + if (cu == '\r') { + if ((token_char = filterCarriageReturn())) { + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + break; + } + } else { + break; + } + // fall through + case '\0': { + token = EOF_SYMBOL; + if (!tagsDone && !inParseEntity) { + int a = t_action(act, token); + if (a < 0) { + raiseError(QXmlStreamReader::PrematureEndOfDocumentError); + return false; + } + } + + } break; + case '\n': + ++lineNumber; + lastLineStart = characterOffset + readBufferPos; + case ' ': + case '\t': + token = SPACE; + break; + case '&': + token = AMPERSAND; + break; + case '#': + token = HASH; + break; + case '\'': + token = QUOTE; + break; + case '\"': + token = DBLQUOTE; + break; + case '<': + token = LANGLE; + break; + case '>': + token = RANGLE; + break; + case '[': + token = LBRACK; + break; + case ']': + token = RBRACK; + break; + case '(': + token = LPAREN; + break; + case ')': + token = RPAREN; + break; + case '|': + token = PIPE; + break; + case '=': + token = EQ; + break; + case '%': + token = PERCENT; + break; + case '/': + token = SLASH; + break; + case ':': + token = COLON; + break; + case ';': + token = SEMICOLON; + break; + case ',': + token = COMMA; + break; + case '-': + token = DASH; + break; + case '+': + token = PLUS; + break; + case '*': + token = STAR; + break; + case '.': + token = DOT; + break; + case '?': + token = QUESTIONMARK; + break; + case '!': + token = BANG; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token = DIGIT; + break; + default: + if (cu < 0x20) + token = NOTOKEN; + else + token = LETTER; + break; + } + } + + act = t_action (act, token); + if (act == ACCEPT_STATE) { + // reset the parser in case someone resumes (process instructions can follow a valid document) + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return true; + } else if (act > 0) { + if (++tos == stack_size) + reallocateStack(); + + Value &val = sym_stack[tos]; + val.c = token_char; + val.pos = textBuffer.size(); + val.prefix = 0; + val.len = 1; + if (token_char) + textBuffer += QChar(token_char); + + state_stack[tos] = act; + token = -1; + + + } else if (act < 0) { + r = - act - 1; + +#if defined (QLALR_DEBUG) + int ridx = rule_index[r]; + printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]); + ++ridx; + for (int i = ridx; i < ridx + rhs[r]; ++i) { + int symbol = rule_info[i]; + if (const char *name = spell[symbol]) + printf (" %s", name); + else + printf (" #%d", symbol); + } + printf ("\n"); +#endif + + tos -= rhs[r]; + act = state_stack[tos++]; + ResumeReduction: + switch (r) { + + case 0: + setType(QXmlStreamReader::EndDocument); + break; + + case 1: + if (type != QXmlStreamReader::Invalid) { + if (hasSeenTag || inParseEntity) { + setType(QXmlStreamReader::EndDocument); + } else { + raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected.")); + // reset the parser + tos = 0; + state_stack[tos++] = 0; + state_stack[tos] = 0; + return false; + } + } + break; + + case 10: + entityReferenceStack.pop()->isCurrentlyReferenced = false; + clearSym(); + break; + + case 11: + if (!scanString(spell[VERSION], VERSION, false) && atEnd) { + resume(11); + return false; + } + break; + + case 12: + setType(QXmlStreamReader::StartDocument); + documentVersion = symString(6); + startDocument(); + break; + + case 13: + hasExternalDtdSubset = true; + dtdSystemId = symString(2); + break; + + case 14: + checkPublicLiteral(symString(2)); + dtdPublicId = symString(2); + dtdSystemId = symString(4); + hasExternalDtdSubset = true; + break; + + case 16: + if (!scanPublicOrSystem() && atEnd) { + resume(16); + return false; + } + dtdName = symString(3); + break; + + case 17: + case 18: + dtdName = symString(3); + // fall through + + case 19: + case 20: + setType(QXmlStreamReader::DTD); + text = &textBuffer; + break; + + case 21: + scanDtd = true; + break; + + case 22: + scanDtd = false; + break; + + case 36: + if (!scanString(spell[EMPTY], EMPTY, false) + && !scanString(spell[ANY], ANY, false) + && atEnd) { + resume(36); + return false; + } + break; + + case 42: + if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) { + resume(42); + return false; + } + break; + + case 67: { + lastAttributeIsCData = true; + } break; + + case 77: + if (!scanAfterDefaultDecl() && atEnd) { + resume(77); + return false; + } + break; + + case 82: + sym(1) = sym(2); + lastAttributeValue.clear(); + lastAttributeIsCData = false; + if (!scanAttType() && atEnd) { + resume(82); + return false; + } + break; + + case 83: { + DtdAttribute &dtdAttribute = dtdAttributes.push(); + dtdAttribute.tagName.clear(); + dtdAttribute.isCDATA = lastAttributeIsCData; + dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1)); + dtdAttribute.attributeName = addToStringStorage(symString(1)); + dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1)); + dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns") + || (dtdAttribute.attributePrefix.isEmpty() + && dtdAttribute.attributeName == QLatin1String("xmlns"))); + if (lastAttributeValue.isNull()) { + dtdAttribute.defaultValue.clear(); + } else { + if (dtdAttribute.isCDATA) + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue); + else + dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified()); + + } + } break; + + case 87: { + if (referenceToUnparsedEntityDetected && !standalone) + break; + int n = dtdAttributes.size(); + QStringRef tagName = addToStringStorage(symName(3)); + while (n--) { + DtdAttribute &dtdAttribute = dtdAttributes[n]; + if (!dtdAttribute.tagName.isNull()) + break; + dtdAttribute.tagName = tagName; + for (int i = 0; i < n; ++i) { + if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName) + && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) { + dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it + break; + } + } + } + } break; + + case 88: { + if (!scanPublicOrSystem() && atEnd) { + resume(88); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(3); + } break; + + case 89: { + if (!scanPublicOrSystem() && atEnd) { + resume(89); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.push(); + entityDeclaration.clear(); + entityDeclaration.name = symString(5); + entityDeclaration.parameter = true; + } break; + + case 90: { + if (!scanNData() && atEnd) { + resume(90); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.systemId = symString(3); + entityDeclaration.external = true; + } break; + + case 91: { + if (!scanNData() && atEnd) { + resume(91); + return false; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + checkPublicLiteral((entityDeclaration.publicId = symString(3))); + entityDeclaration.systemId = symString(5); + entityDeclaration.external = true; + } break; + + case 92: { + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + entityDeclaration.notationName = symString(3); + if (entityDeclaration.parameter) + raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration.")); + } + //fall through + + case 93: + case 94: { + if (referenceToUnparsedEntityDetected && !standalone) { + entityDeclarations.pop(); + break; + } + EntityDeclaration &entityDeclaration = entityDeclarations.top(); + if (!entityDeclaration.external) + entityDeclaration.value = symString(2); + QString entityName = entityDeclaration.name.toString(); + QHash<QString, Entity> &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash; + if (!hash.contains(entityName)) { + Entity entity(entityDeclaration.value.toString()); + entity.unparsed = (!entityDeclaration.notationName.isNull()); + entity.external = entityDeclaration.external; + hash.insert(entityName, entity); + } + } break; + + case 95: { + setType(QXmlStreamReader::ProcessingInstruction); + int pos = sym(4).pos + sym(4).len; + processingInstructionTarget = symString(3); + if (scanUntil("?>")) { + processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2); + const QString piTarget(processingInstructionTarget.toString()); + if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) { + raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document.")); + } + else if(!QXmlUtils::isNCName(piTarget)) + raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget)); + } else if (type != QXmlStreamReader::Invalid){ + resume(95); + return false; + } + } break; + + case 96: + setType(QXmlStreamReader::ProcessingInstruction); + processingInstructionTarget = symString(3); + if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive)) + raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name.")); + break; + + case 97: + if (!scanAfterLangleBang() && atEnd) { + resume(97); + return false; + } + break; + + case 98: + if (!scanUntil("--")) { + resume(98); + return false; + } + break; + + case 99: { + setType(QXmlStreamReader::Comment); + int pos = sym(1).pos + 4; + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } break; + + case 100: { + setType(QXmlStreamReader::Characters); + isCDATA = true; + isWhitespace = false; + int pos = sym(2).pos; + if (scanUntil("]]>", -1)) { + text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3); + } else { + resume(100); + return false; + } + } break; + + case 101: { + if (!scanPublicOrSystem() && atEnd) { + resume(101); + return false; + } + NotationDeclaration ¬ationDeclaration = notationDeclarations.push(); + notationDeclaration.name = symString(3); + } break; + + case 102: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId = symString(3); + notationDeclaration.publicId.clear(); + } break; + + case 103: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + notationDeclaration.systemId.clear(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + } break; + + case 104: { + NotationDeclaration ¬ationDeclaration = notationDeclarations.top(); + checkPublicLiteral((notationDeclaration.publicId = symString(3))); + notationDeclaration.systemId = symString(5); + } break; + + case 128: + isWhitespace = false; + // fall through + + case 129: + sym(1).len += fastScanContentCharList(); + if (atEnd && !inParseEntity) { + resume(129); + return false; + } + break; + + case 138: + if (!textBuffer.isEmpty()) { + setType(QXmlStreamReader::Characters); + text = &textBuffer; + } + break; + + case 139: + case 140: + clearSym(); + break; + + case 141: + case 142: + sym(1) = sym(2); + break; + + case 143: + case 144: + case 145: + case 146: + sym(1).len += sym(2).len; + break; + + case 172: + if (normalizeLiterals) + textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' '); + break; + + case 173: + sym(1).len += fastScanLiteralContent(); + if (atEnd) { + resume(173); + return false; + } + break; + + case 174: { + if (!QXmlUtils::isPublicID(symString(1).toString())) { + raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString())); + resume(174); + return false; + } + } break; + + case 175: + case 176: + clearSym(); + break; + + case 177: + case 178: + sym(1) = sym(2); + break; + + case 179: + case 180: + case 181: + case 182: + sym(1).len += sym(2).len; + break; + + case 212: + case 213: + clearSym(); + break; + + case 214: + case 215: + sym(1) = sym(2); + lastAttributeValue = symString(1); + break; + + case 216: + case 217: + case 218: + case 219: + sym(1).len += sym(2).len; + break; + + case 228: { + QStringRef prefix = symPrefix(1); + if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + namespaceDeclaration.prefix.clear(); + + const QStringRef ns(symString(5)); + if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") || + ns == QLatin1String("http://www.w3.org/XML/1998/namespace")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + else + namespaceDeclaration.namespaceUri = addToStringStorage(ns); + } else { + Attribute &attribute = attributeStack.push(); + attribute.key = sym(1); + attribute.value = sym(5); + + QStringRef attributeQualifiedName = symName(1); + bool normalize = false; + for (int a = 0; a < dtdAttributes.size(); ++a) { + DtdAttribute &dtdAttribute = dtdAttributes[a]; + if (!dtdAttribute.isCDATA + && dtdAttribute.tagName == qualifiedName + && dtdAttribute.attributeQualifiedName == attributeQualifiedName + ) { + normalize = true; + break; + } + } + if (normalize) { + // normalize attribute value (simplify and trim) + int pos = textBuffer.size(); + int n = 0; + bool wasSpace = true; + for (int i = 0; i < attribute.value.len; ++i) { + QChar c = textBuffer.at(attribute.value.pos + i); + if (c.unicode() == ' ') { + if (wasSpace) + continue; + wasSpace = true; + } else { + wasSpace = false; + } + textBuffer += textBuffer.at(attribute.value.pos + i); + ++n; + } + if (wasSpace) + while (n && textBuffer.at(pos + n - 1).unicode() == ' ') + --n; + attribute.value.pos = pos; + attribute.value.len = n; + } + if (prefix == QLatin1String("xmlns") && namespaceProcessing) { + NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push(); + QStringRef namespacePrefix = symString(attribute.key); + QStringRef namespaceUri = symString(attribute.value); + attributeStack.pop(); + if (((namespacePrefix == QLatin1String("xml")) + ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))) + || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/") + || namespaceUri.isEmpty() + || namespacePrefix == QLatin1String("xmlns")) + raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration.")); + + namespaceDeclaration.prefix = addToStringStorage(namespacePrefix); + namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri); + } + } + } break; + + case 234: { + normalizeLiterals = true; + Tag &tag = tagStack_push(); + prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2)); + name = tag.name = addToStringStorage(symString(2)); + qualifiedName = tag.qualifiedName = addToStringStorage(symName(2)); + if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name)) + raiseWellFormedError(QXmlStream::tr("Invalid XML name.")); + } break; + + case 235: + isEmptyElement = true; + // fall through + + case 236: + setType(QXmlStreamReader::StartElement); + resolveTag(); + if (tagStack.size() == 1 && hasSeenTag && !inParseEntity) + raiseWellFormedError(QXmlStream::tr("Extra content at end of document.")); + hasSeenTag = true; + break; + + case 237: { + setType(QXmlStreamReader::EndElement); + Tag &tag = tagStack_pop(); + + namespaceUri = tag.namespaceDeclaration.namespaceUri; + name = tag.name; + qualifiedName = tag.qualifiedName; + if (qualifiedName != symName(3)) + raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); + } break; + + case 238: + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity)); + break; + } + setType(QXmlStreamReader::EntityReference); + name = &unresolvedEntity; + break; + + case 239: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (entityHash.contains(reference)) { + Entity &entity = entityHash[reference]; + if (entity.unparsed) { + raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference)); + } else { + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacement(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + + injectToken(UNRESOLVED_ENTITY); + unresolvedEntity = symString(2).toString(); + textBuffer.chop(2 + sym(2).len); + clearSym(); + + } break; + + case 240: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (parameterEntityHash.contains(reference)) { + referenceToParameterEntityDetected = true; + Entity &entity = parameterEntityHash[reference]; + if (entity.unparsed || entity.external) { + referenceToUnparsedEntityDetected = true; + } else { + if (referenceEntity(entity)) + putString(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + } + } else if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString())); + } + } break; + + case 241: + sym(1).len += sym(2).len + 1; + break; + + case 242: { + sym(1).len += sym(2).len + 1; + QString reference = symString(2).toString(); + if (entityHash.contains(reference)) { + Entity &entity = entityHash[reference]; + if (entity.unparsed || entity.value.isNull()) { + raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference)); + break; + } + if (!entity.hasBeenParsed) { + parseEntity(entity.value); + entity.hasBeenParsed = true; + } + if (entity.literal) + putStringLiteral(entity.value); + else if (referenceEntity(entity)) + putReplacementInAttributeValue(entity.value); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + + if (entityResolver) { + QString replacementText = resolveUndeclaredEntity(reference); + if (!replacementText.isNull()) { + putReplacement(replacementText); + textBuffer.chop(2 + sym(2).len); + clearSym(); + break; + } + } + if (entitiesMustBeDeclared()) { + raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference)); + } + } break; + + case 243: { + if (uint s = resolveCharRef(3)) { + if (s >= 0xffff) + putStringLiteral(QString::fromUcs4(&s, 1)); + else + putChar((LETTER << 16) | s); + + textBuffer.chop(3 + sym(3).len); + clearSym(); + } else { + raiseWellFormedError(QXmlStream::tr("Invalid character reference.")); + } + } break; + + case 246: + case 247: + sym(1).len += sym(2).len; + break; + + case 258: + sym(1).len += fastScanSpace(); + if (atEnd) { + resume(258); + return false; + } + break; + + case 261: { + sym(1).len += fastScanName(&sym(1).prefix); + if (atEnd) { + resume(261); + return false; + } + } break; + + case 262: + sym(1).len += fastScanName(); + if (atEnd) { + resume(262); + return false; + } + break; + + case 263: + case 264: + case 265: + case 266: + case 267: + sym(1).len += fastScanNMTOKEN(); + if (atEnd) { + resume(267); + return false; + } + + break; + + default: + ; + } // switch + act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT); + if (type != QXmlStreamReader::NoToken) + return true; + } else { + parseError(); + break; + } + } + return false; +} + +#endif // QXMLSTREAM_P_H + diff --git a/src/corelib/xml/qxmlutils.cpp b/src/corelib/xml/qxmlutils.cpp new file mode 100644 index 0000000..26ecc51 --- /dev/null +++ b/src/corelib/xml/qxmlutils.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QRegExp> +#include <QString> + +#include "qxmlutils_p.h" + +QT_BEGIN_NAMESPACE + +/* TODO: + * - isNameChar() doesn't have to be public, it's only needed in + * qdom.cpp -- refactor fixedXmlName() to use isNCName() + * - A lot of functions can be inlined. + */ + +class QXmlCharRange +{ +public: + ushort min; + ushort max; +}; +typedef const QXmlCharRange *RangeIter; + +/*! + Performs a binary search between \a begin and \a end inclusive, to check whether \a + c is contained. Remember that the QXmlCharRange instances must be in numeric order. + */ +bool QXmlUtils::rangeContains(RangeIter begin, RangeIter end, const QChar c) +{ + const ushort cp(c.unicode()); + + // check the first two ranges "manually" as characters in that + // range are checked very often and we avoid the binary search below. + + if (cp <= begin->max) + return cp >= begin->min; + + ++begin; + + if (begin == end) + return false; + + if (cp <= begin->max) + return cp >= begin->min; + + while (begin != end) { + int delta = (end - begin) / 2; + RangeIter mid = begin + delta; + + if (mid->min > cp) + end = mid; + else if (mid->max < cp) + begin = mid; + else + return true; + + if (delta == 0) + break; + } + + return false; +} + +// [85] BaseChar ::= ... + +static const QXmlCharRange g_base_begin[] = +{ + {0x0041, 0x005A}, {0x0061, 0x007A}, {0x00C0, 0x00D6}, {0x00D8, 0x00F6}, {0x00F8, 0x00FF}, + {0x0100, 0x0131}, {0x0134, 0x013E}, {0x0141, 0x0148}, {0x014A, 0x017E}, {0x0180, 0x01C3}, + {0x01CD, 0x01F0}, {0x01F4, 0x01F5}, {0x01FA, 0x0217}, {0x0250, 0x02A8}, {0x02BB, 0x02C1}, + {0x0386, 0x0386}, {0x0388, 0x038A}, {0x038C, 0x038C}, {0x038E, 0x03A1}, {0x03A3, 0x03CE}, + {0x03D0, 0x03D6}, {0x03DA, 0x03DA}, {0x03DC, 0x03DC}, {0x03DE, 0x03DE}, {0x03E0, 0x03E0}, + {0x03E2, 0x03F3}, {0x0401, 0x040C}, {0x040E, 0x044F}, {0x0451, 0x045C}, {0x045E, 0x0481}, + {0x0490, 0x04C4}, {0x04C7, 0x04C8}, {0x04CB, 0x04CC}, {0x04D0, 0x04EB}, {0x04EE, 0x04F5}, + {0x04F8, 0x04F9}, {0x0531, 0x0556}, {0x0559, 0x0559}, {0x0561, 0x0586}, {0x05D0, 0x05EA}, + {0x05F0, 0x05F2}, {0x0621, 0x063A}, {0x0641, 0x064A}, {0x0671, 0x06B7}, {0x06BA, 0x06BE}, + {0x06C0, 0x06CE}, {0x06D0, 0x06D3}, {0x06D5, 0x06D5}, {0x06E5, 0x06E6}, {0x0905, 0x0939}, + {0x093D, 0x093D}, {0x0958, 0x0961}, {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, + {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, + {0x09F0, 0x09F1}, {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, + {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, + {0x0A72, 0x0A74}, {0x0A85, 0x0A8B}, {0x0A8D, 0x0A8D}, {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, + {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABD, 0x0ABD}, {0x0AE0, 0x0AE0}, + {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, + {0x0B36, 0x0B39}, {0x0B3D, 0x0B3D}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B85, 0x0B8A}, + {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, + {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB5}, {0x0BB7, 0x0BB9}, {0x0C05, 0x0C0C}, + {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C33}, {0x0C35, 0x0C39}, {0x0C60, 0x0C61}, + {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90}, {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, + {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1}, {0x0D05, 0x0D0C}, {0x0D0E, 0x0D10}, {0x0D12, 0x0D28}, + {0x0D2A, 0x0D39}, {0x0D60, 0x0D61}, {0x0E01, 0x0E2E}, {0x0E30, 0x0E30}, {0x0E32, 0x0E33}, + {0x0E40, 0x0E45}, {0x0E81, 0x0E82}, {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, + {0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, + {0x0EA7, 0x0EA7}, {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EAE}, {0x0EB0, 0x0EB0}, {0x0EB2, 0x0EB3}, + {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0F40, 0x0F47}, {0x0F49, 0x0F69}, {0x10A0, 0x10C5}, + {0x10D0, 0x10F6}, {0x1100, 0x1100}, {0x1102, 0x1103}, {0x1105, 0x1107}, {0x1109, 0x1109}, + {0x110B, 0x110C}, {0x110E, 0x1112}, {0x113C, 0x113C}, {0x113E, 0x113E}, {0x1140, 0x1140}, + {0x114C, 0x114C}, {0x114E, 0x114E}, {0x1150, 0x1150}, {0x1154, 0x1155}, {0x1159, 0x1159}, + {0x115F, 0x1161}, {0x1163, 0x1163}, {0x1165, 0x1165}, {0x1167, 0x1167}, {0x1169, 0x1169}, + {0x116D, 0x116E}, {0x1172, 0x1173}, {0x1175, 0x1175}, {0x119E, 0x119E}, {0x11A8, 0x11A8}, + {0x11AB, 0x11AB}, {0x11AE, 0x11AF}, {0x11B7, 0x11B8}, {0x11BA, 0x11BA}, {0x11BC, 0x11C2}, + {0x11EB, 0x11EB}, {0x11F0, 0x11F0}, {0x11F9, 0x11F9}, {0x1E00, 0x1E9B}, {0x1EA0, 0x1EF9}, + {0x1F00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, + {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, + {0x1FB6, 0x1FBC}, {0x1FBE, 0x1FBE}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FD0, 0x1FD3}, + {0x1FD6, 0x1FDB}, {0x1FE0, 0x1FEC}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x2126, 0x2126}, + {0x212A, 0x212B}, {0x212E, 0x212E}, {0x2180, 0x2182}, {0x3041, 0x3094}, {0x30A1, 0x30FA}, + {0x3105, 0x312C}, {0xAC00, 0xD7A3} +}; +static const RangeIter g_base_end = g_base_begin + sizeof(g_base_begin) / sizeof(QXmlCharRange); + +static const QXmlCharRange g_ideographic_begin[] = +{ + {0x3007, 0x3007}, {0x3021, 0x3029}, {0x4E00, 0x9FA5} +}; +static const RangeIter g_ideographic_end = g_ideographic_begin + sizeof(g_ideographic_begin) / sizeof(QXmlCharRange); + +bool QXmlUtils::isIdeographic(const QChar c) +{ + return rangeContains(g_ideographic_begin, g_ideographic_end, c); +} + +static const QXmlCharRange g_combining_begin[] = +{ + {0x0300, 0x0345}, {0x0360, 0x0361}, {0x0483, 0x0486}, {0x0591, 0x05A1}, {0x05A3, 0x05B9}, + {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C4}, {0x064B, 0x0652}, + {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DD, 0x06DF}, {0x06E0, 0x06E4}, {0x06E7, 0x06E8}, + {0x06EA, 0x06ED}, {0x0901, 0x0903}, {0x093C, 0x093C}, {0x093E, 0x094C}, {0x094D, 0x094D}, + {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0983}, {0x09BC, 0x09BC}, {0x09BE, 0x09BE}, + {0x09BF, 0x09BF}, {0x09C0, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, + {0x09E2, 0x09E3}, {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A3E}, {0x0A3F, 0x0A3F}, + {0x0A40, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, {0x0A81, 0x0A83}, + {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, {0x0B01, 0x0B03}, + {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B43}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, + {0x0B82, 0x0B83}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, + {0x0C01, 0x0C03}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, + {0x0C82, 0x0C83}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, + {0x0D02, 0x0D03}, {0x0D3E, 0x0D43}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, + {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, + {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, {0x0F3E, 0x0F3E}, {0x0F3F, 0x0F3F}, {0x0F71, 0x0F84}, {0x0F86, 0x0F8B}, + {0x0F90, 0x0F95}, {0x0F97, 0x0F97}, {0x0F99, 0x0FAD}, {0x0FB1, 0x0FB7}, {0x0FB9, 0x0FB9}, + {0x20D0, 0x20DC}, {0x20E1, 0x20E1}, {0x302A, 0x302F}, {0x3099, 0x3099}, {0x309A, 0x309A} +}; +static const RangeIter g_combining_end = g_combining_begin + sizeof(g_combining_begin) / sizeof(QXmlCharRange); + +bool QXmlUtils::isCombiningChar(const QChar c) +{ + return rangeContains(g_combining_begin, g_combining_end, c); +} + +// [88] Digit ::= ... +static const QXmlCharRange g_digit_begin[] = +{ + {0x0030, 0x0039}, {0x0660, 0x0669}, {0x06F0, 0x06F9}, {0x0966, 0x096F}, {0x09E6, 0x09EF}, + {0x0A66, 0x0A6F}, {0x0AE6, 0x0AEF}, {0x0B66, 0x0B6F}, {0x0BE7, 0x0BEF}, {0x0C66, 0x0C6F}, + {0x0CE6, 0x0CEF}, {0x0D66, 0x0D6F}, {0x0E50, 0x0E59}, {0x0ED0, 0x0ED9}, {0x0F20, 0x0F29} +}; +static const RangeIter g_digit_end = g_digit_begin + sizeof(g_digit_begin) / sizeof(QXmlCharRange); + +bool QXmlUtils::isDigit(const QChar c) +{ + return rangeContains(g_digit_begin, g_digit_end, c); +} + +// [89] Extender ::= ... +static const QXmlCharRange g_extender_begin[] = +{ + {0x00B7, 0x00B7}, {0x02D0, 0x02D0}, {0x02D1, 0x02D1}, {0x0387, 0x0387}, {0x0640, 0x0640}, + {0x0E46, 0x0E46}, {0x0EC6, 0x0EC6}, {0x3005, 0x3005}, {0x3031, 0x3035}, {0x309D, 0x309E}, + {0x30FC, 0x30FE} +}; +static const RangeIter g_extender_end = g_extender_begin + sizeof(g_extender_begin) / sizeof(QXmlCharRange); + +bool QXmlUtils::isExtender(const QChar c) +{ + return rangeContains(g_extender_begin, g_extender_end, c); +} + +bool QXmlUtils::isBaseChar(const QChar c) +{ + return rangeContains(g_base_begin, g_base_end, c); +} + +/*! + \internal + + Determines whether \a encName is a valid instance of production [81]EncName in the XML 1.0 + specification. If it is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml/#NT-EncName} + {Extensible Markup Language (XML) 1.0 (Fourth Edition), [81] EncName} + */ +bool QXmlUtils::isEncName(const QString &encName) +{ + /* Right, we here have a dependency on QRegExp. Writing a manual parser to + * replace that regexp is probably a 70 lines so I prioritize this to when + * the dependency is considered alarming, or when the rest of the bugs + * are fixed. */ + const QRegExp encNameRegExp(QLatin1String("[A-Za-z][A-Za-z0-9._\\-]*")); + Q_ASSERT(encNameRegExp.isValid()); + + return encNameRegExp.exactMatch(encName); +} + +/*! + \internal + + Determines whether \a c is a valid instance of production [84]Letter in the XML 1.0 + specification. If it is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml/#NT-Letter} + {Extensible Markup Language (XML) 1.0 (Fourth Edition), [84] Letter} + */ +bool QXmlUtils::isLetter(const QChar c) +{ + return isBaseChar(c) || isIdeographic(c); +} + +/*! + \internal + + Determines whether \a c is a valid instance of production [2]Char in the XML 1.0 + specification. If it is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml/#NT-Char} + {Extensible Markup Language (XML) 1.0 (Fourth Edition), [2] Char} + */ +bool QXmlUtils::isChar(const QChar c) +{ + return (c.unicode() >= 0x0020 && c.unicode() <= 0xD7FF) + || c.unicode() == 0x0009 + || c.unicode() == 0x000A + || c.unicode() == 0x000D + || (c.unicode() >= 0xE000 && c.unicode() <= 0xFFFD); +} + +/*! + \internal + + Determines whether \a c is a valid instance of + production [4]NameChar in the XML 1.0 specification. If it + is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml/#NT-NameChar} + {Extensible Markup Language (XML) 1.0 (Fourth Edition), [4] NameChar} + */ +bool QXmlUtils::isNameChar(const QChar c) +{ + return isBaseChar(c) + || isDigit(c) + || c.unicode() == '.' + || c.unicode() == '-' + || c.unicode() == '_' + || c.unicode() == ':' + || isCombiningChar(c) + || isIdeographic(c) + || isExtender(c); +} + +/*! + \internal + + Determines whether \a c is a valid instance of + production [12] PubidLiteral in the XML 1.0 specification. If it + is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml/#NT-PubidLiteral} + {Extensible Markup Language (XML) 1.0 (Fourth Edition), [12] PubidLiteral} + */ +bool QXmlUtils::isPublicID(const QString &candidate) +{ + const int len = candidate.length(); + + for(int i = 0; i < len; ++i) + { + const ushort cp = candidate.at(i).unicode(); + + if ((cp >= 'a' && cp <= 'z') + || (cp >= 'A' && cp <= 'Z') + || (cp >= '0' && cp <= '9')) + { + continue; + } + + switch (cp) + { + /* Fallthrough all these. */ + case 0x20: + case 0x0D: + case 0x0A: + case '-': + case '\'': + case '(': + case ')': + case '+': + case ',': + case '.': + case '/': + case ':': + case '=': + case '?': + case ';': + case '!': + case '*': + case '#': + case '@': + case '$': + case '_': + case '%': + continue; + default: + return false; + } + } + + return true; +} + +/*! + \internal + + Determines whether \a c is a valid instance of + production [4]NCName in the XML 1.0 Namespaces specification. If it + is, true is returned, otherwise false. + + \sa \l {http://www.w3.org/TR/REC-xml-names/#NT-NCName} + {W3CNamespaces in XML 1.0 (Second Edition), [4] NCName} + */ +bool QXmlUtils::isNCName(const QStringRef &ncName) +{ + if(ncName.isEmpty()) + return false; + + const QChar first(ncName.at(0)); + + if(!QXmlUtils::isLetter(first) && first.unicode() != '_' && first.unicode() != ':') + return false; + + const int len = ncName.size(); + for(int i = 0; i < len; ++i) + { + const QChar &at = ncName.at(i); + if(!QXmlUtils::isNameChar(at) || at == QLatin1Char(':')) + return false; + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/xml/qxmlutils_p.h new file mode 100644 index 0000000..5230bb7 --- /dev/null +++ b/src/corelib/xml/qxmlutils_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLUTILS_P_H +#define QXMLUTILS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class QString; +class QChar; +class QXmlCharRange; + +/*! + \internal + \short This class contains helper functions related to XML, for validating character classes, + productions in the XML specification, and so on. + */ +class Q_CORE_EXPORT QXmlUtils +{ +public: + static bool isEncName(const QString &encName); + static bool isChar(const QChar c); + static bool isNameChar(const QChar c); + static bool isLetter(const QChar c); + static bool isNCName(const QStringRef &ncName); + static inline bool isNCName(const QString &ncName) { return isNCName(&ncName); } + static bool isPublicID(const QString &candidate); + +private: + typedef const QXmlCharRange *RangeIter; + static bool rangeContains(RangeIter begin, RangeIter end, const QChar c); + static bool isBaseChar(const QChar c); + static bool isDigit(const QChar c); + static bool isExtender(const QChar c); + static bool isIdeographic(const QChar c); + static bool isCombiningChar(const QChar c); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/xml/xml.pri b/src/corelib/xml/xml.pri new file mode 100644 index 0000000..2401c09 --- /dev/null +++ b/src/corelib/xml/xml.pri @@ -0,0 +1,10 @@ +# Qt xml core module + +HEADERS += \ + xml/qxmlstream.h \ + xml/qxmlstream_p.h \ + xml/qxmlutils_p.h + +SOURCES += \ + xml/qxmlstream.cpp \ + xml/qxmlutils.cpp |