diff options
Diffstat (limited to 'src/xml')
-rw-r--r-- | src/xml/dom/dom.pri | 2 | ||||
-rw-r--r-- | src/xml/dom/qdom.cpp | 7563 | ||||
-rw-r--r-- | src/xml/dom/qdom.h | 681 | ||||
-rw-r--r-- | src/xml/sax/qxml.cpp | 8114 | ||||
-rw-r--r-- | src/xml/sax/qxml.h | 425 | ||||
-rw-r--r-- | src/xml/sax/sax.pri | 2 | ||||
-rw-r--r-- | src/xml/stream/qxmlstream.h | 73 | ||||
-rw-r--r-- | src/xml/stream/stream.pri | 9 | ||||
-rw-r--r-- | src/xml/xml.pro | 20 |
9 files changed, 16889 insertions, 0 deletions
diff --git a/src/xml/dom/dom.pri b/src/xml/dom/dom.pri new file mode 100644 index 0000000..d86071e --- /dev/null +++ b/src/xml/dom/dom.pri @@ -0,0 +1,2 @@ +HEADERS += $$PWD/qdom.h +SOURCES += $$PWD/qdom.cpp diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp new file mode 100644 index 0000000..550abc9 --- /dev/null +++ b/src/xml/dom/qdom.cpp @@ -0,0 +1,7563 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXml 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 <qplatformdefs.h> +#include <qdom.h> +#include "private/qxmlutils_p.h" + +#ifndef QT_NO_DOM + +#include <qatomic.h> +#include <qbuffer.h> +#include <qhash.h> +#include <qiodevice.h> +#include <qlist.h> +#include <qregexp.h> +#include <qtextcodec.h> +#include <qtextstream.h> +#include <qxml.h> +#include <qvariant.h> +#include <qmap.h> +#include <qdebug.h> +#include <stdio.h> + +QT_BEGIN_NAMESPACE + +/* + ### old todo comments -- I don't know if they still apply... + + If the document dies, remove all pointers to it from children + which can not be deleted at this time. + + If a node dies and has direct children which can not be deleted, + then remove the pointer to the parent. + + createElement and friends create double reference counts. +*/ + +/* ##### new TODOs: + + Remove emtpy emthods in the *Private classes + + Make a lot of the (mostly empty) methods in the public classes inline. + Specially constructors assignment operators and comparison operators are candidates. + + The virtual isXxx functions in *Private can probably be replaced by inline methods checking the nodeType(). +*/ + +/* + Reference counting: + + Some simple rules: + 1) If an intern object returns a pointer to another intern object + then the reference count of the returned object is not increased. + 2) If an extern object is created and gets a pointer to some intern + object, then the extern object increases the intern objects reference count. + 3) If an extern object is deleted, then it decreases the reference count + on its associated intern object and deletes it if nobody else hold references + on the intern object. +*/ + + +/* + Helper to split a qualified name in the prefix and local name. +*/ +static void qt_split_namespace(QString& prefix, QString& name, const QString& qName, bool hasURI) +{ + int i = qName.indexOf(QLatin1Char(':')); + if (i == -1) { + if (hasURI) + prefix = QLatin1String(""); + else + prefix.clear(); + name = qName; + } else { + prefix = qName.left(i); + name = qName.mid(i + 1); + } +} + +/************************************************************** + * + * Private class declerations + * + **************************************************************/ + +class QDomImplementationPrivate +{ +public: + QDomImplementationPrivate() { ref = 1; } + QDomImplementationPrivate* clone(); + QAtomicInt ref; + static QDomImplementation::InvalidDataPolicy invalidDataPolicy; +}; + +class QDomNodePrivate +{ +public: + QDomNodePrivate(QDomDocumentPrivate*, QDomNodePrivate* parent = 0); + QDomNodePrivate(QDomNodePrivate* n, bool deep); + virtual ~QDomNodePrivate(); + + QString nodeName() const { return name; } + QString nodeValue() const { return value; } + virtual void setNodeValue(const QString& v) { value = v; } + + QDomDocumentPrivate* ownerDocument(); + void setOwnerDocument(QDomDocumentPrivate* doc); + + virtual QDomNodePrivate* insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild); + virtual QDomNodePrivate* insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild); + virtual QDomNodePrivate* replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild); + virtual QDomNodePrivate* removeChild(QDomNodePrivate* oldChild); + virtual QDomNodePrivate* appendChild(QDomNodePrivate* newChild); + + QDomNodePrivate* namedItem(const QString& name); + + virtual QDomNodePrivate* cloneNode(bool deep = true); + virtual void normalize(); + virtual void clear(); + + inline QDomNodePrivate* parent() const { return hasParent ? ownerNode : 0; } + inline void setParent(QDomNodePrivate *p) { ownerNode = p; hasParent = true; } + + void setNoParent() { + ownerNode = hasParent ? (QDomNodePrivate*)ownerDocument() : 0; + hasParent = false; + } + + // Dynamic cast + virtual bool isAttr() const { return false; } + virtual bool isCDATASection() const { return false; } + virtual bool isDocumentFragment() const { return false; } + virtual bool isDocument() const { return false; } + virtual bool isDocumentType() const { return false; } + virtual bool isElement() const { return false; } + virtual bool isEntityReference() const { return false; } + virtual bool isText() const { return false; } + virtual bool isEntity() const { return false; } + virtual bool isNotation() const { return false; } + virtual bool isProcessingInstruction() const { return false; } + virtual bool isCharacterData() const { return false; } + virtual bool isComment() const { return false; } + + virtual QDomNode::NodeType nodeType() const { return QDomNode::BaseNode; } + + virtual void save(QTextStream&, int, int) const; + + void setLocation(int lineNumber, int columnNumber); + + // Variables + QAtomicInt ref; + QDomNodePrivate* prev; + QDomNodePrivate* next; + QDomNodePrivate* ownerNode; // either the node's parent or the node's owner document + QDomNodePrivate* first; + QDomNodePrivate* last; + + QString name; // this is the local name if prefix != null + QString value; + QString prefix; // set this only for ElementNode and AttributeNode + QString namespaceURI; // set this only for ElementNode and AttributeNode + bool createdWithDom1Interface : 1; + bool hasParent : 1; + + int lineNumber; + int columnNumber; +}; + +class QDomNodeListPrivate +{ +public: + QDomNodeListPrivate(QDomNodePrivate*); + QDomNodeListPrivate(QDomNodePrivate*, const QString& ); + QDomNodeListPrivate(QDomNodePrivate*, const QString&, const QString& ); + ~QDomNodeListPrivate(); + + bool operator== (const QDomNodeListPrivate&) const; + bool operator!= (const QDomNodeListPrivate&) const; + + void createList(); + QDomNodePrivate* item(int index); + uint length() const; + + QAtomicInt ref; + /* + This list contains the children of this node. + */ + QDomNodePrivate* node_impl; + QString tagname; + QString nsURI; + QList<QDomNodePrivate*> list; + long timestamp; +}; + +class QDomNamedNodeMapPrivate +{ +public: + QDomNamedNodeMapPrivate(QDomNodePrivate*); + ~QDomNamedNodeMapPrivate(); + + QDomNodePrivate* namedItem(const QString& name) const; + QDomNodePrivate* namedItemNS(const QString& nsURI, const QString& localName) const; + QDomNodePrivate* setNamedItem(QDomNodePrivate* arg); + QDomNodePrivate* setNamedItemNS(QDomNodePrivate* arg); + QDomNodePrivate* removeNamedItem(const QString& name); + QDomNodePrivate* item(int index) const; + uint length() const; + bool contains(const QString& name) const; + bool containsNS(const QString& nsURI, const QString & localName) const; + + /** + * Remove all children from the map. + */ + void clearMap(); + bool isReadOnly() { return readonly; } + void setReadOnly(bool r) { readonly = r; } + bool isAppendToParent() { return appendToParent; } + /** + * If true, then the node will redirect insert/remove calls + * to its parent by calling QDomNodePrivate::appendChild or removeChild. + * In addition the map wont increase or decrease the reference count + * of the nodes it contains. + * + * By default this value is false and the map will handle reference counting + * by itself. + */ + void setAppendToParent(bool b) { appendToParent = b; } + + /** + * Creates a copy of the map. It is a deep copy + * that means that all children are cloned. + */ + QDomNamedNodeMapPrivate* clone(QDomNodePrivate* parent); + + // Variables + QAtomicInt ref; + QHash<QString, QDomNodePrivate *> map; + QDomNodePrivate* parent; + bool readonly; + bool appendToParent; +}; + +class QDomDocumentTypePrivate : public QDomNodePrivate +{ +public: + QDomDocumentTypePrivate(QDomDocumentPrivate*, QDomNodePrivate* parent = 0); + QDomDocumentTypePrivate(QDomDocumentTypePrivate* n, bool deep); + ~QDomDocumentTypePrivate(); + void init(); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + QDomNodePrivate* insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild); + QDomNodePrivate* insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild); + QDomNodePrivate* replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild); + QDomNodePrivate* removeChild(QDomNodePrivate* oldChild); + QDomNodePrivate* appendChild(QDomNodePrivate* newChild); + + virtual bool isDocumentType() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::DocumentTypeNode; } + + void save(QTextStream& s, int, int) const; + + // Variables + QDomNamedNodeMapPrivate* entities; + QDomNamedNodeMapPrivate* notations; + QString publicId; + QString systemId; + QString internalSubset; +}; + +class QDomDocumentFragmentPrivate : public QDomNodePrivate +{ +public: + QDomDocumentFragmentPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent = 0); + QDomDocumentFragmentPrivate(QDomNodePrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + virtual QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isDocumentFragment() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::DocumentFragmentNode; } +}; + +class QDomCharacterDataPrivate : public QDomNodePrivate +{ +public: + QDomCharacterDataPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& data); + QDomCharacterDataPrivate(QDomCharacterDataPrivate* n, bool deep); + + uint dataLength() const; + QString substringData(unsigned long offset, unsigned long count) const; + void appendData(const QString& arg); + void insertData(unsigned long offset, const QString& arg); + void deleteData(unsigned long offset, unsigned long count); + void replaceData(unsigned long offset, unsigned long count, const QString& arg); + + // Reimplemented from QDomNodePrivate + virtual bool isCharacterData() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::CharacterDataNode; } + QDomNodePrivate* cloneNode(bool deep = true); +}; + +class QDomTextPrivate : public QDomCharacterDataPrivate +{ +public: + QDomTextPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& val); + QDomTextPrivate(QDomTextPrivate* n, bool deep); + + QDomTextPrivate* splitText(int offset); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isText() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::TextNode; } + virtual void save(QTextStream& s, int, int) const; +}; + +class QDomAttrPrivate : public QDomNodePrivate +{ +public: + QDomAttrPrivate(QDomDocumentPrivate*, QDomNodePrivate*, const QString& name); + QDomAttrPrivate(QDomDocumentPrivate*, QDomNodePrivate*, const QString& nsURI, const QString& qName); + QDomAttrPrivate(QDomAttrPrivate* n, bool deep); + + bool specified() const; + + // Reimplemented from QDomNodePrivate + void setNodeValue(const QString& v); + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isAttr() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::AttributeNode; } + virtual void save(QTextStream& s, int, int) const; + + // Variables + bool m_specified; +}; + +class QDomElementPrivate : public QDomNodePrivate +{ +public: + QDomElementPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& name); + QDomElementPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& nsURI, const QString& qName); + QDomElementPrivate(QDomElementPrivate* n, bool deep); + ~QDomElementPrivate(); + + QString attribute(const QString& name, const QString& defValue) const; + QString attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const; + void setAttribute(const QString& name, const QString& value); + void setAttributeNS(const QString& nsURI, const QString& qName, const QString& newValue); + void removeAttribute(const QString& name); + QDomAttrPrivate* attributeNode(const QString& name); + QDomAttrPrivate* attributeNodeNS(const QString& nsURI, const QString& localName); + QDomAttrPrivate* setAttributeNode(QDomAttrPrivate* newAttr); + QDomAttrPrivate* setAttributeNodeNS(QDomAttrPrivate* newAttr); + QDomAttrPrivate* removeAttributeNode(QDomAttrPrivate* oldAttr); + bool hasAttribute(const QString& name); + bool hasAttributeNS(const QString& nsURI, const QString& localName); + + QString text(); + + // Reimplemented from QDomNodePrivate + QDomNamedNodeMapPrivate* attributes() { return m_attr; } + bool hasAttributes() { return (m_attr->length() > 0); } + virtual bool isElement() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::ElementNode; } + QDomNodePrivate* cloneNode(bool deep = true); + virtual void save(QTextStream& s, int, int) const; + + // Variables + QDomNamedNodeMapPrivate* m_attr; +}; + + +class QDomCommentPrivate : public QDomCharacterDataPrivate +{ +public: + QDomCommentPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& val); + QDomCommentPrivate(QDomCommentPrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isComment() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::CommentNode; } + virtual void save(QTextStream& s, int, int) const; +}; + +class QDomCDATASectionPrivate : public QDomTextPrivate +{ +public: + QDomCDATASectionPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& val); + QDomCDATASectionPrivate(QDomCDATASectionPrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isCDATASection() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::CDATASectionNode; } + virtual void save(QTextStream& s, int, int) const; +}; + +class QDomNotationPrivate : public QDomNodePrivate +{ +public: + QDomNotationPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& name, + const QString& pub, const QString& sys); + QDomNotationPrivate(QDomNotationPrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isNotation() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::NotationNode; } + virtual void save(QTextStream& s, int, int) const; + + // Variables + QString m_sys; + QString m_pub; +}; + +class QDomEntityPrivate : public QDomNodePrivate +{ +public: + QDomEntityPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& name, + const QString& pub, const QString& sys, const QString& notation); + QDomEntityPrivate(QDomEntityPrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isEntity() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::EntityNode; } + virtual void save(QTextStream& s, int, int) const; + + // Variables + QString m_sys; + QString m_pub; + QString m_notationName; +}; + +class QDomEntityReferencePrivate : public QDomNodePrivate +{ +public: + QDomEntityReferencePrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& name); + QDomEntityReferencePrivate(QDomNodePrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + bool isEntityReference() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::EntityReferenceNode; } + virtual void save(QTextStream& s, int, int) const; +}; + +class QDomProcessingInstructionPrivate : public QDomNodePrivate +{ +public: + QDomProcessingInstructionPrivate(QDomDocumentPrivate*, QDomNodePrivate* parent, const QString& target, + const QString& data); + QDomProcessingInstructionPrivate(QDomProcessingInstructionPrivate* n, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + virtual bool isProcessingInstruction() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::ProcessingInstructionNode; } + virtual void save(QTextStream& s, int, int) const; +}; + +class QDomDocumentPrivate : public QDomNodePrivate +{ +public: + QDomDocumentPrivate(); + QDomDocumentPrivate(const QString& name); + QDomDocumentPrivate(QDomDocumentTypePrivate* dt); + QDomDocumentPrivate(QDomDocumentPrivate* n, bool deep); + ~QDomDocumentPrivate(); + + bool setContent(QXmlInputSource *source, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn); + bool setContent(QXmlInputSource *source, QXmlReader *reader, QString *errorMsg, int *errorLine, int *errorColumn); + + // Attributes + QDomDocumentTypePrivate* doctype() { return type; }; + QDomImplementationPrivate* implementation() { return impl; }; + QDomElementPrivate* documentElement(); + + // Factories + QDomElementPrivate* createElement(const QString& tagName); + QDomElementPrivate* createElementNS(const QString& nsURI, const QString& qName); + QDomDocumentFragmentPrivate* createDocumentFragment(); + QDomTextPrivate* createTextNode(const QString& data); + QDomCommentPrivate* createComment(const QString& data); + QDomCDATASectionPrivate* createCDATASection(const QString& data); + QDomProcessingInstructionPrivate* createProcessingInstruction(const QString& target, const QString& data); + QDomAttrPrivate* createAttribute(const QString& name); + QDomAttrPrivate* createAttributeNS(const QString& nsURI, const QString& qName); + QDomEntityReferencePrivate* createEntityReference(const QString& name); + + QDomNodePrivate* importNode(const QDomNodePrivate* importedNode, bool deep); + + // Reimplemented from QDomNodePrivate + QDomNodePrivate* cloneNode(bool deep = true); + bool isDocument() const { return true; } + QDomNode::NodeType nodeType() const { return QDomNode::DocumentNode; } + void clear(); + + // Variables + QDomImplementationPrivate* impl; + QDomDocumentTypePrivate* type; + + void saveDocument(QTextStream& stream, const int indent, QDomNode::EncodingPolicy encUsed) const; + + /* \internal + Counter for the QDomNodeListPrivate timestamps. + + This is a cache optimization, that might in some cases be effective. The + dilemma is that QDomNode::childNodes() returns a list, but the + implementation stores the children in a linked list. Hence, in order to + get the children out through childNodes(), a list must be populated each + time, which is O(N). + + DOM has the requirement of node references being live, see DOM Core + Level 3, 1.1.1 The DOM Structure Model, which means that changes to the + underlying documents must be reflected in node lists. + + This mechanism, nodeListTime, is a caching optimization that reduces the + amount of times the node list is rebuilt, by only doing so when the + document actually changes. However, a change to anywhere in any document + invalidate all lists, since no dependency tracking is done. + + It functions by that all modifying functions(insertBefore() and so on) + increment the count; each QDomNodeListPrivate copies nodeListTime on + construction, and compares its own value to nodeListTime in order to + determine whether it needs to rebuild. + + This is reentrant. The nodeListTime may overflow, but that's ok since we + check for equalness, not whether nodeListTime is smaller than the list's + stored timestamp. + */ + long nodeListTime; +}; + +/************************************************************** + * + * QDomHandler + * + **************************************************************/ + +class QDomHandler : public QXmlDefaultHandler +{ +public: + QDomHandler(QDomDocumentPrivate* d, bool namespaceProcessing); + ~QDomHandler(); + + // content handler + bool endDocument(); + bool startElement(const QString& nsURI, const QString& localName, const QString& qName, const QXmlAttributes& atts); + bool endElement(const QString& nsURI, const QString& localName, const QString& qName); + bool characters(const QString& ch); + bool processingInstruction(const QString& target, const QString& data); + bool skippedEntity(const QString& name); + + // error handler + bool fatalError(const QXmlParseException& exception); + + // lexical handler + bool startCDATA(); + bool endCDATA(); + bool startEntity(const QString &); + bool endEntity(const QString &); + bool startDTD(const QString& name, const QString& publicId, const QString& systemId); + bool comment(const QString& ch); + + // decl handler + bool externalEntityDecl(const QString &name, const QString &publicId, const QString &systemId) ; + + // DTD handler + bool notationDecl(const QString & name, const QString & publicId, const QString & systemId); + bool unparsedEntityDecl(const QString &name, const QString &publicId, const QString &systemId, const QString ¬ationName) ; + + void setDocumentLocator(QXmlLocator *locator); + + QString errorMsg; + int errorLine; + int errorColumn; + +private: + QDomDocumentPrivate *doc; + QDomNodePrivate *node; + QString entityName; + bool cdata; + bool nsProcessing; + QXmlLocator *locator; +}; + +/************************************************************** + * + * Functions for verifying legal data + * + **************************************************************/ +QDomImplementation::InvalidDataPolicy QDomImplementationPrivate::invalidDataPolicy + = QDomImplementation::AcceptInvalidChars; + +// [5] Name ::= (Letter | '_' | ':') (NameChar)* + +static QString fixedXmlName(const QString &_name, bool *ok, bool namespaces = false) +{ + QString name, prefix; + if (namespaces) + qt_split_namespace(prefix, name, _name, true); + else + name = _name; + + if (name.isEmpty()) { + *ok = false; + return QString(); + } + + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return _name; + } + + QString result; + bool firstChar = true; + for (int i = 0; i < name.size(); ++i) { + QChar c = name.at(i); + if (firstChar) { + if (QXmlUtils::isLetter(c) || c.unicode() == '_' || c.unicode() == ':') { + result.append(c); + firstChar = false; + } else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + } else { + if (QXmlUtils::isNameChar(c)) + result.append(c); + else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + } + } + + if (result.isEmpty()) { + *ok = false; + return QString(); + } + + *ok = true; + if (namespaces && !prefix.isEmpty()) + return prefix + QLatin1Char(':') + result; + return result; +} + +// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) +// '<', '&' and "]]>" will be escaped when writing + +static QString fixedCharData(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString result; + for (int i = 0; i < data.size(); ++i) { + QChar c = data.at(i); + if (QXmlUtils::isChar(c)) { + result.append(c); + } else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + } + + *ok = true; + return result; +} + +// [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' +// can't escape "--", since entities are not recognised within comments + +static QString fixedComment(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString fixedData = fixedCharData(data, ok); + if (!*ok) + return QString(); + + for (;;) { + int idx = fixedData.indexOf(QLatin1String("--")); + if (idx == -1) + break; + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + fixedData.remove(idx, 2); + } + + *ok = true; + return fixedData; +} + +// [20] CData ::= (Char* - (Char* ']]>' Char*)) +// can't escape "]]>", since entities are not recognised within comments + +static QString fixedCDataSection(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString fixedData = fixedCharData(data, ok); + if (!*ok) + return QString(); + + for (;;) { + int idx = fixedData.indexOf(QLatin1String("]]>")); + if (idx == -1) + break; + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + fixedData.remove(idx, 3); + } + + *ok = true; + return fixedData; +} + +// [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' + +static QString fixedPIData(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString fixedData = fixedCharData(data, ok); + if (!*ok) + return QString(); + + for (;;) { + int idx = fixedData.indexOf(QLatin1String("?>")); + if (idx == -1) + break; + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + fixedData.remove(idx, 2); + } + + *ok = true; + return fixedData; +} + +// [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" +// The correct quote will be chosen when writing + +static QString fixedPubidLiteral(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString result; + + if(QXmlUtils::isPublicID(data)) + result = data; + else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } + + if (result.indexOf(QLatin1Char('\'')) != -1 + && result.indexOf(QLatin1Char('"')) != -1) { + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } else { + result.remove(QLatin1Char('\'')); + } + } + + *ok = true; + return result; +} + +// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") +// The correct quote will be chosen when writing + +static QString fixedSystemLiteral(const QString &data, bool *ok) +{ + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) { + *ok = true; + return data; + } + + QString result = data; + + if (result.indexOf(QLatin1Char('\'')) != -1 + && result.indexOf(QLatin1Char('"')) != -1) { + if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) { + *ok = false; + return QString(); + } else { + result.remove(QLatin1Char('\'')); + } + } + + *ok = true; + return result; +} + +/************************************************************** + * + * QDomImplementationPrivate + * + **************************************************************/ + +QDomImplementationPrivate* QDomImplementationPrivate::clone() +{ + QDomImplementationPrivate* p = new QDomImplementationPrivate; + // We are not interested in this node + p->ref.deref(); + return p; +} + +/************************************************************** + * + * QDomImplementation + * + **************************************************************/ + +/*! + \class QDomImplementation + \reentrant + \brief The QDomImplementation class provides information about the + features of the DOM implementation. + + \inmodule QtXml + \ingroup xml-tools + + This class describes the features that are supported by the DOM + implementation. Currently the XML subset of DOM Level 1 and DOM + Level 2 Core are supported. + + Normally you will use the function QDomDocument::implementation() + to get the implementation object. + + You can create a new document type with createDocumentType() and a + new document with createDocument(). + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. For a more + general introduction of the DOM implementation see the QDomDocument + documentation. + + The QDom classes have a few issues of nonconformance with the XML + specifications that cannot be fixed in Qt 4 without breaking backward + compatibility. The QtXmlPatterns module and the QXmlStreamReader and + QXmlStreamWriter classes have a higher degree of a conformance. + + \sa hasFeature() +*/ + +/*! + Constructs a QDomImplementation object. +*/ +QDomImplementation::QDomImplementation() +{ + impl = 0; +} + +/*! + Constructs a copy of \a x. +*/ +QDomImplementation::QDomImplementation(const QDomImplementation &x) +{ + impl = x.impl; + if (impl) + impl->ref.ref(); +} + +QDomImplementation::QDomImplementation(QDomImplementationPrivate *p) +{ + // We want to be co-owners, so increase the reference count + impl = p; + if (impl) + impl->ref.ref(); +} + +/*! + Assigns \a x to this DOM implementation. +*/ +QDomImplementation& QDomImplementation::operator=(const QDomImplementation &x) +{ + if (x.impl) + x.impl->ref.ref(); + if (impl && !impl->ref.deref()) + delete impl; + impl = x.impl; + return *this; +} + +/*! + Returns true if \a x and this DOM implementation object were + created from the same QDomDocument; otherwise returns false. +*/ +bool QDomImplementation::operator==(const QDomImplementation &x) const +{ + return (impl == x.impl); +} + +/*! + Returns true if \a x and this DOM implementation object were + created from different QDomDocuments; otherwise returns false. +*/ +bool QDomImplementation::operator!=(const QDomImplementation &x) const +{ + return (impl != x.impl); +} + +/*! + Destroys the object and frees its resources. +*/ +QDomImplementation::~QDomImplementation() +{ + if (impl && !impl->ref.deref()) + delete impl; +} + +/*! + The function returns true if QDom implements the requested \a + version of a \a feature; otherwise returns false. + + The currently supported features and their versions: + \table + \header \i Feature \i Version + \row \i XML \i 1.0 + \endtable +*/ +bool QDomImplementation::hasFeature(const QString& feature, const QString& version) const +{ + if (feature == QLatin1String("XML")) { + if (version.isEmpty() || version == QLatin1String("1.0")) { + return true; + } + } + // ### add DOM level 2 features + return false; +} + +/*! + Creates a document type node for the name \a qName. + + \a publicId specifies the public identifier of the external + subset. If you specify an empty string (QString()) as the \a + publicId, this means that the document type has no public + identifier. + + \a systemId specifies the system identifier of the external + subset. If you specify an empty string as the \a systemId, this + means that the document type has no system identifier. + + Since you cannot have a public identifier without a system + identifier, the public identifier is set to an empty string if + there is no system identifier. + + DOM level 2 does not support any other document type declaration + features. + + The only way you can use a document type that was created this + way, is in combination with the createDocument() function to + create a QDomDocument with this document type. + + In the DOM specification, this is the only way to create a non-null + document. For historical reasons, Qt also allows to create the + document using the default empty constructor. The resulting document + is null, but becomes non-null when a factory function, for example + QDomDocument::createElement(), is called. The document also becomes + non-null when setContent() is called. + + \sa createDocument() +*/ +QDomDocumentType QDomImplementation::createDocumentType(const QString& qName, const QString& publicId, const QString& systemId) +{ + bool ok; + QString fixedName = fixedXmlName(qName, &ok, true); + if (!ok) + return QDomDocumentType(); + + QString fixedPublicId = fixedPubidLiteral(publicId, &ok); + if (!ok) + return QDomDocumentType(); + + QString fixedSystemId = fixedSystemLiteral(systemId, &ok); + if (!ok) + return QDomDocumentType(); + + QDomDocumentTypePrivate *dt = new QDomDocumentTypePrivate(0); + dt->name = fixedName; + if (systemId.isNull()) { + dt->publicId.clear(); + dt->systemId.clear(); + } else { + dt->publicId = fixedPublicId; + dt->systemId = fixedSystemId; + } + dt->ref.deref(); + return QDomDocumentType(dt); +} + +/*! + Creates a DOM document with the document type \a doctype. This + function also adds a root element node with the qualified name \a + qName and the namespace URI \a nsURI. +*/ +QDomDocument QDomImplementation::createDocument(const QString& nsURI, const QString& qName, const QDomDocumentType& doctype) +{ + QDomDocument doc(doctype); + QDomElement root = doc.createElementNS(nsURI, qName); + if (root.isNull()) + return QDomDocument(); + doc.appendChild(root); + return doc; +} + +/*! + Returns false if the object was created by + QDomDocument::implementation(); otherwise returns true. +*/ +bool QDomImplementation::isNull() +{ + return (impl == 0); +} + +/*! + \enum QDomImplementation::InvalidDataPolicy + + This enum specifies what should be done when a factory function + in QDomDocument is called with invalid data. + \value AcceptInvalidChars The data should be stored in the DOM object + anyway. In this case the resulting XML document might not be well-formed. + This is the default value and QDom's behavior in Qt < 4.1. + \value DropInvalidChars The invalid characters should be removed from + the data. + \value ReturnNullNode The factory function should return a null node. + + \sa setInvalidDataPolicy() invalidDataPolicy() +*/ + +/*! + \enum QDomNode::EncodingPolicy + \since 4.3 + + This enum specifies how QDomNode::save() determines what encoding to use + when serializing. + + \value EncodingFromDocument The encoding is fetched from the document. + \value EncodingFromTextStream The encoding is fetched from the QTextStream. + + See also the overload of the save() function that takes an EncodingPolicy. +*/ + +/*! + \since 4.1 + \nonreentrant + + Returns the invalid data policy, which specifies what should be done when + a factory function in QDomDocument is passed invalid data. + + \sa setInvalidDataPolicy() InvalidDataPolicy +*/ + +QDomImplementation::InvalidDataPolicy QDomImplementation::invalidDataPolicy() +{ + return QDomImplementationPrivate::invalidDataPolicy; +} + +/*! + \since 4.1 + \nonreentrant + + Sets the invalid data policy, which specifies what should be done when + a factory function in QDomDocument is passed invalid data. + + The \a policy is set for all instances of QDomDocument which already + exist and which will be created in the future. + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 0 + + \sa invalidDataPolicy() InvalidDataPolicy +*/ + +void QDomImplementation::setInvalidDataPolicy(InvalidDataPolicy policy) +{ + QDomImplementationPrivate::invalidDataPolicy = policy; +} + +/************************************************************** + * + * QDomNodeListPrivate + * + **************************************************************/ + +QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl) +{ + ref = 1; + node_impl = n_impl; + if (node_impl) + node_impl->ref.ref(); + timestamp = 0; +} + +QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl, const QString &name) +{ + ref = 1; + node_impl = n_impl; + if (node_impl) + node_impl->ref.ref(); + tagname = name; + timestamp = 0; +} + +QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl, const QString &_nsURI, const QString &localName) +{ + ref = 1; + node_impl = n_impl; + if (node_impl) + node_impl->ref.ref(); + tagname = localName; + nsURI = _nsURI; + timestamp = 0; +} + +QDomNodeListPrivate::~QDomNodeListPrivate() +{ + if (node_impl && !node_impl->ref.deref()) + delete node_impl; +} + +bool QDomNodeListPrivate::operator==(const QDomNodeListPrivate &other) const +{ + return (node_impl == other.node_impl) && (tagname == other.tagname); +} + +bool QDomNodeListPrivate::operator!=(const QDomNodeListPrivate &other) const +{ + return (node_impl != other.node_impl) || (tagname != other.tagname); +} + +void QDomNodeListPrivate::createList() +{ + if (!node_impl) + return; + + const QDomDocumentPrivate *const doc = node_impl->ownerDocument(); + if (doc && timestamp != doc->nodeListTime) + timestamp = doc->nodeListTime; + + QDomNodePrivate* p = node_impl->first; + + list.clear(); + if (tagname.isNull()) { + while (p) { + list.append(p); + p = p->next; + } + } else if (nsURI.isNull()) { + while (p && p != node_impl) { + if (p->isElement() && p->nodeName() == tagname) { + list.append(p); + } + if (p->first) + p = p->first; + else if (p->next) + p = p->next; + else { + p = p->parent(); + while (p && p != node_impl && !p->next) + p = p->parent(); + if (p && p != node_impl) + p = p->next; + } + } + } else { + while (p && p != node_impl) { + if (p->isElement() && p->name==tagname && p->namespaceURI==nsURI) { + list.append(p); + } + if (p->first) + p = p->first; + else if (p->next) + p = p->next; + else { + p = p->parent(); + while (p && p != node_impl && !p->next) + p = p->parent(); + if (p && p != node_impl) + p = p->next; + } + } + } +} + +QDomNodePrivate* QDomNodeListPrivate::item(int index) +{ + if (!node_impl) + return 0; + + const QDomDocumentPrivate *const doc = node_impl->ownerDocument(); + if (!doc || timestamp != doc->nodeListTime) + createList(); + + if (index >= list.size()) + return 0; + + return list.at(index); +} + +uint QDomNodeListPrivate::length() const +{ + if (!node_impl) + return 0; + + const QDomDocumentPrivate *const doc = node_impl->ownerDocument(); + if (!doc || timestamp != doc->nodeListTime) { + QDomNodeListPrivate *that = const_cast<QDomNodeListPrivate *>(this); + that->createList(); + } + + return list.count(); +} + +/************************************************************** + * + * QDomNodeList + * + **************************************************************/ + +/*! + \class QDomNodeList + \reentrant + \brief The QDomNodeList class is a list of QDomNode objects. + + \inmodule QtXml + \ingroup xml-tools + + Lists can be obtained by QDomDocument::elementsByTagName() and + QDomNode::childNodes(). The Document Object Model (DOM) requires + these lists to be "live": whenever you change the underlying + document, the contents of the list will get updated. + + You can get a particular node from the list with item(). The + number of items in the list is returned by length(). + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. + + \sa QDomNode::childNodes() QDomDocument::elementsByTagName() +*/ + +/*! + Creates an empty node list. +*/ +QDomNodeList::QDomNodeList() +{ + impl = 0; +} + +QDomNodeList::QDomNodeList(QDomNodeListPrivate* p) +{ + impl = p; +} + +/*! + Constructs a copy of \a n. +*/ +QDomNodeList::QDomNodeList(const QDomNodeList& n) +{ + impl = n.impl; + if (impl) + impl->ref.ref(); +} + +/*! + Assigns \a n to this node list. +*/ +QDomNodeList& QDomNodeList::operator=(const QDomNodeList &n) +{ + if (n.impl) + n.impl->ref.ref(); + if (impl && !impl->ref.deref()) + delete impl; + impl = n.impl; + return *this; +} + +/*! + Returns true if the node list \a n and this node list are equal; + otherwise returns false. +*/ +bool QDomNodeList::operator==(const QDomNodeList &n) const +{ + if (impl == n.impl) + return true; + if (!impl || !n.impl) + return false; + return (*impl == *n.impl); +} + +/*! + Returns true the node list \a n and this node list are not equal; + otherwise returns false. +*/ +bool QDomNodeList::operator!=(const QDomNodeList &n) const +{ + return !operator==(n); +} + +/*! + Destroys the object and frees its resources. +*/ +QDomNodeList::~QDomNodeList() +{ + if (impl && !impl->ref.deref()) + delete impl; +} + +/*! + Returns the node at position \a index. + + If \a index is negative or if \a index >= length() then a null + node is returned (i.e. a node for which QDomNode::isNull() returns + true). + + \sa length() +*/ +QDomNode QDomNodeList::item(int index) const +{ + if (!impl) + return QDomNode(); + + return QDomNode(impl->item(index)); +} + +/*! + Returns the number of nodes in the list. +*/ +uint QDomNodeList::length() const +{ + if (!impl) + return 0; + return impl->length(); +} + +/*! + \fn bool QDomNodeList::isEmpty() const + + Returns true if the list contains no items; otherwise returns false. + This function is provided for Qt API consistency. +*/ + +/*! + \fn int QDomNodeList::count() const + + This function is provided for Qt API consistency. It is equivalent to length(). +*/ + +/*! + \fn int QDomNodeList::size() const + + This function is provided for Qt API consistency. It is equivalent to length(). +*/ + +/*! + \fn QDomNode QDomNodeList::at(int index) const + + This function is provided for Qt API consistency. It is equivalent + to item(). + + If \a index is negative or if \a index >= length() then a null + node is returned (i.e. a node for which QDomNode::isNull() returns + true). +*/ + +/************************************************************** + * + * QDomNodePrivate + * + **************************************************************/ + +inline void QDomNodePrivate::setOwnerDocument(QDomDocumentPrivate *doc) +{ + ownerNode = doc; + hasParent = false; +} + +QDomNodePrivate::QDomNodePrivate(QDomDocumentPrivate *doc, QDomNodePrivate *par) +{ + ref = 1; + if (par) + setParent(par); + else + setOwnerDocument(doc); + prev = 0; + next = 0; + first = 0; + last = 0; + createdWithDom1Interface = true; + lineNumber = -1; + columnNumber = -1; +} + +QDomNodePrivate::QDomNodePrivate(QDomNodePrivate *n, bool deep) +{ + ref = 1; + setOwnerDocument(n->ownerDocument()); + prev = 0; + next = 0; + first = 0; + last = 0; + + name = n->name; + value = n->value; + prefix = n->prefix; + namespaceURI = n->namespaceURI; + createdWithDom1Interface = n->createdWithDom1Interface; + lineNumber = -1; + columnNumber = -1; + + if (!deep) + return; + + for (QDomNodePrivate* x = n->first; x; x = x->next) + appendChild(x->cloneNode(true)); +} + +QDomNodePrivate::~QDomNodePrivate() +{ + QDomNodePrivate* p = first; + QDomNodePrivate* n; + + while (p) { + n = p->next; + if (!p->ref.deref()) + delete p; + else + p->setNoParent(); + p = n; + } + first = 0; + last = 0; +} + +void QDomNodePrivate::clear() +{ + QDomNodePrivate* p = first; + QDomNodePrivate* n; + + while (p) { + n = p->next; + if (!p->ref.deref()) + delete p; + p = n; + } + first = 0; + last = 0; +} + +QDomNodePrivate* QDomNodePrivate::namedItem(const QString &n) +{ + QDomNodePrivate* p = first; + while (p) { + if (p->nodeName() == n) + return p; + p = p->next; + } + return 0; +} + + +QDomNodePrivate* QDomNodePrivate::insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild) +{ + // Error check + if (!newChild) + return 0; + + // Error check + if (newChild == refChild) + return 0; + + // Error check + if (refChild && refChild->parent() != this) + return 0; + + // "mark lists as dirty" + QDomDocumentPrivate *const doc = ownerDocument(); + if(doc) + doc->nodeListTime++; + + // Special handling for inserting a fragment. We just insert + // all elements of the fragment instead of the fragment itself. + if (newChild->isDocumentFragment()) { + // Fragment is empty ? + if (newChild->first == 0) + return newChild; + + // New parent + QDomNodePrivate* n = newChild->first; + while (n) { + n->setParent(this); + n = n->next; + } + + // Insert at the beginning ? + if (!refChild || refChild->prev == 0) { + if (first) + first->prev = newChild->last; + newChild->last->next = first; + if (!last) + last = newChild->last; + first = newChild->first; + } else { + // Insert in the middle + newChild->last->next = refChild; + newChild->first->prev = refChild->prev; + refChild->prev->next = newChild->first; + refChild->prev = newChild->last; + } + + // No need to increase the reference since QDomDocumentFragment + // does not decrease the reference. + + // Remove the nodes from the fragment + newChild->first = 0; + newChild->last = 0; + return newChild; + } + + // No more errors can occur now, so we take + // ownership of the node. + newChild->ref.ref(); + + if (newChild->parent()) + newChild->parent()->removeChild(newChild); + + newChild->setParent(this); + + if (!refChild) { + if (first) + first->prev = newChild; + newChild->next = first; + if (!last) + last = newChild; + first = newChild; + return newChild; + } + + if (refChild->prev == 0) { + if (first) + first->prev = newChild; + newChild->next = first; + if (!last) + last = newChild; + first = newChild; + return newChild; + } + + newChild->next = refChild; + newChild->prev = refChild->prev; + refChild->prev->next = newChild; + refChild->prev = newChild; + + return newChild; +} + +QDomNodePrivate* QDomNodePrivate::insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild) +{ + // Error check + if (!newChild) + return 0; + + // Error check + if (newChild == refChild) + return 0; + + // Error check + if (refChild && refChild->parent() != this) + return 0; + + // "mark lists as dirty" + QDomDocumentPrivate *const doc = ownerDocument(); + if(doc) + doc->nodeListTime++; + + // Special handling for inserting a fragment. We just insert + // all elements of the fragment instead of the fragment itself. + if (newChild->isDocumentFragment()) { + // Fragment is empty ? + if (newChild->first == 0) + return newChild; + + // New parent + QDomNodePrivate* n = newChild->first; + while (n) { + n->setParent(this); + n = n->next; + } + + // Insert at the end + if (!refChild || refChild->next == 0) { + if (last) + last->next = newChild->first; + newChild->first->prev = last; + if (!first) + first = newChild->first; + last = newChild->last; + } else { // Insert in the middle + newChild->first->prev = refChild; + newChild->last->next = refChild->next; + refChild->next->prev = newChild->last; + refChild->next = newChild->first; + } + + // No need to increase the reference since QDomDocumentFragment + // does not decrease the reference. + + // Remove the nodes from the fragment + newChild->first = 0; + newChild->last = 0; + return newChild; + } + + // Release new node from its current parent + if (newChild->parent()) + newChild->parent()->removeChild(newChild); + + // No more errors can occur now, so we take + // ownership of the node + newChild->ref.ref(); + + newChild->setParent(this); + + // Insert at the end + if (!refChild) { + if (last) + last->next = newChild; + newChild->prev = last; + if (!first) + first = newChild; + last = newChild; + return newChild; + } + + if (refChild->next == 0) { + if (last) + last->next = newChild; + newChild->prev = last; + if (!first) + first = newChild; + last = newChild; + return newChild; + } + + newChild->prev = refChild; + newChild->next = refChild->next; + refChild->next->prev = newChild; + refChild->next = newChild; + + return newChild; +} + +QDomNodePrivate* QDomNodePrivate::replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild) +{ + if (!newChild || !oldChild) + return 0; + if (oldChild->parent() != this) + return 0; + if (newChild == oldChild) + return 0; + + // mark lists as dirty + QDomDocumentPrivate *const doc = ownerDocument(); + if(doc) + doc->nodeListTime++; + + // Special handling for inserting a fragment. We just insert + // all elements of the fragment instead of the fragment itself. + if (newChild->isDocumentFragment()) { + // Fragment is empty ? + if (newChild->first == 0) + return newChild; + + // New parent + QDomNodePrivate* n = newChild->first; + while (n) { + n->setParent(this); + n = n->next; + } + + + if (oldChild->next) + oldChild->next->prev = newChild->last; + if (oldChild->prev) + oldChild->prev->next = newChild->first; + + newChild->last->next = oldChild->next; + newChild->first->prev = oldChild->prev; + + if (first == oldChild) + first = newChild->first; + if (last == oldChild) + last = newChild->last; + + oldChild->setNoParent(); + oldChild->next = 0; + oldChild->prev = 0; + + // No need to increase the reference since QDomDocumentFragment + // does not decrease the reference. + + // Remove the nodes from the fragment + newChild->first = 0; + newChild->last = 0; + + // We are no longer interested in the old node + if (oldChild) + oldChild->ref.deref(); + + return oldChild; + } + + // No more errors can occur now, so we take + // ownership of the node + newChild->ref.ref(); + + // Release new node from its current parent + if (newChild->parent()) + newChild->parent()->removeChild(newChild); + + newChild->setParent(this); + + if (oldChild->next) + oldChild->next->prev = newChild; + if (oldChild->prev) + oldChild->prev->next = newChild; + + newChild->next = oldChild->next; + newChild->prev = oldChild->prev; + + if (first == oldChild) + first = newChild; + if (last == oldChild) + last = newChild; + + oldChild->setNoParent(); + oldChild->next = 0; + oldChild->prev = 0; + + // We are no longer interested in the old node + if (oldChild) + oldChild->ref.deref(); + + return oldChild; +} + +QDomNodePrivate* QDomNodePrivate::removeChild(QDomNodePrivate* oldChild) +{ + // Error check + if (oldChild->parent() != this) + return 0; + + // "mark lists as dirty" + QDomDocumentPrivate *const doc = ownerDocument(); + if(doc) + doc->nodeListTime++; + + // Perhaps oldChild was just created with "createElement" or that. In this case + // its parent is QDomDocument but it is not part of the documents child list. + if (oldChild->next == 0 && oldChild->prev == 0 && first != oldChild) + return 0; + + if (oldChild->next) + oldChild->next->prev = oldChild->prev; + if (oldChild->prev) + oldChild->prev->next = oldChild->next; + + if (last == oldChild) + last = oldChild->prev; + if (first == oldChild) + first = oldChild->next; + + oldChild->setNoParent(); + oldChild->next = 0; + oldChild->prev = 0; + + // We are no longer interested in the old node + if (oldChild) + oldChild->ref.deref(); + + return oldChild; +} + +QDomNodePrivate* QDomNodePrivate::appendChild(QDomNodePrivate* newChild) +{ + // No reference manipulation needed. Done in insertAfter. + return insertAfter(newChild, 0); +} + +QDomDocumentPrivate* QDomNodePrivate::ownerDocument() +{ + QDomNodePrivate* p = this; + while (p && !p->isDocument()) { + if (!p->hasParent) + return (QDomDocumentPrivate*)p->ownerNode; + p = p->parent(); + } + + return static_cast<QDomDocumentPrivate *>(p); +} + +QDomNodePrivate* QDomNodePrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomNodePrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +static void qNormalizeNode(QDomNodePrivate* n) +{ + QDomNodePrivate* p = n->first; + QDomTextPrivate* t = 0; + + while (p) { + if (p->isText()) { + if (t) { + QDomNodePrivate* tmp = p->next; + t->appendData(p->nodeValue()); + n->removeChild(p); + p = tmp; + } else { + t = (QDomTextPrivate*)p; + p = p->next; + } + } else { + p = p->next; + t = 0; + } + } +} +void QDomNodePrivate::normalize() +{ + // ### This one has moved from QDomElementPrivate to this position. It is + // not tested. + qNormalizeNode(this); +} + +/*! \internal + \a depth is used for indentation, it seems. + */ +void QDomNodePrivate::save(QTextStream& s, int depth, int indent) const +{ + const QDomNodePrivate* n = first; + while (n) { + n->save(s, depth, indent); + n = n->next; + } +} + +void QDomNodePrivate::setLocation(int lineNumber, int columnNumber) +{ + this->lineNumber = lineNumber; + this->columnNumber = columnNumber; +} + +/************************************************************** + * + * QDomNode + * + **************************************************************/ + +#define IMPL ((QDomNodePrivate*)impl) + +/*! + \class QDomNode + \reentrant + \brief The QDomNode class is the base class for all the nodes in a DOM tree. + + \inmodule QtXml + \ingroup xml-tools + \mainclass + + Many functions in the DOM return a QDomNode. + + You can find out the type of a node using isAttr(), + isCDATASection(), isDocumentFragment(), isDocument(), + isDocumentType(), isElement(), isEntityReference(), isText(), + isEntity(), isNotation(), isProcessingInstruction(), + isCharacterData() and isComment(). + + A QDomNode can be converted into one of its subclasses using + toAttr(), toCDATASection(), toDocumentFragment(), toDocument(), + toDocumentType(), toElement(), toEntityReference(), toText(), + toEntity(), toNotation(), toProcessingInstruction(), + toCharacterData() or toComment(). You can convert a node to a null + node with clear(). + + Copies of the QDomNode class share their data using explicit + sharing. This means that modifying one node will change all + copies. This is especially useful in combination with functions + which return a QDomNode, e.g. firstChild(). You can make an + independent (deep) copy of the node with cloneNode(). + + A QDomNode can be null, much like a null pointer. Creating a copy + of a null node results in another null node. It is not + possible to modify a null node, but it is possible to assign another, + possibly non-null node to it. In this case, the copy of the null node + will remain null. You can check if a QDomNode is null by calling isNull(). + The empty constructor of a QDomNode (or any of the derived classes) creates + a null node. + + Nodes are inserted with insertBefore(), insertAfter() or + appendChild(). You can replace one node with another using + replaceChild() and remove a node with removeChild(). + + To traverse nodes use firstChild() to get a node's first child (if + any), and nextSibling() to traverse. QDomNode also provides + lastChild(), previousSibling() and parentNode(). To find the first + child node with a particular node name use namedItem(). + + To find out if a node has children use hasChildNodes() and to get + a list of all of a node's children use childNodes(). + + The node's name and value (the meaning of which varies depending + on its type) is returned by nodeName() and nodeValue() + respectively. The node's type is returned by nodeType(). The + node's value can be set with setNodeValue(). + + The document to which the node belongs is returned by + ownerDocument(). + + Adjacent QDomText nodes can be merged into a single node with + normalize(). + + \l QDomElement nodes have attributes which can be retrieved with + attributes(). + + QDomElement and QDomAttr nodes can have namespaces which can be + retrieved with namespaceURI(). Their local name is retrieved with + localName(), and their prefix with prefix(). The prefix can be set + with setPrefix(). + + You can write the XML representation of the node to a text stream + with save(). + + The following example looks for the first element in an XML document and + prints the names of all the elements that are its direct children. + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 1 + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs a \link isNull() null\endlink node. +*/ +QDomNode::QDomNode() +{ + impl = 0; +} + +/*! + Constructs a copy of \a n. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomNode::QDomNode(const QDomNode &n) +{ + impl = n.impl; + if (impl) + impl->ref.ref(); +} + +/*! \internal + Constructs a new node for the data \a n. +*/ +QDomNode::QDomNode(QDomNodePrivate *n) +{ + impl = n; + if (impl) + impl->ref.ref(); +} + +/*! + Assigns a copy of \a n to this DOM node. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomNode& QDomNode::operator=(const QDomNode &n) +{ + if (n.impl) + n.impl->ref.ref(); + if (impl && !impl->ref.deref()) + delete impl; + impl = n.impl; + return *this; +} + +/*! + Returns true if \a n and this DOM node are equal; otherwise + returns false. + + Any instance of QDomNode acts as a reference to an underlying data + structure in QDomDocument. The test for equality checks if the two + references point to the same underlying node. For example: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 2 + + The two nodes (QDomElement is a QDomNode subclass) both refer to + the document's root element, and \c {element1 == element2} will + return true. On the other hand: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 3 + + Even though both nodes are empty elements carrying the same name, + \c {element3 == element4} will return false because they refer to + two different nodes in the underlying data structure. +*/ +bool QDomNode::operator== (const QDomNode& n) const +{ + return (impl == n.impl); +} + +/*! + Returns true if \a n and this DOM node are not equal; otherwise + returns false. +*/ +bool QDomNode::operator!= (const QDomNode& n) const +{ + return (impl != n.impl); +} + +/*! + Destroys the object and frees its resources. +*/ +QDomNode::~QDomNode() +{ + if (impl && !impl->ref.deref()) + delete impl; +} + +/*! + Returns the name of the node. + + The meaning of the name depends on the subclass: + + \table + \header \i Name \i Meaning + \row \i QDomAttr \i The name of the attribute + \row \i QDomCDATASection \i The string "#cdata-section" + \row \i QDomComment \i The string "#comment" + \row \i QDomDocument \i The string "#document" + \row \i QDomDocumentFragment \i The string "#document-fragment" + \row \i QDomDocumentType \i The name of the document type + \row \i QDomElement \i The tag name + \row \i QDomEntity \i The name of the entity + \row \i QDomEntityReference \i The name of the referenced entity + \row \i QDomNotation \i The name of the notation + \row \i QDomProcessingInstruction \i The target of the processing instruction + \row \i QDomText \i The string "#text" + \endtable + + \bold{Note:} This function does not take the presence of namespaces into account + when processing the names of element and attribute nodes. As a result, the + returned name can contain any namespace prefix that may be present. + To obtain the node name of an element or attribute, use localName(); to + obtain the namespace prefix, use namespaceURI(). + + \sa nodeValue() +*/ +QString QDomNode::nodeName() const +{ + if (!impl) + return QString(); + + if (!IMPL->prefix.isEmpty()) + return IMPL->prefix + QLatin1Char(':') + IMPL->name; + return IMPL->name; +} + +/*! + Returns the value of the node. + + The meaning of the value depends on the subclass: + \table + \header \i Name \i Meaning + \row \i QDomAttr \i The attribute value + \row \i QDomCDATASection \i The content of the CDATA section + \row \i QDomComment \i The comment + \row \i QDomProcessingInstruction \i The data of the processing instruction + \row \i QDomText \i The text + \endtable + + All the other subclasses do not have a node value and will return + an empty string. + + \sa setNodeValue() nodeName() +*/ +QString QDomNode::nodeValue() const +{ + if (!impl) + return QString(); + return IMPL->value; +} + +/*! + Sets the node's value to \a v. + + \sa nodeValue() +*/ +void QDomNode::setNodeValue(const QString& v) +{ + if (!impl) + return; + IMPL->setNodeValue(v); +} + +/*! + \enum QDomNode::NodeType + + This enum defines the type of the node: + \value ElementNode + \value AttributeNode + \value TextNode + \value CDATASectionNode + \value EntityReferenceNode + \value EntityNode + \value ProcessingInstructionNode + \value CommentNode + \value DocumentNode + \value DocumentTypeNode + \value DocumentFragmentNode + \value NotationNode + \value BaseNode A QDomNode object, i.e. not a QDomNode subclass. + \value CharacterDataNode +*/ + +/*! + Returns the type of the node. + + \sa toAttr(), toCDATASection(), toDocumentFragment(), + toDocument() toDocumentType(), toElement(), toEntityReference(), + toText(), toEntity() toNotation(), toProcessingInstruction(), + toCharacterData(), toComment() +*/ +QDomNode::NodeType QDomNode::nodeType() const +{ + if (!impl) + return QDomNode::BaseNode; + return IMPL->nodeType(); +} + +/*! + Returns the parent node. If this node has no parent, a null node + is returned (i.e. a node for which isNull() returns true). +*/ +QDomNode QDomNode::parentNode() const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->parent()); +} + +/*! + Returns a list of all direct child nodes. + + Most often you will call this function on a QDomElement object. + + For example, if the XML document looks like this: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 4 + Then the list of child nodes for the "body"-element will contain + the node created by the <h1> tag and the node created by the + <p> tag. + + The nodes in the list are not copied; so changing the nodes in the + list will also change the children of this node. + + \sa firstChild() lastChild() +*/ +QDomNodeList QDomNode::childNodes() const +{ + if (!impl) + return QDomNodeList(); + return QDomNodeList(new QDomNodeListPrivate(impl)); +} + +/*! + Returns the first child of the node. If there is no child node, a + \link isNull() null node\endlink is returned. Changing the + returned node will also change the node in the document tree. + + \sa lastChild() childNodes() +*/ +QDomNode QDomNode::firstChild() const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->first); +} + +/*! + Returns the last child of the node. If there is no child node, a + \link isNull() null node\endlink is returned. Changing the + returned node will also change the node in the document tree. + + \sa firstChild() childNodes() +*/ +QDomNode QDomNode::lastChild() const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->last); +} + +/*! + Returns the previous sibling in the document tree. Changing the + returned node will also change the node in the document tree. + + For example, if you have XML like this: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 5 + and this QDomNode represents the <p> tag, previousSibling() + will return the node representing the <h1> tag. + + \sa nextSibling() +*/ +QDomNode QDomNode::previousSibling() const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->prev); +} + +/*! + Returns the next sibling in the document tree. Changing the + returned node will also change the node in the document tree. + + If you have XML like this: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 6 + and this QDomNode represents the <p> tag, nextSibling() will + return the node representing the <h2> tag. + + \sa previousSibling() +*/ +QDomNode QDomNode::nextSibling() const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->next); +} + + +// ###### don't think this is part of the DOM and +/*! + Returns a named node map of all attributes. Attributes are only + provided for \l{QDomElement}s. + + Changing the attributes in the map will also change the attributes + of this QDomNode. +*/ +QDomNamedNodeMap QDomNode::attributes() const +{ + if (!impl || !impl->isElement()) + return QDomNamedNodeMap(); + + return QDomNamedNodeMap(static_cast<QDomElementPrivate *>(impl)->attributes()); +} + +/*! + Returns the document to which this node belongs. +*/ +QDomDocument QDomNode::ownerDocument() const +{ + if (!impl) + return QDomDocument(); + return QDomDocument(IMPL->ownerDocument()); +} + +/*! + Creates a deep (not shallow) copy of the QDomNode. + + If \a deep is true, then the cloning is done recursively which + means that all the node's children are deep copied too. If \a deep + is false only the node itself is copied and the copy will have no + child nodes. +*/ +QDomNode QDomNode::cloneNode(bool deep) const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->cloneNode(deep)); +} + +/*! + Calling normalize() on an element converts all its children into a + standard form. This means that adjacent QDomText objects will be + merged into a single text object (QDomCDATASection nodes are not + merged). +*/ +void QDomNode::normalize() +{ + if (!impl) + return; + IMPL->normalize(); +} + +/*! + Returns true if the DOM implementation implements the feature \a + feature and this feature is supported by this node in the version + \a version; otherwise returns false. + + \sa QDomImplementation::hasFeature() +*/ +bool QDomNode::isSupported(const QString& feature, const QString& version) const +{ + QDomImplementation i; + return i.hasFeature(feature, version); +} + +/*! + Returns the namespace URI of this node or an empty string if the + node has no namespace URI. + + Only nodes of type \link QDomNode::NodeType ElementNode\endlink or + \link QDomNode::NodeType AttributeNode\endlink can have + namespaces. A namespace URI must be specified at creation time and + cannot be changed later. + + \sa prefix() localName() QDomDocument::createElementNS() + QDomDocument::createAttributeNS() +*/ +QString QDomNode::namespaceURI() const +{ + if (!impl) + return QString(); + return IMPL->namespaceURI; +} + +/*! + Returns the namespace prefix of the node or an empty string if the + node has no namespace prefix. + + Only nodes of type \link QDomNode::NodeType ElementNode\endlink or + \link QDomNode::NodeType AttributeNode\endlink can have + namespaces. A namespace prefix must be specified at creation time. + If a node was created with a namespace prefix, you can change it + later with setPrefix(). + + If you create an element or attribute with + QDomDocument::createElement() or QDomDocument::createAttribute(), + the prefix will be an empty string. If you use + QDomDocument::createElementNS() or + QDomDocument::createAttributeNS() instead, the prefix will not be + an empty string; but it might be an empty string if the name does + not have a prefix. + + \sa setPrefix() localName() namespaceURI() + QDomDocument::createElementNS() QDomDocument::createAttributeNS() +*/ +QString QDomNode::prefix() const +{ + if (!impl) + return QString(); + return IMPL->prefix; +} + +/*! + If the node has a namespace prefix, this function changes the + namespace prefix of the node to \a pre. Otherwise this function + does nothing. + + Only nodes of type \link QDomNode::NodeType ElementNode\endlink or + \link QDomNode::NodeType AttributeNode\endlink can have + namespaces. A namespace prefix must have be specified at creation + time; it is not possible to add a namespace prefix afterwards. + + \sa prefix() localName() namespaceURI() + QDomDocument::createElementNS() QDomDocument::createAttributeNS() +*/ +void QDomNode::setPrefix(const QString& pre) +{ + if (!impl || IMPL->prefix.isNull()) + return; + if (isAttr() || isElement()) + IMPL->prefix = pre; +} + +/*! + If the node uses namespaces, this function returns the local name + of the node; otherwise it returns an empty string. + + Only nodes of type \link QDomNode::NodeType ElementNode\endlink or + \link QDomNode::NodeType AttributeNode\endlink can have + namespaces. A namespace must have been specified at creation time; + it is not possible to add a namespace afterwards. + + \sa prefix() namespaceURI() QDomDocument::createElementNS() + QDomDocument::createAttributeNS() +*/ +QString QDomNode::localName() const +{ + if (!impl || IMPL->createdWithDom1Interface) + return QString(); + return IMPL->name; +} + +/*! + Returns true if the node has attributes; otherwise returns false. + + \sa attributes() +*/ +bool QDomNode::hasAttributes() const +{ + if (!impl || !impl->isElement()) + return false; + return static_cast<QDomElementPrivate *>(impl)->hasAttributes(); +} + +/*! + Inserts the node \a newChild before the child node \a refChild. + \a refChild must be a direct child of this node. If \a refChild is + \link isNull() null\endlink then \a newChild is inserted as the + node's first child. + + If \a newChild is the child of another node, it is reparented to + this node. If \a newChild is a child of this node, then its + position in the list of children is changed. + + If \a newChild is a QDomDocumentFragment, then the children of the + fragment are removed from the fragment and inserted before \a + refChild. + + Returns a new reference to \a newChild on success or a \link + isNull() null node\endlink on failure. + + The DOM specification disallow inserting attribute nodes, but due + to historical reasons QDom accept them nevertheless. + + \sa insertAfter() replaceChild() removeChild() appendChild() +*/ +QDomNode QDomNode::insertBefore(const QDomNode& newChild, const QDomNode& refChild) +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->insertBefore(newChild.impl, refChild.impl)); +} + +/*! + Inserts the node \a newChild after the child node \a refChild. \a + refChild must be a direct child of this node. If \a refChild is + \link isNull() null\endlink then \a newChild is appended as this + node's last child. + + If \a newChild is the child of another node, it is reparented to + this node. If \a newChild is a child of this node, then its + position in the list of children is changed. + + If \a newChild is a QDomDocumentFragment, then the children of the + fragment are removed from the fragment and inserted after \a + refChild. + + Returns a new reference to \a newChild on success or a \link + isNull() null node\endlink on failure. + + The DOM specification disallow inserting attribute nodes, but due + to historical reasons QDom accept them nevertheless. + + \sa insertBefore() replaceChild() removeChild() appendChild() +*/ +QDomNode QDomNode::insertAfter(const QDomNode& newChild, const QDomNode& refChild) +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->insertAfter(newChild.impl, refChild.impl)); +} + +/*! + Replaces \a oldChild with \a newChild. \a oldChild must be a + direct child of this node. + + If \a newChild is the child of another node, it is reparented to + this node. If \a newChild is a child of this node, then its + position in the list of children is changed. + + If \a newChild is a QDomDocumentFragment, then \a oldChild is + replaced by all of the children of the fragment. + + Returns a new reference to \a oldChild on success or a \link + isNull() null node\endlink an failure. + + \sa insertBefore() insertAfter() removeChild() appendChild() +*/ +QDomNode QDomNode::replaceChild(const QDomNode& newChild, const QDomNode& oldChild) +{ + if (!impl || !newChild.impl || !oldChild.impl) + return QDomNode(); + return QDomNode(IMPL->replaceChild(newChild.impl, oldChild.impl)); +} + +/*! + Removes \a oldChild from the list of children. \a oldChild must be + a direct child of this node. + + Returns a new reference to \a oldChild on success or a \link + isNull() null node\endlink on failure. + + \sa insertBefore() insertAfter() replaceChild() appendChild() +*/ +QDomNode QDomNode::removeChild(const QDomNode& oldChild) +{ + if (!impl) + return QDomNode(); + + if (oldChild.isNull()) + return QDomNode(); + + return QDomNode(IMPL->removeChild(oldChild.impl)); +} + +/*! + Appends \a newChild as the node's last child. + + If \a newChild is the child of another node, it is reparented to + this node. If \a newChild is a child of this node, then its + position in the list of children is changed. + + If \a newChild is a QDomDocumentFragment, then the children of the + fragment are removed from the fragment and appended. + + If \a newChild is a QDomElement and this node is a QDomDocument that + already has an element node as a child, \a newChild is not added as + a child and a null node is returned. + + Calling this function on a null node(created, for example, with the + default constructor) does nothing. + + The DOM specification disallow inserting attribute nodes, but due + to historical reasons QDom accept them nevertheless. + + \sa insertBefore() insertAfter() replaceChild() removeChild() +*/ +QDomNode QDomNode::appendChild(const QDomNode& newChild) +{ + if (!impl) { + qWarning("Calling appendChild() on a null node does nothing."); + return QDomNode(); + } + return QDomNode(IMPL->appendChild(newChild.impl)); +} + +/*! + Returns true if the node has one or more children; otherwise + returns false. +*/ +bool QDomNode::hasChildNodes() const +{ + if (!impl) + return false; + return IMPL->first != 0; +} + +/*! + Returns true if this node is null (i.e. if it has no type or + contents); otherwise returns false. +*/ +bool QDomNode::isNull() const +{ + return (impl == 0); +} + +/*! + Converts the node into a null node; if it was not a null node + before, its type and contents are deleted. + + \sa isNull() +*/ +void QDomNode::clear() +{ + if (impl && !impl->ref.deref()) + delete impl; + impl = 0; +} + +/*! + Returns the first direct child node for which nodeName() equals \a + name. + + If no such direct child exists, a \link isNull() null node\endlink + is returned. + + \sa nodeName() +*/ +QDomNode QDomNode::namedItem(const QString& name) const +{ + if (!impl) + return QDomNode(); + return QDomNode(impl->namedItem(name)); +} + +/*! + Writes the XML representation of the node and all its children to + the stream \a str. This function uses \a indent as the amount of + space to indent the node. + + If this node is a document node, the encoding of text stream \a str's encoding is + set by treating a processing instruction by name "xml" as an XML declaration, if such a one exists, + and otherwise defaults to UTF-8. XML declarations are not processing instructions, but this + behavior exists for historical reasons. If this node is not a document node, + the text stream's encoding is used. + + If the document contains invalid XML characters or characters that cannot be + encoded in the given encoding, the result and behavior is undefined. + +*/ +void QDomNode::save(QTextStream& str, int indent) const +{ + save(str, indent, QDomNode::EncodingFromDocument); +} + +/*! + If \a encodingPolicy is QDomNode::EncodingFromDocument, this function behaves as save(QTextStream &str, int indent). + + If \a encodingPolicy is EncodingFromTextStream and this node is a document node, this + function behaves as save(QTextStream &str, int indent) with the exception that the encoding + specified in the text stream \a str is used. + + If the document contains invalid XML characters or characters that cannot be + encoded in the given encoding, the result and behavior is undefined. + + \since 4.2 + */ +void QDomNode::save(QTextStream& str, int indent, EncodingPolicy encodingPolicy) const +{ + if (!impl) + return; + + if(isDocument()) + static_cast<const QDomDocumentPrivate *>(impl)->saveDocument(str, indent, encodingPolicy); + else + IMPL->save(str, 1, indent); +} + +/*! + \relates QDomNode + + Writes the XML representation of the node \a node and all its + children to the stream \a str. +*/ +QTextStream& operator<<(QTextStream& str, const QDomNode& node) +{ + node.save(str, 1); + + return str; +} + +/*! + Returns true if the node is an attribute; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomAttribute; you can get the QDomAttribute with + toAttribute(). + + \sa toAttr() +*/ +bool QDomNode::isAttr() const +{ + if(impl) + return impl->isAttr(); + return false; +} + +/*! + Returns true if the node is a CDATA section; otherwise returns + false. + + If this function returns true, it does not imply that this object + is a QDomCDATASection; you can get the QDomCDATASection with + toCDATASection(). + + \sa toCDATASection() +*/ +bool QDomNode::isCDATASection() const +{ + if(impl) + return impl->isCDATASection(); + return false; +} + +/*! + Returns true if the node is a document fragment; otherwise returns + false. + + If this function returns true, it does not imply that this object + is a QDomDocumentFragment; you can get the QDomDocumentFragment + with toDocumentFragment(). + + \sa toDocumentFragment() +*/ +bool QDomNode::isDocumentFragment() const +{ + if(impl) + return impl->isDocumentFragment(); + return false; +} + +/*! + Returns true if the node is a document; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomDocument; you can get the QDomDocument with toDocument(). + + \sa toDocument() +*/ +bool QDomNode::isDocument() const +{ + if(impl) + return impl->isDocument(); + return false; +} + +/*! + Returns true if the node is a document type; otherwise returns + false. + + If this function returns true, it does not imply that this object + is a QDomDocumentType; you can get the QDomDocumentType with + toDocumentType(). + + \sa toDocumentType() +*/ +bool QDomNode::isDocumentType() const +{ + if(impl) + return impl->isDocumentType(); + return false; +} + +/*! + Returns true if the node is an element; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomElement; you can get the QDomElement with toElement(). + + \sa toElement() +*/ +bool QDomNode::isElement() const +{ + if(impl) + return impl->isElement(); + return false; +} + +/*! + Returns true if the node is an entity reference; otherwise returns + false. + + If this function returns true, it does not imply that this object + is a QDomEntityReference; you can get the QDomEntityReference with + toEntityReference(). + + \sa toEntityReference() +*/ +bool QDomNode::isEntityReference() const +{ + if(impl) + return impl->isEntityReference(); + return false; +} + +/*! + Returns true if the node is a text node; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomText; you can get the QDomText with toText(). + + \sa toText() +*/ +bool QDomNode::isText() const +{ + if(impl) + return impl->isText(); + return false; +} + +/*! + Returns true if the node is an entity; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomEntity; you can get the QDomEntity with toEntity(). + + \sa toEntity() +*/ +bool QDomNode::isEntity() const +{ + if(impl) + return impl->isEntity(); + return false; +} + +/*! + Returns true if the node is a notation; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomNotation; you can get the QDomNotation with toNotation(). + + \sa toNotation() +*/ +bool QDomNode::isNotation() const +{ + if(impl) + return impl->isNotation(); + return false; +} + +/*! + Returns true if the node is a processing instruction; otherwise + returns false. + + If this function returns true, it does not imply that this object + is a QDomProcessingInstruction; you can get the + QProcessingInstruction with toProcessingInstruction(). + + \sa toProcessingInstruction() +*/ +bool QDomNode::isProcessingInstruction() const +{ + if(impl) + return impl->isProcessingInstruction(); + return false; +} + +/*! + Returns true if the node is a character data node; otherwise + returns false. + + If this function returns true, it does not imply that this object + is a QDomCharacterData; you can get the QDomCharacterData with + toCharacterData(). + + \sa toCharacterData() +*/ +bool QDomNode::isCharacterData() const +{ + if (impl) + return impl->isCharacterData(); + return false; +} + +/*! + Returns true if the node is a comment; otherwise returns false. + + If this function returns true, it does not imply that this object + is a QDomComment; you can get the QDomComment with toComment(). + + \sa toComment() +*/ +bool QDomNode::isComment() const +{ + if (impl) + return impl->isComment(); + return false; +} + +#undef IMPL + +/*! + Returns the first child element with tag name \a tagName if tagName is non-empty; + otherwise returns the first child element. Returns a null element if no + such child exists. + + \sa lastChildElement() previousSiblingElement() nextSiblingElement() +*/ + +QDomElement QDomNode::firstChildElement(const QString &tagName) const +{ + for (QDomNode child = firstChild(); !child.isNull(); child = child.nextSibling()) { + if (child.isElement()) { + QDomElement elt = child.toElement(); + if (tagName.isEmpty() || elt.tagName() == tagName) + return elt; + } + } + return QDomElement(); +} + +/*! + Returns the last child element with tag name \a tagName if tagName is non-empty; + otherwise returns the first child element. Returns a null element if no + such child exists. + + \sa firstChildElement() previousSiblingElement() nextSiblingElement() +*/ + +QDomElement QDomNode::lastChildElement(const QString &tagName) const +{ + for (QDomNode child = lastChild(); !child.isNull(); child = child.previousSibling()) { + if (child.isElement()) { + QDomElement elt = child.toElement(); + if (tagName.isEmpty() || elt.tagName() == tagName) + return elt; + } + } + return QDomElement(); +} + +/*! + Returns the next sibilng element with tag name \a tagName if \a tagName + is non-empty; otherwise returns any next sibling element. + Returns a null element if no such sibling exists. + + \sa firstChildElement() previousSiblingElement() lastChildElement() +*/ + +QDomElement QDomNode::nextSiblingElement(const QString &tagName) const +{ + for (QDomNode sib = nextSibling(); !sib.isNull(); sib = sib.nextSibling()) { + if (sib.isElement()) { + QDomElement elt = sib.toElement(); + if (tagName.isEmpty() || elt.tagName() == tagName) + return elt; + } + } + return QDomElement(); +} + +/*! + Returns the previous sibilng element with tag name \a tagName if \a tagName + is non-empty; otherwise returns any previous sibling element. + Returns a null element if no such sibling exists. + + \sa firstChildElement(), nextSiblingElement(), lastChildElement() +*/ + +QDomElement QDomNode::previousSiblingElement(const QString &tagName) const +{ + for (QDomNode sib = previousSibling(); !sib.isNull(); sib = sib.previousSibling()) { + if (sib.isElement()) { + QDomElement elt = sib.toElement(); + if (tagName.isEmpty() || elt.tagName() == tagName) + return elt; + } + } + return QDomElement(); +} + +/*! + \since 4.1 + + For nodes created by QDomDocument::setContent(), this function + returns the line number in the XML document where the node was parsed. + Otherwise, -1 is returned. + + \sa columnNumber(), QDomDocument::setContent() +*/ +int QDomNode::lineNumber() const +{ + return impl ? impl->lineNumber : -1; +} + +/*! + \since 4.1 + + For nodes created by QDomDocument::setContent(), this function + returns the column number in the XML document where the node was parsed. + Otherwise, -1 is returned. + + \sa lineNumber(), QDomDocument::setContent() +*/ +int QDomNode::columnNumber() const +{ + return impl ? impl->columnNumber : -1; +} + + +/************************************************************** + * + * QDomNamedNodeMapPrivate + * + **************************************************************/ + +QDomNamedNodeMapPrivate::QDomNamedNodeMapPrivate(QDomNodePrivate* n) +{ + ref = 1; + readonly = false; + parent = n; + appendToParent = false; +} + +QDomNamedNodeMapPrivate::~QDomNamedNodeMapPrivate() +{ + clearMap(); +} + +QDomNamedNodeMapPrivate* QDomNamedNodeMapPrivate::clone(QDomNodePrivate* p) +{ + QDomNamedNodeMapPrivate* m = new QDomNamedNodeMapPrivate(p); + m->readonly = readonly; + m->appendToParent = appendToParent; + + QHash<QString, QDomNodePrivate*>::const_iterator it = map.constBegin(); + for (; it != map.constEnd(); ++it) { + QDomNodePrivate *new_node = (*it)->cloneNode(); + new_node->setParent(p); + m->setNamedItem(new_node); + } + + // we are no longer interested in ownership + m->ref.deref(); + return m; +} + +void QDomNamedNodeMapPrivate::clearMap() +{ + // Dereference all of our children if we took references + if (!appendToParent) { + QHash<QString, QDomNodePrivate *>::const_iterator it = map.constBegin(); + for (; it != map.constEnd(); ++it) + if (!(*it)->ref.deref()) + delete *it; + } + map.clear(); +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::namedItem(const QString& name) const +{ + QDomNodePrivate* p = map[name]; + return p; +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::namedItemNS(const QString& nsURI, const QString& localName) const +{ + QHash<QString, QDomNodePrivate *>::const_iterator it = map.constBegin(); + QDomNodePrivate *n; + for (; it != map.constEnd(); ++it) { + n = *it; + if (!n->prefix.isNull()) { + // node has a namespace + if (n->namespaceURI == nsURI && n->name == localName) + return n; + } + } + return 0; +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::setNamedItem(QDomNodePrivate* arg) +{ + if (readonly || !arg) + return 0; + + if (appendToParent) + return parent->appendChild(arg); + + QDomNodePrivate *n = map.value(arg->nodeName()); + // We take a reference + arg->ref.ref(); + map.insertMulti(arg->nodeName(), arg); + return n; +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::setNamedItemNS(QDomNodePrivate* arg) +{ + if (readonly || !arg) + return 0; + + if (appendToParent) + return parent->appendChild(arg); + + if (!arg->prefix.isNull()) { + // node has a namespace + QDomNodePrivate *n = namedItemNS(arg->namespaceURI, arg->name); + // We take a reference + arg->ref.ref(); + map.insertMulti(arg->nodeName(), arg); + return n; + } else { + // ### check the following code if it is ok + return setNamedItem(arg); + } +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::removeNamedItem(const QString& name) +{ + if (readonly) + return 0; + + QDomNodePrivate* p = namedItem(name); + if (p == 0) + return 0; + if (appendToParent) + return parent->removeChild(p); + + map.remove(p->nodeName()); + // We took a reference, so we have to free one here + p->ref.deref(); + return p; +} + +QDomNodePrivate* QDomNamedNodeMapPrivate::item(int index) const +{ + if ((uint)index >= length()) + return 0; + return *(map.constBegin() + index); +} + +// ### Qt 5: convert all length/size() functions in QDom to use int instead of uint. +uint QDomNamedNodeMapPrivate::length() const +{ + return map.count(); +} + +bool QDomNamedNodeMapPrivate::contains(const QString& name) const +{ + return map.value(name) != 0; +} + +bool QDomNamedNodeMapPrivate::containsNS(const QString& nsURI, const QString & localName) const +{ + return namedItemNS(nsURI, localName) != 0; +} + +/************************************************************** + * + * QDomNamedNodeMap + * + **************************************************************/ + +#define IMPL ((QDomNamedNodeMapPrivate*)impl) + +/*! + \class QDomNamedNodeMap + \reentrant + \brief The QDomNamedNodeMap class contains a collection of nodes + that can be accessed by name. + + \inmodule QtXml + \ingroup xml-tools + + Note that QDomNamedNodeMap does not inherit from QDomNodeList. + QDomNamedNodeMaps do not provide any specific node ordering. + Although nodes in a QDomNamedNodeMap may be accessed by an ordinal + index, this is simply to allow a convenient enumeration of the + contents of a QDomNamedNodeMap, and does not imply that the DOM + specifies an ordering of the nodes. + + The QDomNamedNodeMap is used in three places: + \list 1 + \i QDomDocumentType::entities() returns a map of all entities + described in the DTD. + \i QDomDocumentType::notations() returns a map of all notations + described in the DTD. + \i QDomNode::attributes() returns a map of all attributes of an + element. + \endlist + + Items in the map are identified by the name which QDomNode::name() + returns. Nodes are retrieved using namedItem(), namedItemNS() or + item(). New nodes are inserted with setNamedItem() or + setNamedItemNS() and removed with removeNamedItem() or + removeNamedItemNS(). Use contains() to see if an item with the + given name is in the named node map. The number of items is + returned by length(). + + Terminology: in this class we use "item" and "node" + interchangeably. +*/ + +/*! + Constructs an empty named node map. +*/ +QDomNamedNodeMap::QDomNamedNodeMap() +{ + impl = 0; +} + +/*! + Constructs a copy of \a n. +*/ +QDomNamedNodeMap::QDomNamedNodeMap(const QDomNamedNodeMap &n) +{ + impl = n.impl; + if (impl) + impl->ref.ref(); +} + +QDomNamedNodeMap::QDomNamedNodeMap(QDomNamedNodeMapPrivate *n) +{ + impl = n; + if (impl) + impl->ref.ref(); +} + +/*! + Assigns \a n to this named node map. +*/ +QDomNamedNodeMap& QDomNamedNodeMap::operator=(const QDomNamedNodeMap &n) +{ + if (n.impl) + n.impl->ref.ref(); + if (impl && !impl->ref.deref()) + delete impl; + impl = n.impl; + return *this; +} + +/*! + Returns true if \a n and this named node map are equal; otherwise + returns false. +*/ +bool QDomNamedNodeMap::operator== (const QDomNamedNodeMap& n) const +{ + return (impl == n.impl); +} + +/*! + Returns true if \a n and this named node map are not equal; + otherwise returns false. +*/ +bool QDomNamedNodeMap::operator!= (const QDomNamedNodeMap& n) const +{ + return (impl != n.impl); +} + +/*! + Destroys the object and frees its resources. +*/ +QDomNamedNodeMap::~QDomNamedNodeMap() +{ + if (impl && !impl->ref.deref()) + delete impl; +} + +/*! + Returns the node called \a name. + + If the named node map does not contain such a node, a \link + QDomNode::isNull() null node\endlink is returned. A node's name is + the name returned by QDomNode::nodeName(). + + \sa setNamedItem() namedItemNS() +*/ +QDomNode QDomNamedNodeMap::namedItem(const QString& name) const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->namedItem(name)); +} + +/*! + Inserts the node \a newNode into the named node map. The name used + by the map is the node name of \a newNode as returned by + QDomNode::nodeName(). + + If the new node replaces an existing node, i.e. the map contains a + node with the same name, the replaced node is returned. + + \sa namedItem() removeNamedItem() setNamedItemNS() +*/ +QDomNode QDomNamedNodeMap::setNamedItem(const QDomNode& newNode) +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->setNamedItem((QDomNodePrivate*)newNode.impl)); +} + +/*! + Removes the node called \a name from the map. + + The function returns the removed node or a \link + QDomNode::isNull() null node\endlink if the map did not contain a + node called \a name. + + \sa setNamedItem() namedItem() removeNamedItemNS() +*/ +QDomNode QDomNamedNodeMap::removeNamedItem(const QString& name) +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->removeNamedItem(name)); +} + +/*! + Retrieves the node at position \a index. + + This can be used to iterate over the map. Note that the nodes in + the map are ordered arbitrarily. + + \sa length() +*/ +QDomNode QDomNamedNodeMap::item(int index) const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->item(index)); +} + +/*! + Returns the node associated with the local name \a localName and + the namespace URI \a nsURI. + + If the map does not contain such a node, a \link + QDomNode::isNull() null node\endlink is returned. + + \sa setNamedItemNS() namedItem() +*/ +QDomNode QDomNamedNodeMap::namedItemNS(const QString& nsURI, const QString& localName) const +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->namedItemNS(nsURI, localName)); +} + +/*! + Inserts the node \a newNode in the map. If a node with the same + namespace URI and the same local name already exists in the map, + it is replaced by \a newNode. If the new node replaces an existing + node, the replaced node is returned. + + \sa namedItemNS() removeNamedItemNS() setNamedItem() +*/ +QDomNode QDomNamedNodeMap::setNamedItemNS(const QDomNode& newNode) +{ + if (!impl) + return QDomNode(); + return QDomNode(IMPL->setNamedItemNS((QDomNodePrivate*)newNode.impl)); +} + +/*! + Removes the node with the local name \a localName and the + namespace URI \a nsURI from the map. + + The function returns the removed node or a \link + QDomNode::isNull() null node\endlink if the map did not contain a + node with the local name \a localName and the namespace URI \a + nsURI. + + \sa setNamedItemNS() namedItemNS() removeNamedItem() +*/ +QDomNode QDomNamedNodeMap::removeNamedItemNS(const QString& nsURI, const QString& localName) +{ + if (!impl) + return QDomNode(); + QDomNodePrivate *n = IMPL->namedItemNS(nsURI, localName); + if (!n) + return QDomNode(); + return QDomNode(IMPL->removeNamedItem(n->name)); +} + +/*! + Returns the number of nodes in the map. + + \sa item() +*/ +uint QDomNamedNodeMap::length() const +{ + if (!impl) + return 0; + return IMPL->length(); +} + +/*! + \fn bool QDomNamedNodeMap::isEmpty() const + + Returns true if the map is empty; otherwise returns false. This function is + provided for Qt API consistency. +*/ + +/*! + \fn int QDomNamedNodeMap::count() const + + This function is provided for Qt API consistency. It is equivalent to length(). +*/ + +/*! + \fn int QDomNamedNodeMap::size() const + + This function is provided for Qt API consistency. It is equivalent to length(). +*/ + +/*! + Returns true if the map contains a node called \a name; otherwise + returns false. + + \bold{Note:} This function does not take the presence of namespaces into account. + Use namedItemNS() to test whether the map contains a node with a specific namespace + URI and name. +*/ +bool QDomNamedNodeMap::contains(const QString& name) const +{ + if (!impl) + return false; + return IMPL->contains(name); +} + +#undef IMPL + +/************************************************************** + * + * QDomDocumentTypePrivate + * + **************************************************************/ + +QDomDocumentTypePrivate::QDomDocumentTypePrivate(QDomDocumentPrivate* doc, QDomNodePrivate* parent) + : QDomNodePrivate(doc, parent) +{ + init(); +} + +QDomDocumentTypePrivate::QDomDocumentTypePrivate(QDomDocumentTypePrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ + init(); + // Refill the maps with our new children + QDomNodePrivate* p = first; + while (p) { + if (p->isEntity()) + // Dont use normal insert function since we would create infinite recursion + entities->map.insertMulti(p->nodeName(), p); + if (p->isNotation()) + // Dont use normal insert function since we would create infinite recursion + notations->map.insertMulti(p->nodeName(), p); + } +} + +QDomDocumentTypePrivate::~QDomDocumentTypePrivate() +{ + if (!entities->ref.deref()) + delete entities; + if (!notations->ref.deref()) + delete notations; +} + +void QDomDocumentTypePrivate::init() +{ + entities = new QDomNamedNodeMapPrivate(this); + notations = new QDomNamedNodeMapPrivate(this); + publicId.clear(); + systemId.clear(); + internalSubset.clear(); + + entities->setAppendToParent(true); + notations->setAppendToParent(true); +} + +QDomNodePrivate* QDomDocumentTypePrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomDocumentTypePrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +QDomNodePrivate* QDomDocumentTypePrivate::insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild) +{ + // Call the origianl implementation + QDomNodePrivate* p = QDomNodePrivate::insertBefore(newChild, refChild); + // Update the maps + if (p && p->isEntity()) + entities->map.insertMulti(p->nodeName(), p); + else if (p && p->isNotation()) + notations->map.insertMulti(p->nodeName(), p); + + return p; +} + +QDomNodePrivate* QDomDocumentTypePrivate::insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild) +{ + // Call the origianl implementation + QDomNodePrivate* p = QDomNodePrivate::insertAfter(newChild, refChild); + // Update the maps + if (p && p->isEntity()) + entities->map.insertMulti(p->nodeName(), p); + else if (p && p->isNotation()) + notations->map.insertMulti(p->nodeName(), p); + + return p; +} + +QDomNodePrivate* QDomDocumentTypePrivate::replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild) +{ + // Call the origianl implementation + QDomNodePrivate* p = QDomNodePrivate::replaceChild(newChild, oldChild); + // Update the maps + if (p) { + if (oldChild && oldChild->isEntity()) + entities->map.remove(oldChild->nodeName()); + else if (oldChild && oldChild->isNotation()) + notations->map.remove(oldChild->nodeName()); + + if (p->isEntity()) + entities->map.insertMulti(p->nodeName(), p); + else if (p->isNotation()) + notations->map.insertMulti(p->nodeName(), p); + } + + return p; +} + +QDomNodePrivate* QDomDocumentTypePrivate::removeChild(QDomNodePrivate* oldChild) +{ + // Call the origianl implementation + QDomNodePrivate* p = QDomNodePrivate::removeChild( oldChild); + // Update the maps + if (p && p->isEntity()) + entities->map.remove(p->nodeName()); + else if (p && p->isNotation()) + notations->map.remove(p ->nodeName()); + + return p; +} + +QDomNodePrivate* QDomDocumentTypePrivate::appendChild(QDomNodePrivate* newChild) +{ + return insertAfter(newChild, 0); +} + +static QString quotedValue(const QString &data) +{ + QChar quote = data.indexOf(QLatin1Char('\'')) == -1 + ? QLatin1Char('\'') + : QLatin1Char('"'); + return quote + data + quote; +} + +void QDomDocumentTypePrivate::save(QTextStream& s, int, int indent) const +{ + if (name.isEmpty()) + return; + + s << "<!DOCTYPE " << name; + + if (!publicId.isNull()) { + s << " PUBLIC " << quotedValue(publicId); + if (!systemId.isNull()) { + s << ' ' << quotedValue(systemId); + } + } else if (!systemId.isNull()) { + s << " SYSTEM " << quotedValue(systemId); + } + + if (entities->length()>0 || notations->length()>0) { + s << " [" << endl; + + QHash<QString, QDomNodePrivate *>::const_iterator it2 = notations->map.constBegin(); + for (; it2 != notations->map.constEnd(); ++it2) + (*it2)->save(s, 0, indent); + + QHash<QString, QDomNodePrivate *>::const_iterator it = entities->map.constBegin(); + for (; it != entities->map.constEnd(); ++it) + (*it)->save(s, 0, indent); + + s << ']'; + } + + s << '>' << endl; +} + +/************************************************************** + * + * QDomDocumentType + * + **************************************************************/ + +#define IMPL ((QDomDocumentTypePrivate*)impl) + +/*! + \class QDomDocumentType + \reentrant + \brief The QDomDocumentType class is the representation of the DTD + in the document tree. + + \inmodule QtXml + \ingroup xml-tools + + The QDomDocumentType class allows read-only access to some of the + data structures in the DTD: it can return a map of all entities() + and notations(). In addition the function name() returns the name + of the document type as specified in the <!DOCTYPE name> + tag. This class also provides the publicId(), systemId() and + internalSubset() functions. + + \sa QDomDocument +*/ + +/*! + Creates an empty QDomDocumentType object. +*/ +QDomDocumentType::QDomDocumentType() : QDomNode() +{ +} + +/*! + Constructs a copy of \a n. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocumentType::QDomDocumentType(const QDomDocumentType& n) + : QDomNode(n) +{ +} + +QDomDocumentType::QDomDocumentType(QDomDocumentTypePrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a n to this document type. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocumentType& QDomDocumentType::operator= (const QDomDocumentType& n) +{ + return (QDomDocumentType&) QDomNode::operator=(n); +} + +/*! + Returns the name of the document type as specified in the + <!DOCTYPE name> tag. + + \sa nodeName() +*/ +QString QDomDocumentType::name() const +{ + if (!impl) + return QString(); + return IMPL->nodeName(); +} + +/*! + Returns a map of all entities described in the DTD. +*/ +QDomNamedNodeMap QDomDocumentType::entities() const +{ + if (!impl) + return QDomNamedNodeMap(); + return QDomNamedNodeMap(IMPL->entities); +} + +/*! + Returns a map of all notations described in the DTD. +*/ +QDomNamedNodeMap QDomDocumentType::notations() const +{ + if (!impl) + return QDomNamedNodeMap(); + return QDomNamedNodeMap(IMPL->notations); +} + +/*! + Returns the public identifier of the external DTD subset or + an empty string if there is no public identifier. + + \sa systemId() internalSubset() QDomImplementation::createDocumentType() +*/ +QString QDomDocumentType::publicId() const +{ + if (!impl) + return QString(); + return IMPL->publicId; +} + +/*! + Returns the system identifier of the external DTD subset or + an empty string if there is no system identifier. + + \sa publicId() internalSubset() QDomImplementation::createDocumentType() +*/ +QString QDomDocumentType::systemId() const +{ + if (!impl) + return QString(); + return IMPL->systemId; +} + +/*! + Returns the internal subset of the document type or an empty + string if there is no internal subset. + + \sa publicId() systemId() +*/ +QString QDomDocumentType::internalSubset() const +{ + if (!impl) + return QString(); + return IMPL->internalSubset; +} + +/* + Are these needed at all? The only difference when removing these + two methods in all subclasses is that we'd get a different type + for null nodes. +*/ + +/*! + \fn QDomNode::NodeType QDomDocumentType::nodeType() const + + Returns \c DocumentTypeNode. + + \sa isDocumentType() QDomNode::toDocumentType() +*/ + +#undef IMPL + +/************************************************************** + * + * QDomDocumentFragmentPrivate + * + **************************************************************/ + +QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomDocumentPrivate* doc, QDomNodePrivate* parent) + : QDomNodePrivate(doc, parent) +{ + name = QLatin1String("#document-fragment"); +} + +QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomNodePrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ +} + +QDomNodePrivate* QDomDocumentFragmentPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomDocumentFragmentPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +/************************************************************** + * + * QDomDocumentFragment + * + **************************************************************/ + +/*! + \class QDomDocumentFragment + \reentrant + \brief The QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument. + + \inmodule QtXml + \ingroup xml-tools + + If you want to do complex tree operations it is useful to have a + lightweight class to store nodes and their relations. + QDomDocumentFragment stores a subtree of a document which does not + necessarily represent a well-formed XML document. + + QDomDocumentFragment is also useful if you want to group several + nodes in a list and insert them all together as children of some + node. In these cases QDomDocumentFragment can be used as a + temporary container for this list of children. + + The most important feature of QDomDocumentFragment is that it is + treated in a special way by QDomNode::insertAfter(), + QDomNode::insertBefore(), QDomNode::replaceChild() and + QDomNode::appendChild(): instead of inserting the fragment itself, all + the fragment's children are inserted. +*/ + +/*! + Constructs an empty document fragment. +*/ +QDomDocumentFragment::QDomDocumentFragment() +{ +} + +QDomDocumentFragment::QDomDocumentFragment(QDomDocumentFragmentPrivate* n) + : QDomNode(n) +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocumentFragment::QDomDocumentFragment(const QDomDocumentFragment& x) + : QDomNode(x) +{ +} + +/*! + Assigns \a x to this DOM document fragment. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocumentFragment& QDomDocumentFragment::operator= (const QDomDocumentFragment& x) +{ + return (QDomDocumentFragment&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomDocumentFragment::nodeType() const + + Returns \c DocumentFragment. + + \sa isDocumentFragment() QDomNode::toDocumentFragment() +*/ + +/************************************************************** + * + * QDomCharacterDataPrivate + * + **************************************************************/ + +QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, + const QString& data) + : QDomNodePrivate(d, p) +{ + value = data; + name = QLatin1String("#character-data"); +} + +QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomCharacterDataPrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ +} + +QDomNodePrivate* QDomCharacterDataPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomCharacterDataPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +uint QDomCharacterDataPrivate::dataLength() const +{ + return value.length(); +} + +QString QDomCharacterDataPrivate::substringData(unsigned long offset, unsigned long n) const +{ + return value.mid(offset, n); +} + +void QDomCharacterDataPrivate::insertData(unsigned long offset, const QString& arg) +{ + value.insert(offset, arg); +} + +void QDomCharacterDataPrivate::deleteData(unsigned long offset, unsigned long n) +{ + value.remove(offset, n); +} + +void QDomCharacterDataPrivate::replaceData(unsigned long offset, unsigned long n, const QString& arg) +{ + value.replace(offset, n, arg); +} + +void QDomCharacterDataPrivate::appendData(const QString& arg) +{ + value += arg; +} + +/************************************************************** + * + * QDomCharacterData + * + **************************************************************/ + +#define IMPL ((QDomCharacterDataPrivate*)impl) + +/*! + \class QDomCharacterData + \reentrant + \brief The QDomCharacterData class represents a generic string in the DOM. + + \inmodule QtXml + \ingroup xml-tools + + Character data as used in XML specifies a generic data string. + More specialized versions of this class are QDomText, QDomComment + and QDomCDATASection. + + The data string is set with setData() and retrieved with data(). + You can retrieve a portion of the data string using + substringData(). Extra data can be appended with appendData(), or + inserted with insertData(). Portions of the data string can be + deleted with deleteData() or replaced with replaceData(). The + length of the data string is returned by length(). + + The node type of the node containing this character data is + returned by nodeType(). + + \sa QDomText QDomComment QDomCDATASection +*/ + +/*! + Constructs an empty character data object. +*/ +QDomCharacterData::QDomCharacterData() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomCharacterData::QDomCharacterData(const QDomCharacterData& x) + : QDomNode(x) +{ +} + +QDomCharacterData::QDomCharacterData(QDomCharacterDataPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this character data. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomCharacterData& QDomCharacterData::operator= (const QDomCharacterData& x) +{ + return (QDomCharacterData&) QDomNode::operator=(x); +} + +/*! + Returns the string stored in this object. + + If the node is a \link isNull() null node\endlink, it will return + an empty string. +*/ +QString QDomCharacterData::data() const +{ + if (!impl) + return QString(); + return impl->nodeValue(); +} + +/*! + Sets this object's string to \a v. +*/ +void QDomCharacterData::setData(const QString& v) +{ + if (impl) + impl->setNodeValue(v); +} + +/*! + Returns the length of the stored string. +*/ +uint QDomCharacterData::length() const +{ + if (impl) + return IMPL->dataLength(); + return 0; +} + +/*! + Returns the substring of length \a count from position \a offset. +*/ +QString QDomCharacterData::substringData(unsigned long offset, unsigned long count) +{ + if (!impl) + return QString(); + return IMPL->substringData(offset, count); +} + +/*! + Appends the string \a arg to the stored string. +*/ +void QDomCharacterData::appendData(const QString& arg) +{ + if (impl) + IMPL->appendData(arg); +} + +/*! + Inserts the string \a arg into the stored string at position \a offset. +*/ +void QDomCharacterData::insertData(unsigned long offset, const QString& arg) +{ + if (impl) + IMPL->insertData(offset, arg); +} + +/*! + Deletes a substring of length \a count from position \a offset. +*/ +void QDomCharacterData::deleteData(unsigned long offset, unsigned long count) +{ + if (impl) + IMPL->deleteData(offset, count); +} + +/*! + Replaces the substring of length \a count starting at position \a + offset with the string \a arg. +*/ +void QDomCharacterData::replaceData(unsigned long offset, unsigned long count, const QString& arg) +{ + if (impl) + IMPL->replaceData(offset, count, arg); +} + +/*! + Returns the type of node this object refers to (i.e. \c TextNode, + \c CDATASectionNode, \c CommentNode or \c CharacterDataNode). For + a \link isNull() null node\endlink, returns \c CharacterDataNode. +*/ +QDomNode::NodeType QDomCharacterData::nodeType() const +{ + if (!impl) + return CharacterDataNode; + return QDomNode::nodeType(); +} + +#undef IMPL + +/************************************************************** + * + * QDomAttrPrivate + * + **************************************************************/ + +QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& name_) + : QDomNodePrivate(d, parent) +{ + name = name_; + m_specified = false; +} + +QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, const QString& nsURI, const QString& qName) + : QDomNodePrivate(d, p) +{ + qt_split_namespace(prefix, name, qName, !nsURI.isNull()); + namespaceURI = nsURI; + createdWithDom1Interface = false; + m_specified = false; +} + +QDomAttrPrivate::QDomAttrPrivate(QDomAttrPrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ + m_specified = n->specified(); +} + +void QDomAttrPrivate::setNodeValue(const QString& v) +{ + value = v; + QDomTextPrivate *t = new QDomTextPrivate(0, this, v); + // keep the refcount balanced: appendChild() does a ref anyway. + t->ref.deref(); + if (first) { + delete removeChild(first); + } + appendChild(t); +} + +QDomNodePrivate* QDomAttrPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomAttrPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +bool QDomAttrPrivate::specified() const +{ + return m_specified; +} + +/* \internal + Encode & escape \a str. Yes, it makes no sense to return a QString, + but is so for legacy reasons. + + Remember that content produced should be able to roundtrip with 2.11 End-of-Line Handling + and 3.3.3 Attribute-Value Normalization. + + If \a performAVN is true, characters will be escaped to survive Attribute Value Normalization. + If \a encodeEOLs is true, characters will be escaped to survive End-of-Line Handling. +*/ +static QString encodeText(const QString &str, + QTextStream &s, + const bool encodeQuotes = true, + const bool performAVN = false, + const bool encodeEOLs = false) +{ +#ifdef QT_NO_TEXTCODEC + Q_UNUSED(s); +#else + const QTextCodec *const codec = s.codec(); + Q_ASSERT(codec); +#endif + QString retval(str); + int len = retval.length(); + int i = 0; + + while (i < len) { + const QChar ati(retval.at(i)); + + if (ati == QLatin1Char('<')) { + retval.replace(i, 1, QLatin1String("<")); + len += 3; + i += 4; + } else if (encodeQuotes && (ati == QLatin1Char('"'))) { + retval.replace(i, 1, QLatin1String(""")); + len += 5; + i += 6; + } else if (ati == QLatin1Char('&')) { + retval.replace(i, 1, QLatin1String("&")); + len += 4; + i += 5; + } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { + retval.replace(i, 1, QLatin1String(">")); + len += 3; + i += 4; + } else if (performAVN && + (ati == QChar(0xA) || + ati == QChar(0xD) || + ati == QChar(0x9))) { + const QString replacement(QLatin1String("&#x") + QString::number(ati.unicode(), 16) + QLatin1Char(';')); + retval.replace(i, 1, replacement); + i += replacement.length(); + len += replacement.length() - 1; + } else if (encodeEOLs && ati == QChar(0xD)) { + retval.replace(i, 1, QLatin1String("
")); // Replace a single 0xD with a ref for 0xD + len += 4; + i += 5; + } else { +#ifndef QT_NO_TEXTCODEC + if(codec->canEncode(ati)) + ++i; + else +#endif + { + // We have to use a character reference to get it through. + const ushort codepoint(ati.unicode()); + const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); + retval.replace(i, 1, replacement); + i += replacement.length(); + len += replacement.length() - 1; + } + } + } + + return retval; +} + +void QDomAttrPrivate::save(QTextStream& s, int, int) const +{ + if (namespaceURI.isNull()) { + s << name << "=\"" << encodeText(value, s, true, true) << '\"'; + } else { + s << prefix << ':' << name << "=\"" << encodeText(value, s, true, true) << '\"'; + /* This is a fix for 138243, as good as it gets. + * + * QDomElementPrivate::save() output a namespace declaration if + * the element is in a namespace, no matter what. This function do as well, meaning + * that we get two identical namespace declaration if we don't have the if- + * statement below. + * + * This doesn't work when the parent element has the same prefix as us but + * a different namespace. However, this can only occur by the user modifying the element, + * and we don't do fixups by that anyway, and hence it's the user responsibility to not + * arrive in those situations. */ + if(!ownerNode || + ownerNode->prefix != prefix) { + s << " xmlns:" << prefix << "=\"" << encodeText(namespaceURI, s, true, true) << '\"'; + } + } +} + +/************************************************************** + * + * QDomAttr + * + **************************************************************/ + +#define IMPL ((QDomAttrPrivate*)impl) + +/*! + \class QDomAttr + \reentrant + \brief The QDomAttr class represents one attribute of a QDomElement. + + \inmodule QtXml + \ingroup xml-tools + + For example, the following piece of XML produces an element with + no children, but two attributes: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 7 + + You can access the attributes of an element with code like this: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 8 + + This example also shows that changing an attribute received from + an element changes the attribute of the element. If you do not + want to change the value of the element's attribute you must + use cloneNode() to get an independent copy of the attribute. + + QDomAttr can return the name() and value() of an attribute. An + attribute's value is set with setValue(). If specified() returns + true the value was set with setValue(). The node this + attribute is attached to (if any) is returned by ownerElement(). + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + + +/*! + Constructs an empty attribute. +*/ +QDomAttr::QDomAttr() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomAttr::QDomAttr(const QDomAttr& x) + : QDomNode(x) +{ +} + +QDomAttr::QDomAttr(QDomAttrPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this DOM attribute. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomAttr& QDomAttr::operator= (const QDomAttr& x) +{ + return (QDomAttr&) QDomNode::operator=(x); +} + +/*! + Returns the attribute's name. +*/ +QString QDomAttr::name() const +{ + if (!impl) + return QString(); + return impl->nodeName(); +} + +/*! + Returns true if the attribute has been set by the user with setValue(). + Returns false if the value hasn't been specified or set. + + \sa setValue() +*/ +bool QDomAttr::specified() const +{ + if (!impl) + return false; + return IMPL->specified(); +} + +/*! + Returns the element node this attribute is attached to or a \link + QDomNode::isNull() null node\endlink if this attribute is not + attached to any element. +*/ +QDomElement QDomAttr::ownerElement() const +{ + Q_ASSERT(impl->parent()); + if (!impl || !impl->parent()->isElement()) + return QDomElement(); + return QDomElement((QDomElementPrivate*)(impl->parent())); +} + +/*! + Returns the value of the attribute or an empty string if the + attribute has not been specified. + + \sa specified() setValue() +*/ +QString QDomAttr::value() const +{ + if (!impl) + return QString(); + return impl->nodeValue(); +} + +/*! + Sets the attribute's value to \a v. + + \sa value() +*/ +void QDomAttr::setValue(const QString& v) +{ + if (!impl) + return; + impl->setNodeValue(v); + IMPL->m_specified = true; +} + +/*! + \fn QDomNode::NodeType QDomAttr::nodeType() const + + Returns \link QDomNode::NodeType AttributeNode\endlink. +*/ + +#undef IMPL + +/************************************************************** + * + * QDomElementPrivate + * + **************************************************************/ + +QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, + const QString& tagname) + : QDomNodePrivate(d, p) +{ + name = tagname; + m_attr = new QDomNamedNodeMapPrivate(this); +} + +QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, + const QString& nsURI, const QString& qName) + : QDomNodePrivate(d, p) +{ + qt_split_namespace(prefix, name, qName, !nsURI.isNull()); + namespaceURI = nsURI; + createdWithDom1Interface = false; + m_attr = new QDomNamedNodeMapPrivate(this); +} + +QDomElementPrivate::QDomElementPrivate(QDomElementPrivate* n, bool deep) : + QDomNodePrivate(n, deep) +{ + m_attr = n->m_attr->clone(this); + // Reference is down to 0, so we set it to 1 here. + m_attr->ref.ref(); +} + +QDomElementPrivate::~QDomElementPrivate() +{ + if (!m_attr->ref.deref()) + delete m_attr; +} + +QDomNodePrivate* QDomElementPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomElementPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +QString QDomElementPrivate::attribute(const QString& name_, const QString& defValue) const +{ + QDomNodePrivate* n = m_attr->namedItem(name_); + if (!n) + return defValue; + + return n->nodeValue(); +} + +QString QDomElementPrivate::attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const +{ + QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName); + if (!n) + return defValue; + + return n->nodeValue(); +} + +void QDomElementPrivate::setAttribute(const QString& aname, const QString& newValue) +{ + QDomNodePrivate* n = m_attr->namedItem(aname); + if (!n) { + n = new QDomAttrPrivate(ownerDocument(), this, aname); + n->setNodeValue(newValue); + + // Referencing is done by the map, so we set the reference counter back + // to 0 here. This is ok since we created the QDomAttrPrivate. + n->ref.deref(); + m_attr->setNamedItem(n); + } else { + n->setNodeValue(newValue); + } +} + +void QDomElementPrivate::setAttributeNS(const QString& nsURI, const QString& qName, const QString& newValue) +{ + QString prefix, localName; + qt_split_namespace(prefix, localName, qName, true); + QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName); + if (!n) { + n = new QDomAttrPrivate(ownerDocument(), this, nsURI, qName); + n->setNodeValue(newValue); + + // Referencing is done by the map, so we set the reference counter back + // to 0 here. This is ok since we created the QDomAttrPrivate. + n->ref.deref(); + m_attr->setNamedItem(n); + } else { + n->setNodeValue(newValue); + n->prefix = prefix; + } +} + +void QDomElementPrivate::removeAttribute(const QString& aname) +{ + QDomNodePrivate* p = m_attr->removeNamedItem(aname); + if (p && p->ref == 0) + delete p; +} + +QDomAttrPrivate* QDomElementPrivate::attributeNode(const QString& aname) +{ + return (QDomAttrPrivate*)m_attr->namedItem(aname); +} + +QDomAttrPrivate* QDomElementPrivate::attributeNodeNS(const QString& nsURI, const QString& localName) +{ + return (QDomAttrPrivate*)m_attr->namedItemNS(nsURI, localName); +} + +QDomAttrPrivate* QDomElementPrivate::setAttributeNode(QDomAttrPrivate* newAttr) +{ + QDomNodePrivate* n = m_attr->namedItem(newAttr->nodeName()); + + // Referencing is done by the maps + m_attr->setNamedItem(newAttr); + + newAttr->setParent(this); + + return (QDomAttrPrivate*)n; +} + +QDomAttrPrivate* QDomElementPrivate::setAttributeNodeNS(QDomAttrPrivate* newAttr) +{ + QDomNodePrivate* n = 0; + if (!newAttr->prefix.isNull()) + n = m_attr->namedItemNS(newAttr->namespaceURI, newAttr->name); + + // Referencing is done by the maps + m_attr->setNamedItem(newAttr); + + return (QDomAttrPrivate*)n; +} + +QDomAttrPrivate* QDomElementPrivate::removeAttributeNode(QDomAttrPrivate* oldAttr) +{ + return (QDomAttrPrivate*)m_attr->removeNamedItem(oldAttr->nodeName()); +} + +bool QDomElementPrivate::hasAttribute(const QString& aname) +{ + return m_attr->contains(aname); +} + +bool QDomElementPrivate::hasAttributeNS(const QString& nsURI, const QString& localName) +{ + return m_attr->containsNS(nsURI, localName); +} + +QString QDomElementPrivate::text() +{ + QString t(QLatin1String("")); + + QDomNodePrivate* p = first; + while (p) { + if (p->isText() || p->isCDATASection()) + t += p->nodeValue(); + else if (p->isElement()) + t += ((QDomElementPrivate*)p)->text(); + p = p->next; + } + + return t; +} + +void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const +{ + if (!(prev && prev->isText())) + s << QString(indent < 1 ? 0 : depth * indent, QLatin1Char(' ')); + + QString qName(name); + QString nsDecl(QLatin1String("")); + if (!namespaceURI.isNull()) { + /** ### Qt 5: + * + * If we still have QDom, optimize this so that we only declare namespaces that are not + * yet declared. We loose default namespace mappings, so maybe we should rather store + * the information that we get from startPrefixMapping()/endPrefixMapping() and use them. + * Modifications becomes more complex then, however. + * + * We cannot do this during the Qt 4 series because it would require too invasive changes, and + * hence possibly behavioral changes. + */ + if (prefix.isEmpty()) { + nsDecl = QLatin1String(" xmlns"); + } else { + qName = prefix + QLatin1Char(':') + name; + nsDecl = QLatin1String(" xmlns:") + prefix; + } + nsDecl += QLatin1String("=\"") + encodeText(namespaceURI, s) + QLatin1String("\""); + } + s << '<' << qName << nsDecl; + + QSet<QString> outputtedPrefixes; + + /* Write out attributes. */ + if (!m_attr->map.isEmpty()) { + s << ' '; + QHash<QString, QDomNodePrivate *>::const_iterator it = m_attr->map.constBegin(); + for (; it != m_attr->map.constEnd(); ++it) { + if (it.value()->namespaceURI.isNull()) { + s << it.value()->name << "=\"" << encodeText(it.value()->value, s, true, true) << '\"'; + } else { + s << it.value()->prefix << ':' << it.value()->name << "=\"" << encodeText(it.value()->value, s, true, true) << '\"'; + /* This is a fix for 138243, as good as it gets. + * + * QDomElementPrivate::save() output a namespace declaration if + * the element is in a namespace, no matter what. This function do as well, meaning + * that we get two identical namespace declaration if we don't have the if- + * statement below. + * + * This doesn't work when the parent element has the same prefix as us but + * a different namespace. However, this can only occur by the user modifying the element, + * and we don't do fixups by that anyway, and hence it's the user responsibility to not + * arrive in those situations. */ + if((!it.value()->ownerNode || + it.value()->ownerNode->prefix != it.value()->prefix) && + !outputtedPrefixes.contains(it.value()->prefix)) { + s << " xmlns:" << it.value()->prefix << "=\"" << encodeText(it.value()->namespaceURI, s, true, true) << '\"'; + outputtedPrefixes.insert(it.value()->prefix); + } + } + s << ' '; + } + } + + if (last) { + // has child nodes + if (first->isText()) + s << '>'; + else { + s << '>'; + + /* -1 disables new lines. */ + if (indent != -1) + s << endl; + } + QDomNodePrivate::save(s, depth + 1, indent); if (!last->isText()) + s << QString(indent < 1 ? 0 : depth * indent, QLatin1Char(' ')); + + s << "</" << qName << '>'; + } else { + s << "/>"; + } + if (!(next && next->isText())) { + /* -1 disables new lines. */ + if (indent != -1) + s << endl; + } +} + +/************************************************************** + * + * QDomElement + * + **************************************************************/ + +#define IMPL ((QDomElementPrivate*)impl) + +/*! + \class QDomElement + \reentrant + \brief The QDomElement class represents one element in the DOM tree. + + \inmodule QtXml + \ingroup xml-tools + + Elements have a tagName() and zero or more attributes associated + with them. The tag name can be changed with setTagName(). + + Element attributes are represented by QDomAttr objects that can + be queried using the attribute() and attributeNode() functions. + You can set attributes with the setAttribute() and + setAttributeNode() functions. Attributes can be removed with + removeAttribute(). There are namespace-aware equivalents to these + functions, i.e. setAttributeNS(), setAttributeNodeNS() and + removeAttributeNS(). + + If you want to access the text of a node use text(), e.g. + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 9 + The text() function operates recursively to find the text (since + not all elements contain text). If you want to find all the text + in all of a node's children, iterate over the children looking for + QDomText nodes, e.g. + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 10 + Note that we attempt to convert each node to a text node and use + text() rather than using firstChild().toText().data() or + n.toText().data() directly on the node, because the node may not + be a text element. + + You can get a list of all the decendents of an element which have + a specified tag name with elementsByTagName() or + elementsByTagNameNS(). + + To browse the elements of a dom document use firstChildElement(), lastChildElement(), + nextSiblingElement() and previousSiblingElement(). For example, to iterate over all + child elements called "entry" in a root element called "database", you can use: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 11 + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty element. Use the QDomDocument::createElement() + function to construct elements with content. +*/ +QDomElement::QDomElement() + : QDomNode() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomElement::QDomElement(const QDomElement& x) + : QDomNode(x) +{ +} + +QDomElement::QDomElement(QDomElementPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this DOM element. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomElement& QDomElement::operator= (const QDomElement& x) +{ + return (QDomElement&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomElement::nodeType() const + + Returns \c ElementNode. +*/ + +/*! + Sets this element's tag name to \a name. + + \sa tagName() +*/ +void QDomElement::setTagName(const QString& name) +{ + if (impl) + impl->name = name; +} + +/*! + Returns the tag name of this element. For an XML element like this: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 12 + + the tagname would return "img". + + \sa setTagName() +*/ +QString QDomElement::tagName() const +{ + if (!impl) + return QString(); + return impl->nodeName(); +} + + +/*! + Returns a QDomNamedNodeMap containing all this element's attributes. + + \sa attribute() setAttribute() attributeNode() setAttributeNode() +*/ +QDomNamedNodeMap QDomElement::attributes() const +{ + if (!impl) + return QDomNamedNodeMap(); + return QDomNamedNodeMap(IMPL->attributes()); +} + +/*! + Returns the attribute called \a name. If the attribute does not + exist \a defValue is returned. + + \sa setAttribute() attributeNode() setAttributeNode() attributeNS() +*/ +QString QDomElement::attribute(const QString& name, const QString& defValue) const +{ + if (!impl) + return defValue; + return IMPL->attribute(name, defValue); +} + +/*! + Adds an attribute called \a name with value \a value. If an + attribute with the same name exists, its value is replaced by \a + value. + + \sa attribute() setAttributeNode() setAttributeNS() +*/ +void QDomElement::setAttribute(const QString& name, const QString& value) +{ + if (!impl) + return; + IMPL->setAttribute(name, value); +} + +/*! + \fn void QDomElement::setAttribute(const QString& name, int value) + + \overload + The number is formatted according to the current locale. +*/ + +/*! + \fn void QDomElement::setAttribute(const QString& name, uint value) + + \overload + The number is formatted according to the current locale. +*/ + +/*! + \overload + + The number is formatted according to the current locale. +*/ +void QDomElement::setAttribute(const QString& name, qlonglong value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttribute(name, x); +} + +/*! + \overload + + The number is formatted according to the current locale. +*/ +void QDomElement::setAttribute(const QString& name, qulonglong value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttribute(name, x); +} + +/*! + \overload + + The number is formatted according to the current locale. +*/ +void QDomElement::setAttribute(const QString& name, float value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttribute(name, x); +} + +/*! + \overload + + The number is formatted according to the current locale. +*/ +void QDomElement::setAttribute(const QString& name, double value) +{ + if (!impl) + return; + QString x; + char buf[256]; + int count = qsnprintf(buf, sizeof(buf), "%.16g", value); + if (count > 0) + x = QString::fromLatin1(buf, count); + else + x.setNum(value); // Fallback + IMPL->setAttribute(name, x); +} + +/*! + Removes the attribute called name \a name from this element. + + \sa setAttribute() attribute() removeAttributeNS() +*/ +void QDomElement::removeAttribute(const QString& name) +{ + if (!impl) + return; + IMPL->removeAttribute(name); +} + +/*! + Returns the QDomAttr object that corresponds to the attribute + called \a name. If no such attribute exists a \link + QDomNode::isNull() null attribute\endlink is returned. + + \sa setAttributeNode() attribute() setAttribute() attributeNodeNS() +*/ +QDomAttr QDomElement::attributeNode(const QString& name) +{ + if (!impl) + return QDomAttr(); + return QDomAttr(IMPL->attributeNode(name)); +} + +/*! + Adds the attribute \a newAttr to this element. + + If the element has another attribute that has the same name as \a + newAttr, this function replaces that attribute and returns it; + otherwise the function returns a \link QDomNode::isNull() null + attribute\endlink. + + \sa attributeNode() setAttribute() setAttributeNodeNS() +*/ +QDomAttr QDomElement::setAttributeNode(const QDomAttr& newAttr) +{ + if (!impl) + return QDomAttr(); + return QDomAttr(IMPL->setAttributeNode(((QDomAttrPrivate*)newAttr.impl))); +} + +/*! + Removes the attribute \a oldAttr from the element and returns it. + + \sa attributeNode() setAttributeNode() +*/ +QDomAttr QDomElement::removeAttributeNode(const QDomAttr& oldAttr) +{ + if (!impl) + return QDomAttr(); // ### should this return oldAttr? + return QDomAttr(IMPL->removeAttributeNode(((QDomAttrPrivate*)oldAttr.impl))); +} + +/*! + Returns a QDomNodeList containing all descendants of this element + named \a tagname encountered during a preorder traversal of the + element subtree with this element as its root. The order of the + elements in the returned list is the order they are encountered + during the preorder traversal. + + \sa elementsByTagNameNS() QDomDocument::elementsByTagName() +*/ +QDomNodeList QDomElement::elementsByTagName(const QString& tagname) const +{ + return QDomNodeList(new QDomNodeListPrivate(impl, tagname)); +} + +/*! + Returns true if this element has an attribute called \a name; + otherwise returns false. + + \bold{Note:} This function does not take the presence of namespaces + into account. As a result, the specified name will be tested + against fully-qualified attribute names that include any namespace + prefixes that may be present. + + Use hasAttributeNS() to explicitly test for attributes with specific + namespaces and names. +*/ +bool QDomElement::hasAttribute(const QString& name) const +{ + if (!impl) + return false; + return IMPL->hasAttribute(name); +} + +/*! + Returns the attribute with the local name \a localName and the + namespace URI \a nsURI. If the attribute does not exist \a + defValue is returned. + + \sa setAttributeNS() attributeNodeNS() setAttributeNodeNS() attribute() +*/ +QString QDomElement::attributeNS(const QString nsURI, const QString& localName, const QString& defValue) const +{ + if (!impl) + return defValue; + return IMPL->attributeNS(nsURI, localName, defValue); +} + +/*! + Adds an attribute with the qualified name \a qName and the + namespace URI \a nsURI with the value \a value. If an attribute + with the same local name and namespace URI exists, its prefix is + replaced by the prefix of \a qName and its value is repaced by \a + value. + + Although \a qName is the qualified name, the local name is used to + decide if an existing attribute's value should be replaced. + + \sa attributeNS() setAttributeNodeNS() setAttribute() +*/ +void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, const QString& value) +{ + if (!impl) + return; + IMPL->setAttributeNS(nsURI, qName, value); +} + +/*! + \fn void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, int value) + + \overload +*/ + +/*! + \fn void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, uint value) + + \overload +*/ + +/*! + \overload +*/ +void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, qlonglong value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttributeNS(nsURI, qName, x); +} + +/*! + \overload +*/ +void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, qulonglong value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttributeNS(nsURI, qName, x); +} + +/*! + \overload +*/ +void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, double value) +{ + if (!impl) + return; + QString x; + x.setNum(value); + IMPL->setAttributeNS(nsURI, qName, x); +} + +/*! + Removes the attribute with the local name \a localName and the + namespace URI \a nsURI from this element. + + \sa setAttributeNS() attributeNS() removeAttribute() +*/ +void QDomElement::removeAttributeNS(const QString& nsURI, const QString& localName) +{ + if (!impl) + return; + QDomNodePrivate *n = IMPL->attributeNodeNS(nsURI, localName); + if (!n) + return; + IMPL->removeAttribute(n->nodeName()); +} + +/*! + Returns the QDomAttr object that corresponds to the attribute + with the local name \a localName and the namespace URI \a nsURI. + If no such attribute exists a \l{QDomNode::isNull()}{null + attribute} is returned. + + \sa setAttributeNode() attribute() setAttribute() +*/ +QDomAttr QDomElement::attributeNodeNS(const QString& nsURI, const QString& localName) +{ + if (!impl) + return QDomAttr(); + return QDomAttr(IMPL->attributeNodeNS(nsURI, localName)); +} + +/*! + Adds the attribute \a newAttr to this element. + + If the element has another attribute that has the same local name + and namespace URI as \a newAttr, this function replaces that + attribute and returns it; otherwise the function returns a \link + QDomNode::isNull() null attribute\endlink. + + \sa attributeNodeNS() setAttributeNS() setAttributeNode() +*/ +QDomAttr QDomElement::setAttributeNodeNS(const QDomAttr& newAttr) +{ + if (!impl) + return QDomAttr(); + return QDomAttr(IMPL->setAttributeNodeNS(((QDomAttrPrivate*)newAttr.impl))); +} + +/*! + Returns a QDomNodeList containing all descendants of this element + with local name \a localName and namespace URI \a nsURI encountered + during a preorder traversal of the element subtree with this element + as its root. The order of the elements in the returned list is the + order they are encountered during the preorder traversal. + + \sa elementsByTagName() QDomDocument::elementsByTagNameNS() +*/ +QDomNodeList QDomElement::elementsByTagNameNS(const QString& nsURI, const QString& localName) const +{ + return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName)); +} + +/*! + Returns true if this element has an attribute with the local name + \a localName and the namespace URI \a nsURI; otherwise returns + false. +*/ +bool QDomElement::hasAttributeNS(const QString& nsURI, const QString& localName) const +{ + if (!impl) + return false; + return IMPL->hasAttributeNS(nsURI, localName); +} + +/*! + Returns the element's text or an empty string. + + Example: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 13 + + The function text() of the QDomElement for the \c{<h1>} tag, + will return the following text: + + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 14 + + Comments are ignored by this function. It only evaluates QDomText + and QDomCDATASection objects. +*/ +QString QDomElement::text() const +{ + if (!impl) + return QString(); + return IMPL->text(); +} + +#undef IMPL + +/************************************************************** + * + * QDomTextPrivate + * + **************************************************************/ + +QDomTextPrivate::QDomTextPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val) + : QDomCharacterDataPrivate(d, parent, val) +{ + name = QLatin1String("#text"); +} + +QDomTextPrivate::QDomTextPrivate(QDomTextPrivate* n, bool deep) + : QDomCharacterDataPrivate(n, deep) +{ +} + +QDomNodePrivate* QDomTextPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomTextPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +QDomTextPrivate* QDomTextPrivate::splitText(int offset) +{ + if (!parent()) { + qWarning("QDomText::splitText The node has no parent. So I can not split"); + return 0; + } + + QDomTextPrivate* t = new QDomTextPrivate(ownerDocument(), 0, value.mid(offset)); + value.truncate(offset); + + parent()->insertAfter(t, this); + + return t; +} + +void QDomTextPrivate::save(QTextStream& s, int, int) const +{ + QDomTextPrivate *that = const_cast<QDomTextPrivate*>(this); + s << encodeText(value, s, !(that->parent() && that->parent()->isElement()), false, true); +} + +/************************************************************** + * + * QDomText + * + **************************************************************/ + +#define IMPL ((QDomTextPrivate*)impl) + +/*! + \class QDomText + \reentrant + \brief The QDomText class represents text data in the parsed XML document. + + \inmodule QtXml + \ingroup xml-tools + + You can split the text in a QDomText object over two QDomText + objecs with splitText(). + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty QDomText object. + + To construct a QDomText with content, use QDomDocument::createTextNode(). +*/ +QDomText::QDomText() + : QDomCharacterData() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomText::QDomText(const QDomText& x) + : QDomCharacterData(x) +{ +} + +QDomText::QDomText(QDomTextPrivate* n) + : QDomCharacterData(n) +{ +} + +/*! + Assigns \a x to this DOM text. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomText& QDomText::operator= (const QDomText& x) +{ + return (QDomText&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomText::nodeType() const + + Returns \c TextNode. +*/ + +/*! + Splits this DOM text object into two QDomText objects. This object + keeps its first \a offset characters and the second (newly + created) object is inserted into the document tree after this + object with the remaining characters. + + The function returns the newly created object. + + \sa QDomNode::normalize() +*/ +QDomText QDomText::splitText(int offset) +{ + if (!impl) + return QDomText(); + return QDomText(IMPL->splitText(offset)); +} + +#undef IMPL + +/************************************************************** + * + * QDomCommentPrivate + * + **************************************************************/ + +QDomCommentPrivate::QDomCommentPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val) + : QDomCharacterDataPrivate(d, parent, val) +{ + name = QLatin1String("#comment"); +} + +QDomCommentPrivate::QDomCommentPrivate(QDomCommentPrivate* n, bool deep) + : QDomCharacterDataPrivate(n, deep) +{ +} + + +QDomNodePrivate* QDomCommentPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomCommentPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +void QDomCommentPrivate::save(QTextStream& s, int depth, int indent) const +{ + /* We don't output whitespace if we would pollute a text node. */ + if (!(prev && prev->isText())) + s << QString(indent < 1 ? 0 : depth * indent, QLatin1Char(' ')); + + s << "<!--" << value; + if (value.endsWith(QLatin1Char('-'))) + s << ' '; // Ensures that XML comment doesn't end with ---> + s << "-->"; + + if (!(next && next->isText())) + s << endl; +} + +/************************************************************** + * + * QDomComment + * + **************************************************************/ + +/*! + \class QDomComment + \reentrant + \brief The QDomComment class represents an XML comment. + + \inmodule QtXml + \ingroup xml-tools + + A comment in the parsed XML such as this: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 15 + is represented by QDomComment objects in the parsed Dom tree. + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty comment. To construct a comment with content, + use the QDomDocument::createComment() function. +*/ +QDomComment::QDomComment() + : QDomCharacterData() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomComment::QDomComment(const QDomComment& x) + : QDomCharacterData(x) +{ +} + +QDomComment::QDomComment(QDomCommentPrivate* n) + : QDomCharacterData(n) +{ +} + +/*! + Assigns \a x to this DOM comment. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomComment& QDomComment::operator= (const QDomComment& x) +{ + return (QDomComment&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomComment::nodeType() const + + Returns \c CommentNode. +*/ + +/************************************************************** + * + * QDomCDATASectionPrivate + * + **************************************************************/ + +QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, + const QString& val) + : QDomTextPrivate(d, parent, val) +{ + name = QLatin1String("#cdata-section"); +} + +QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomCDATASectionPrivate* n, bool deep) + : QDomTextPrivate(n, deep) +{ +} + +QDomNodePrivate* QDomCDATASectionPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomCDATASectionPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +void QDomCDATASectionPrivate::save(QTextStream& s, int, int) const +{ + // ### How do we escape "]]>" ? + // "]]>" is not allowed; so there should be none in value anyway + s << "<![CDATA[" << value << "]]>"; +} + +/************************************************************** + * + * QDomCDATASection + * + **************************************************************/ + +/*! + \class QDomCDATASection + \reentrant + \brief The QDomCDATASection class represents an XML CDATA section. + + \inmodule QtXml + \ingroup xml-tools + + CDATA sections are used to escape blocks of text containing + characters that would otherwise be regarded as markup. The only + delimiter that is recognized in a CDATA section is the "]]>" + string that terminates the CDATA section. CDATA sections cannot be + nested. Their primary purpose is for including material such as + XML fragments, without needing to escape all the delimiters. + + Adjacent QDomCDATASection nodes are not merged by the + QDomNode::normalize() function. + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty CDATA section. To create a CDATA section with + content, use the QDomDocument::createCDATASection() function. +*/ +QDomCDATASection::QDomCDATASection() + : QDomText() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomCDATASection::QDomCDATASection(const QDomCDATASection& x) + : QDomText(x) +{ +} + +QDomCDATASection::QDomCDATASection(QDomCDATASectionPrivate* n) + : QDomText(n) +{ +} + +/*! + Assigns \a x to this CDATA section. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomCDATASection& QDomCDATASection::operator= (const QDomCDATASection& x) +{ + return (QDomCDATASection&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomCDATASection::nodeType() const + + Returns \c CDATASection. +*/ + +/************************************************************** + * + * QDomNotationPrivate + * + **************************************************************/ + +QDomNotationPrivate::QDomNotationPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, + const QString& aname, + const QString& pub, const QString& sys) + : QDomNodePrivate(d, parent) +{ + name = aname; + m_pub = pub; + m_sys = sys; +} + +QDomNotationPrivate::QDomNotationPrivate(QDomNotationPrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ + m_sys = n->m_sys; + m_pub = n->m_pub; +} + +QDomNodePrivate* QDomNotationPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomNotationPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +void QDomNotationPrivate::save(QTextStream& s, int, int) const +{ + s << "<!NOTATION " << name << ' '; + if (!m_pub.isNull()) { + s << "PUBLIC " << quotedValue(m_pub); + if (!m_sys.isNull()) + s << ' ' << quotedValue(m_sys); + } else { + s << "SYSTEM " << quotedValue(m_sys); + } + s << '>' << endl; +} + +/************************************************************** + * + * QDomNotation + * + **************************************************************/ + +#define IMPL ((QDomNotationPrivate*)impl) + +/*! + \class QDomNotation + \reentrant + \brief The QDomNotation class represents an XML notation. + + \inmodule QtXml + \ingroup xml-tools + + A notation either declares, by name, the format of an unparsed + entity (see section 4.7 of the XML 1.0 specification), or is used + for formal declaration of processing instruction targets (see + section 2.6 of the XML 1.0 specification). + + DOM does not support editing notation nodes; they are therefore + read-only. + + A notation node does not have any parent. + + You can retrieve the publicId() and systemId() from a notation + node. + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + + +/*! + Constructor. +*/ +QDomNotation::QDomNotation() + : QDomNode() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomNotation::QDomNotation(const QDomNotation& x) + : QDomNode(x) +{ +} + +QDomNotation::QDomNotation(QDomNotationPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this DOM notation. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomNotation& QDomNotation::operator= (const QDomNotation& x) +{ + return (QDomNotation&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomNotation::nodeType() const + + Returns \c NotationNode. +*/ + +/*! + Returns the public identifier of this notation. +*/ +QString QDomNotation::publicId() const +{ + if (!impl) + return QString(); + return IMPL->m_pub; +} + +/*! + Returns the system identifier of this notation. +*/ +QString QDomNotation::systemId() const +{ + if (!impl) + return QString(); + return IMPL->m_sys; +} + +#undef IMPL + +/************************************************************** + * + * QDomEntityPrivate + * + **************************************************************/ + +QDomEntityPrivate::QDomEntityPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, + const QString& aname, + const QString& pub, const QString& sys, const QString& notation) + : QDomNodePrivate(d, parent) +{ + name = aname; + m_pub = pub; + m_sys = sys; + m_notationName = notation; +} + +QDomEntityPrivate::QDomEntityPrivate(QDomEntityPrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ + m_sys = n->m_sys; + m_pub = n->m_pub; + m_notationName = n->m_notationName; +} + +QDomNodePrivate* QDomEntityPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomEntityPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +/* + Encode an entity value upon saving. +*/ +static QByteArray encodeEntity(const QByteArray& str) +{ + QByteArray tmp(str); + uint len = tmp.size(); + uint i = 0; + const char* d = tmp.data(); + while (i < len) { + if (d[i] == '%'){ + tmp.replace(i, 1, "<"); + d = tmp; + len += 4; + i += 5; + } + else if (d[i] == '"') { + tmp.replace(i, 1, """); + d = tmp; + len += 4; + i += 5; + } else if (d[i] == '&' && i + 1 < len && d[i+1] == '#') { + // Dont encode < or " or &custom;. + // Only encode character references + tmp.replace(i, 1, "&"); + d = tmp; + len += 4; + i += 5; + } else { + ++i; + } + } + + return tmp; +} + +void QDomEntityPrivate::save(QTextStream& s, int, int) const +{ + QString _name = name; + if (_name.startsWith(QLatin1Char('%'))) + _name = QLatin1String("% ") + _name.mid(1); + + if (m_sys.isNull() && m_pub.isNull()) { + s << "<!ENTITY " << _name << " \"" << encodeEntity(value.toUtf8()) << "\">" << endl; + } else { + s << "<!ENTITY " << _name << ' '; + if (m_pub.isNull()) { + s << "SYSTEM " << quotedValue(m_sys); + } else { + s << "PUBLIC " << quotedValue(m_pub) << ' ' << quotedValue(m_sys); + } + if (! m_notationName.isNull()) { + s << " NDATA " << m_notationName; + } + s << '>' << endl; + } +} + +/************************************************************** + * + * QDomEntity + * + **************************************************************/ + +#define IMPL ((QDomEntityPrivate*)impl) + +/*! + \class QDomEntity + \reentrant + \brief The QDomEntity class represents an XML entity. + + \inmodule QtXml + \ingroup xml-tools + + This class represents an entity in an XML document, either parsed + or unparsed. Note that this models the entity itself not the + entity declaration. + + DOM does not support editing entity nodes; if a user wants to make + changes to the contents of an entity, every related + QDomEntityReference node must be replaced in the DOM tree by a + clone of the entity's contents, and then the desired changes must + be made to each of the clones instead. All the descendants of an + entity node are read-only. + + An entity node does not have any parent. + + You can access the entity's publicId(), systemId() and + notationName() when available. + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + + +/*! + Constructs an empty entity. +*/ +QDomEntity::QDomEntity() + : QDomNode() +{ +} + + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomEntity::QDomEntity(const QDomEntity& x) + : QDomNode(x) +{ +} + +QDomEntity::QDomEntity(QDomEntityPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this DOM entity. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomEntity& QDomEntity::operator= (const QDomEntity& x) +{ + return (QDomEntity&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomEntity::nodeType() const + + Returns \c EntityNode. +*/ + +/*! + Returns the public identifier associated with this entity. If the + public identifier was not specified an empty string is returned. +*/ +QString QDomEntity::publicId() const +{ + if (!impl) + return QString(); + return IMPL->m_pub; +} + +/*! + Returns the system identifier associated with this entity. If the + system identifier was not specified an empty string is returned. +*/ +QString QDomEntity::systemId() const +{ + if (!impl) + return QString(); + return IMPL->m_sys; +} + +/*! + For unparsed entities this function returns the name of the + notation for the entity. For parsed entities this function returns + an empty string. +*/ +QString QDomEntity::notationName() const +{ + if (!impl) + return QString(); + return IMPL->m_notationName; +} + +#undef IMPL + +/************************************************************** + * + * QDomEntityReferencePrivate + * + **************************************************************/ + +QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& aname) + : QDomNodePrivate(d, parent) +{ + name = aname; +} + +QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomNodePrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ +} + +QDomNodePrivate* QDomEntityReferencePrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomEntityReferencePrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +void QDomEntityReferencePrivate::save(QTextStream& s, int, int) const +{ + s << '&' << name << ';'; +} + +/************************************************************** + * + * QDomEntityReference + * + **************************************************************/ + +/*! + \class QDomEntityReference + \reentrant + \brief The QDomEntityReference class represents an XML entity reference. + + \inmodule QtXml + \ingroup xml-tools + + A QDomEntityReference object may be inserted into the DOM tree + when an entity reference is in the source document, or when the + user wishes to insert an entity reference. + + Note that character references and references to predefined + entities are expanded by the XML processor so that characters are + represented by their Unicode equivalent rather than by an entity + reference. + + Moreover, the XML processor may completely expand references to + entities while building the DOM tree, instead of providing + QDomEntityReference objects. + + If it does provide such objects, then for a given entity reference + node, it may be that there is no entity node representing the + referenced entity; but if such an entity exists, then the child + list of the entity reference node is the same as that of the + entity node. As with the entity node, all descendants of the + entity reference are read-only. + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty entity reference. Use + QDomDocument::createEntityReference() to create a entity reference + with content. +*/ +QDomEntityReference::QDomEntityReference() + : QDomNode() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomEntityReference::QDomEntityReference(const QDomEntityReference& x) + : QDomNode(x) +{ +} + +QDomEntityReference::QDomEntityReference(QDomEntityReferencePrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this entity reference. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomEntityReference& QDomEntityReference::operator= (const QDomEntityReference& x) +{ + return (QDomEntityReference&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomEntityReference::nodeType() const + + Returns \c EntityReference. +*/ + +/************************************************************** + * + * QDomProcessingInstructionPrivate + * + **************************************************************/ + +QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomDocumentPrivate* d, + QDomNodePrivate* parent, const QString& target, const QString& data) + : QDomNodePrivate(d, parent) +{ + name = target; + value = data; +} + +QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomProcessingInstructionPrivate* n, bool deep) + : QDomNodePrivate(n, deep) +{ +} + + +QDomNodePrivate* QDomProcessingInstructionPrivate::cloneNode(bool deep) +{ + QDomNodePrivate* p = new QDomProcessingInstructionPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +void QDomProcessingInstructionPrivate::save(QTextStream& s, int, int) const +{ + s << "<?" << name << ' ' << value << "?>" << endl; +} + +/************************************************************** + * + * QDomProcessingInstruction + * + **************************************************************/ + +/*! + \class QDomProcessingInstruction + \reentrant + \brief The QDomProcessingInstruction class represents an XML processing + instruction. + + \inmodule QtXml + \ingroup xml-tools + + Processing instructions are used in XML to keep processor-specific + information in the text of the document. + + The XML declaration that appears at the top of an XML document, + typically \tt{<?xml version='1.0' encoding='UTF-8'?>}, is treated by QDom as a + processing instruction. This is unfortunate, since the XML declaration is + not a processing instruction; among other differences, it cannot be + inserted into a document anywhere but on the first line. + + Do not use this function to create an xml declaration, since although it + has the same syntax as a processing instruction, it isn't, and might not + be treated by QDom as such. + + The content of the processing instruction is retrieved with data() + and set with setData(). The processing instruction's target is + retrieved with target(). + + For further information about the Document Object Model see + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. + For a more general introduction of the DOM implementation see the + QDomDocument documentation. +*/ + +/*! + Constructs an empty processing instruction. Use + QDomDocument::createProcessingInstruction() to create a processing + instruction with content. +*/ +QDomProcessingInstruction::QDomProcessingInstruction() + : QDomNode() +{ +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomProcessingInstruction::QDomProcessingInstruction(const QDomProcessingInstruction& x) + : QDomNode(x) +{ +} + +QDomProcessingInstruction::QDomProcessingInstruction(QDomProcessingInstructionPrivate* n) + : QDomNode(n) +{ +} + +/*! + Assigns \a x to this processing instruction. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomProcessingInstruction& QDomProcessingInstruction::operator= (const QDomProcessingInstruction& x) +{ + return (QDomProcessingInstruction&) QDomNode::operator=(x); +} + +/*! + \fn QDomNode::NodeType QDomProcessingInstruction::nodeType() const + + Returns \c ProcessingInstructionNode. +*/ + +/*! + Returns the target of this processing instruction. + + \sa data() +*/ +QString QDomProcessingInstruction::target() const +{ + if (!impl) + return QString(); + return impl->nodeName(); +} + +/*! + Returns the content of this processing instruction. + + \sa setData() target() +*/ +QString QDomProcessingInstruction::data() const +{ + if (!impl) + return QString(); + return impl->nodeValue(); +} + +/*! + Sets the data contained in the processing instruction to \a d. + + \sa data() +*/ +void QDomProcessingInstruction::setData(const QString& d) +{ + if (!impl) + return; + impl->setNodeValue(d); +} + +/************************************************************** + * + * QDomDocumentPrivate + * + **************************************************************/ + +QDomDocumentPrivate::QDomDocumentPrivate() + : QDomNodePrivate(0), + nodeListTime(1) +{ + impl = new QDomImplementationPrivate; + type = new QDomDocumentTypePrivate(this, this); + + name = QLatin1String("#document"); +} + +QDomDocumentPrivate::QDomDocumentPrivate(const QString& aname) + : QDomNodePrivate(0), + nodeListTime(1) +{ + impl = new QDomImplementationPrivate; + type = new QDomDocumentTypePrivate(this, this); + type->name = aname; + + name = QLatin1String("#document"); +} + +QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentTypePrivate* dt) + : QDomNodePrivate(0), + nodeListTime(1) +{ + impl = new QDomImplementationPrivate; + if (dt != 0) { + type = dt; + type->ref.ref(); + } else { + type = new QDomDocumentTypePrivate(this, this); + } + + name = QLatin1String("#document"); +} + +QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentPrivate* n, bool deep) + : QDomNodePrivate(n, deep), + nodeListTime(1) +{ + impl = n->impl->clone(); + // Reference count is down to 0, so we set it to 1 here. + impl->ref.ref(); + type = (QDomDocumentTypePrivate*)n->type->cloneNode(); + type->setParent(this); + // Reference count is down to 0, so we set it to 1 here. + type->ref.ref(); +} + +QDomDocumentPrivate::~QDomDocumentPrivate() +{ + if (!impl->ref.deref()) + delete impl; + if (!type->ref.deref()) + delete type; +} + +void QDomDocumentPrivate::clear() +{ + if (!impl->ref.deref()) + delete impl; + if (!type->ref.deref()) + delete type; + impl = 0; + type = 0; + QDomNodePrivate::clear(); +} + +static void initializeReader(QXmlSimpleReader &reader, bool namespaceProcessing) +{ + reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), namespaceProcessing); + reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), !namespaceProcessing); + reader.setFeature(QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData"), false); // Shouldn't change in Qt 4 +} + +bool QDomDocumentPrivate::setContent(QXmlInputSource *source, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn) +{ + QXmlSimpleReader reader; + initializeReader(reader, namespaceProcessing); + return setContent(source, &reader, errorMsg, errorLine, errorColumn); +} + +bool QDomDocumentPrivate::setContent(QXmlInputSource *source, QXmlReader *reader, QString *errorMsg, int *errorLine, int *errorColumn) +{ + clear(); + impl = new QDomImplementationPrivate; + type = new QDomDocumentTypePrivate(this, this); + + bool namespaceProcessing = reader->feature(QLatin1String("http://xml.org/sax/features/namespaces")) + && !reader->feature(QLatin1String("http://xml.org/sax/features/namespace-prefixes")); + + QDomHandler hnd(this, namespaceProcessing); + reader->setContentHandler(&hnd); + reader->setErrorHandler(&hnd); + reader->setLexicalHandler(&hnd); + reader->setDeclHandler(&hnd); + reader->setDTDHandler(&hnd); + + if (!reader->parse(source)) { + if (errorMsg) + *errorMsg = hnd.errorMsg; + if (errorLine) + *errorLine = hnd.errorLine; + if (errorColumn) + *errorColumn = hnd.errorColumn; + return false; + } + + return true; +} + +QDomNodePrivate* QDomDocumentPrivate::cloneNode(bool deep) +{ + QDomNodePrivate *p = new QDomDocumentPrivate(this, deep); + // We are not interested in this node + p->ref.deref(); + return p; +} + +QDomElementPrivate* QDomDocumentPrivate::documentElement() +{ + QDomNodePrivate *p = first; + while (p && !p->isElement()) + p = p->next; + + return static_cast<QDomElementPrivate *>(p); +} + +QDomElementPrivate* QDomDocumentPrivate::createElement(const QString &tagName) +{ + bool ok; + QString fixedName = fixedXmlName(tagName, &ok); + if (!ok) + return 0; + + QDomElementPrivate *e = new QDomElementPrivate(this, 0, fixedName); + e->ref.deref(); + return e; +} + +QDomElementPrivate* QDomDocumentPrivate::createElementNS(const QString &nsURI, const QString &qName) +{ + bool ok; + QString fixedName = fixedXmlName(qName, &ok, true); + if (!ok) + return 0; + + QDomElementPrivate *e = new QDomElementPrivate(this, 0, nsURI, fixedName); + e->ref.deref(); + return e; +} + +QDomDocumentFragmentPrivate* QDomDocumentPrivate::createDocumentFragment() +{ + QDomDocumentFragmentPrivate *f = new QDomDocumentFragmentPrivate(this, (QDomNodePrivate*)0); + f->ref.deref(); + return f; +} + +QDomTextPrivate* QDomDocumentPrivate::createTextNode(const QString &data) +{ + bool ok; + QString fixedData = fixedCharData(data, &ok); + if (!ok) + return 0; + + QDomTextPrivate *t = new QDomTextPrivate(this, 0, fixedData); + t->ref.deref(); + return t; +} + +QDomCommentPrivate* QDomDocumentPrivate::createComment(const QString &data) +{ + bool ok; + QString fixedData = fixedComment(data, &ok); + if (!ok) + return 0; + + QDomCommentPrivate *c = new QDomCommentPrivate(this, 0, fixedData); + c->ref.deref(); + return c; +} + +QDomCDATASectionPrivate* QDomDocumentPrivate::createCDATASection(const QString &data) +{ + bool ok; + QString fixedData = fixedCDataSection(data, &ok); + if (!ok) + return 0; + + QDomCDATASectionPrivate *c = new QDomCDATASectionPrivate(this, 0, fixedData); + c->ref.deref(); + return c; +} + +QDomProcessingInstructionPrivate* QDomDocumentPrivate::createProcessingInstruction(const QString &target, + const QString &data) +{ + bool ok; + QString fixedData = fixedPIData(data, &ok); + if (!ok) + return 0; + // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) + QString fixedTarget = fixedXmlName(target, &ok); + if (!ok) + return 0; + + QDomProcessingInstructionPrivate *p = new QDomProcessingInstructionPrivate(this, 0, fixedTarget, fixedData); + p->ref.deref(); + return p; +} +QDomAttrPrivate* QDomDocumentPrivate::createAttribute(const QString &aname) +{ + bool ok; + QString fixedName = fixedXmlName(aname, &ok); + if (!ok) + return 0; + + QDomAttrPrivate *a = new QDomAttrPrivate(this, 0, fixedName); + a->ref.deref(); + return a; +} + +QDomAttrPrivate* QDomDocumentPrivate::createAttributeNS(const QString &nsURI, const QString &qName) +{ + bool ok; + QString fixedName = fixedXmlName(qName, &ok, true); + if (!ok) + return 0; + + QDomAttrPrivate *a = new QDomAttrPrivate(this, 0, nsURI, fixedName); + a->ref.deref(); + return a; +} + +QDomEntityReferencePrivate* QDomDocumentPrivate::createEntityReference(const QString &aname) +{ + bool ok; + QString fixedName = fixedXmlName(aname, &ok); + if (!ok) + return 0; + + QDomEntityReferencePrivate *e = new QDomEntityReferencePrivate(this, 0, fixedName); + e->ref.deref(); + return e; +} + +QDomNodePrivate* QDomDocumentPrivate::importNode(const QDomNodePrivate *importedNode, bool deep) +{ + QDomNodePrivate *node = 0; + switch (importedNode->nodeType()) { + case QDomNode::AttributeNode: + node = new QDomAttrPrivate((QDomAttrPrivate*)importedNode, true); + break; + case QDomNode::DocumentFragmentNode: + node = new QDomDocumentFragmentPrivate((QDomDocumentFragmentPrivate*)importedNode, deep); + break; + case QDomNode::ElementNode: + node = new QDomElementPrivate((QDomElementPrivate*)importedNode, deep); + break; + case QDomNode::EntityNode: + node = new QDomEntityPrivate((QDomEntityPrivate*)importedNode, deep); + break; + case QDomNode::EntityReferenceNode: + node = new QDomEntityReferencePrivate((QDomEntityReferencePrivate*)importedNode, false); + break; + case QDomNode::NotationNode: + node = new QDomNotationPrivate((QDomNotationPrivate*)importedNode, deep); + break; + case QDomNode::ProcessingInstructionNode: + node = new QDomProcessingInstructionPrivate((QDomProcessingInstructionPrivate*)importedNode, deep); + break; + case QDomNode::TextNode: + node = new QDomTextPrivate((QDomTextPrivate*)importedNode, deep); + break; + case QDomNode::CDATASectionNode: + node = new QDomCDATASectionPrivate((QDomCDATASectionPrivate*)importedNode, deep); + break; + case QDomNode::CommentNode: + node = new QDomCommentPrivate((QDomCommentPrivate*)importedNode, deep); + break; + default: + break; + } + if (node) { + node->setOwnerDocument(this); + // The QDomNode constructor increases the refcount, so deref first to + // keep refcount balanced. + node->ref.deref(); + } + return node; +} + +void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNode::EncodingPolicy encUsed) const +{ + const QDomNodePrivate* n = first; + + if(encUsed == QDomNode::EncodingFromDocument) { +#ifndef QT_NO_TEXTCODEC + const QDomNodePrivate* n = first; + + if (n && n->isProcessingInstruction() && n->nodeName() == QLatin1String("xml")) { + // we have an XML declaration + QString data = n->nodeValue(); + QRegExp encoding(QString::fromLatin1("encoding\\s*=\\s*((\"([^\"]*)\")|('([^']*)'))")); + encoding.indexIn(data); + QString enc = encoding.cap(3); + if (enc.isEmpty()) { + enc = encoding.cap(5); + } + if (enc.isEmpty()) + s.setCodec(QTextCodec::codecForName("UTF-8")); + else + s.setCodec(QTextCodec::codecForName(enc.toLatin1().data())); + } else { + s.setCodec(QTextCodec::codecForName("UTF-8")); + } +#endif + bool doc = false; + + while (n) { + if (!doc && !(n->isProcessingInstruction() && n->nodeName() == QLatin1String("xml"))) { + // save doctype after XML declaration + type->save(s, 0, indent); + doc = true; + } + n->save(s, 0, indent); + n = n->next; + } + } + else { + + // Write out the XML declaration. +#ifdef QT_NO_TEXTCODEC + const QLatin1String codecName("iso-8859-1"); +#else + const QTextCodec *const codec = s.codec(); + Q_ASSERT_X(codec, "QDomNode::save()", "A codec must be specified in the text stream."); + const QByteArray codecName = codec->name(); +#endif + + s << "<?xml version=\"1.0\" encoding=\"" + << codecName + << "\"?>\n"; + + // Skip the first processing instruction by name "xml", if any such exists. + const QDomNodePrivate* startNode = n; + + // First, we try to find the PI and sets the startNode to the one appearing after it. + while (n) { + if(n->isProcessingInstruction() && n->nodeName() == QLatin1String("xml")) { + startNode = n->next; + break; + } + else + n = n->next; + } + + // Now we serialize all the nodes after the faked XML declaration(the PI). + while(startNode) { + startNode->save(s, 0, indent); + startNode = startNode->next; + } + } +} + +/************************************************************** + * + * QDomDocument + * + **************************************************************/ + +#define IMPL ((QDomDocumentPrivate*)impl) + +/*! + \class QDomDocument + \reentrant + \brief The QDomDocument class represents an XML document. + + \inmodule QtXml + \mainclass + \ingroup xml-tools + + The QDomDocument class represents the entire XML document. + Conceptually, it is the root of the document tree, and provides + the primary access to the document's data. + + Since elements, text nodes, comments, processing instructions, + etc., cannot exist outside the context of a document, the document + class also contains the factory functions needed to create these + objects. The node objects created have an ownerDocument() function + which associates them with the document within whose context they + were created. The DOM classes that will be used most often are + QDomNode, QDomDocument, QDomElement and QDomText. + + The parsed XML is represented internally by a tree of objects that + can be accessed using the various QDom classes. All QDom classes + only \e reference objects in the internal tree. The internal + objects in the DOM tree will get deleted once the last QDom + object referencing them and the QDomDocument itself are deleted. + + Creation of elements, text nodes, etc. is done using the various + factory functions provided in this class. Using the default + constructors of the QDom classes will only result in empty + objects that cannot be manipulated or inserted into the Document. + + The QDomDocument class has several functions for creating document + data, for example, createElement(), createTextNode(), + createComment(), createCDATASection(), + createProcessingInstruction(), createAttribute() and + createEntityReference(). Some of these functions have versions + that support namespaces, i.e. createElementNS() and + createAttributeNS(). The createDocumentFragment() function is used + to hold parts of the document; this is useful for manipulating for + complex documents. + + The entire content of the document is set with setContent(). This + function parses the string it is passed as an XML document and + creates the DOM tree that represents the document. The root + element is available using documentElement(). The textual + representation of the document can be obtained using toString(). + + It is possible to insert a node from another document into the + document using importNode(). + + You can obtain a list of all the elements that have a particular + tag with elementsByTagName() or with elementsByTagNameNS(). + + The QDom classes are typically used as follows: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 16 + + Once \c doc and \c elem go out of scope, the whole internal tree + representing the XML document is deleted. + + To create a document using DOM use code like this: + \snippet doc/src/snippets/code/src_xml_dom_qdom.cpp 17 + + For further information about the Document Object Model see + the Document Object Model (DOM) + \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and + \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core} + Specifications. + + \sa {DOM Bookmarks Example}, {Simple DOM Model Example} +*/ + + +/*! + Constructs an empty document. +*/ +QDomDocument::QDomDocument() +{ + impl = 0; +} + +/*! + Creates a document and sets the name of the document type to \a + name. +*/ +QDomDocument::QDomDocument(const QString& name) +{ + // We take over ownership + impl = new QDomDocumentPrivate(name); +} + +/*! + Creates a document with the document type \a doctype. + + \sa QDomImplementation::createDocumentType() +*/ +QDomDocument::QDomDocument(const QDomDocumentType& doctype) +{ + impl = new QDomDocumentPrivate((QDomDocumentTypePrivate*)(doctype.impl)); +} + +/*! + Constructs a copy of \a x. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocument::QDomDocument(const QDomDocument& x) + : QDomNode(x) +{ +} + +QDomDocument::QDomDocument(QDomDocumentPrivate* x) + : QDomNode(x) +{ +} + +/*! + Assigns \a x to this DOM document. + + The data of the copy is shared (shallow copy): modifying one node + will also change the other. If you want to make a deep copy, use + cloneNode(). +*/ +QDomDocument& QDomDocument::operator= (const QDomDocument& x) +{ + return (QDomDocument&) QDomNode::operator=(x); +} + +/*! + Destroys the object and frees its resources. +*/ +QDomDocument::~QDomDocument() +{ +} + +/*! + \overload + + This function reads the XML document from the string \a text, returning + true if the content was successfully parsed; otherwise returns false. + Since \a text is already a Unicode string, no encoding detection + is done. +*/ +bool QDomDocument::setContent(const QString& text, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + QXmlInputSource source; + source.setData(text); + return IMPL->setContent(&source, namespaceProcessing, errorMsg, errorLine, errorColumn); +} + +/*! + \nonreentrant + + This function parses the XML document from the byte array \a + data and sets it as the content of the document. It tries to + detect the encoding of the document as required by the XML + specification. + + If \a namespaceProcessing is true, the parser recognizes + namespaces in the XML file and sets the prefix name, local name + and namespace URI to appropriate values. If \a namespaceProcessing + is false, the parser does no namespace processing when it reads + the XML file. + + If a parse error occurs, this function returns false and the error + message is placed in \c{*}\a{errorMsg}, the line number in + \c{*}\a{errorLine} and the column number in \c{*}\a{errorColumn} + (unless the associated pointer is set to 0); otherwise this + function returns true. The various error messages are described in + the QXmlParseException class documentation. Note that, if you + want to display these error messages to your application's users, + they will be displayed in English unless they are explicitly + translated. + + If \a namespaceProcessing is true, the function QDomNode::prefix() + returns a string for all elements and attributes. It returns an + empty string if the element or attribute has no prefix. + + Text nodes consisting only of whitespace are stripped and won't + appear in the QDomDocument. If this behavior is not desired, + one can use the setContent() overload that allows a QXmlReader to be + supplied. + + If \a namespaceProcessing is false, the functions + QDomNode::prefix(), QDomNode::localName() and + QDomNode::namespaceURI() return an empty string. + + Entity references are handled as follows: + \list + \o References to internal general entities and character entities occurring in the + content are included. The result is a QDomText node with the references replaced + by their corresponding entity values. + \o References to parameter entities occurring in the internal subset are included. + The result is a QDomDocumentType node which contains entity and notation declarations + with the references replaced by their corresponding entity values. + \o Any general parsed entity reference which is not defined in the internal subset and + which occurs in the content is represented as a QDomEntityReference node. + \o Any parsed entity reference which is not defined in the internal subset and which + occurs outside of the content is replaced with an empty string. + \o Any unparsed entity reference is replaced with an empty string. + \endlist + + \sa QDomNode::namespaceURI() QDomNode::localName() + QDomNode::prefix() QString::isNull() QString::isEmpty() +*/ +bool QDomDocument::setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + QBuffer buf; + buf.setData(data); + QXmlInputSource source(&buf); + return IMPL->setContent(&source, namespaceProcessing, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + + This function reads the XML document from the IO device \a dev, returning + true if the content was successfully parsed; otherwise returns false. +*/ +bool QDomDocument::setContent(QIODevice* dev, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + QXmlInputSource source(dev); + return IMPL->setContent(&source, namespaceProcessing, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + \since 4.5 + + This function reads the XML document from the QXmlInputSource \a source, + returning true if the content was successfully parsed; otherwise returns false. + +*/ +bool QDomDocument::setContent(QXmlInputSource *source, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn ) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + QXmlSimpleReader reader; + initializeReader(reader, namespaceProcessing); + return IMPL->setContent(source, &reader, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + + This function reads the XML document from the string \a text, returning + true if the content was successfully parsed; otherwise returns false. + Since \a text is already a Unicode string, no encoding detection + is performed. + + No namespace processing is performed either. +*/ +bool QDomDocument::setContent(const QString& text, QString *errorMsg, int *errorLine, int *errorColumn) +{ + return setContent(text, false, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + + This function reads the XML document from the byte array \a buffer, + returning true if the content was successfully parsed; otherwise returns + false. + + No namespace processing is performed. +*/ +bool QDomDocument::setContent(const QByteArray& buffer, QString *errorMsg, int *errorLine, int *errorColumn ) +{ + return setContent(buffer, false, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + + This function reads the XML document from the IO device \a dev, returning + true if the content was successfully parsed; otherwise returns false. + + No namespace processing is performed. +*/ +bool QDomDocument::setContent(QIODevice* dev, QString *errorMsg, int *errorLine, int *errorColumn ) +{ + return setContent(dev, false, errorMsg, errorLine, errorColumn); +} + +/*! + \overload + + This function reads the XML document from the QXmlInputSource \a source and + parses it with the QXmlReader \a reader, returning true if the content was + successfully parsed; otherwise returns false. + + This function doesn't change the features of the \a reader. If you want to + use certain features for parsing you can use this function to set up the + reader appropriately. + + \sa QXmlSimpleReader +*/ +bool QDomDocument::setContent(QXmlInputSource *source, QXmlReader *reader, QString *errorMsg, int *errorLine, int *errorColumn ) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return IMPL->setContent(source, reader, errorMsg, errorLine, errorColumn); +} + +/*! + Converts the parsed document back to its textual representation. + + This function uses \a indent as the amount of space to indent + subelements. + + If \a indent is -1, no whitespace at all is added. +*/ +QString QDomDocument::toString(int indent) const +{ + QString str; + QTextStream s(&str, QIODevice::WriteOnly); + save(s, indent); + return str; +} + +/*! + Converts the parsed document back to its textual representation + and returns a QByteArray containing the data encoded as UTF-8. + + This function uses \a indent as the amount of space to indent + subelements. + + \sa toString() +*/ +QByteArray QDomDocument::toByteArray(int indent) const +{ + // ### if there is an encoding specified in the xml declaration, this + // encoding declaration should be changed to utf8 + return toString(indent).toUtf8(); +} + + +/*! + Returns the document type of this document. +*/ +QDomDocumentType QDomDocument::doctype() const +{ + if (!impl) + return QDomDocumentType(); + return QDomDocumentType(IMPL->doctype()); +} + +/*! + Returns a QDomImplementation object. +*/ +QDomImplementation QDomDocument::implementation() const +{ + if (!impl) + return QDomImplementation(); + return QDomImplementation(IMPL->implementation()); +} + +/*! + Returns the root element of the document. +*/ +QDomElement QDomDocument::documentElement() const +{ + if (!impl) + return QDomElement(); + return QDomElement(IMPL->documentElement()); +} + +/*! + Creates a new element called \a tagName that can be inserted into + the DOM tree, e.g. using QDomNode::appendChild(). + + If \a tagName is not a valid XML name, the behavior of this function is governed + by QDomImplementation::InvalidDataPolicy. + + \sa createElementNS() QDomNode::appendChild() QDomNode::insertBefore() + QDomNode::insertAfter() +*/ +QDomElement QDomDocument::createElement(const QString& tagName) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomElement(IMPL->createElement(tagName)); +} + +/*! + Creates a new document fragment, that can be used to hold parts of + the document, e.g. when doing complex manipulations of the + document tree. +*/ +QDomDocumentFragment QDomDocument::createDocumentFragment() +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomDocumentFragment(IMPL->createDocumentFragment()); +} + +/*! + Creates a text node for the string \a value that can be inserted + into the document tree, e.g. using QDomNode::appendChild(). + + If \a value contains characters which cannot be stored as character + data of an XML document (even in the form of character references), the + behavior of this function is governed by QDomImplementation::InvalidDataPolicy. + + \sa QDomNode::appendChild() QDomNode::insertBefore() QDomNode::insertAfter() +*/ +QDomText QDomDocument::createTextNode(const QString& value) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomText(IMPL->createTextNode(value)); +} + +/*! + Creates a new comment for the string \a value that can be inserted + into the document, e.g. using QDomNode::appendChild(). + + If \a value contains characters which cannot be stored in an XML comment, + the behavior of this function is governed by QDomImplementation::InvalidDataPolicy. + + \sa QDomNode::appendChild() QDomNode::insertBefore() QDomNode::insertAfter() +*/ +QDomComment QDomDocument::createComment(const QString& value) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomComment(IMPL->createComment(value)); +} + +/*! + Creates a new CDATA section for the string \a value that can be + inserted into the document, e.g. using QDomNode::appendChild(). + + If \a value contains characters which cannot be stored in a CDATA section, + the behavior of this function is governed by + QDomImplementation::InvalidDataPolicy. + + \sa QDomNode::appendChild() QDomNode::insertBefore() QDomNode::insertAfter() +*/ +QDomCDATASection QDomDocument::createCDATASection(const QString& value) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomCDATASection(IMPL->createCDATASection(value)); +} + +/*! + Creates a new processing instruction that can be inserted into the + document, e.g. using QDomNode::appendChild(). This function sets + the target for the processing instruction to \a target and the + data to \a data. + + If \a target is not a valid XML name, or data if contains characters which cannot + appear in a processing instruction, the behavior of this function is governed by + QDomImplementation::InvalidDataPolicy. + + \sa QDomNode::appendChild() QDomNode::insertBefore() QDomNode::insertAfter() +*/ +QDomProcessingInstruction QDomDocument::createProcessingInstruction(const QString& target, + const QString& data) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomProcessingInstruction(IMPL->createProcessingInstruction(target, data)); +} + + +/*! + Creates a new attribute called \a name that can be inserted into + an element, e.g. using QDomElement::setAttributeNode(). + + If \a name is not a valid XML name, the behavior of this function is governed by + QDomImplementation::InvalidDataPolicy. + + \sa createAttributeNS() +*/ +QDomAttr QDomDocument::createAttribute(const QString& name) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomAttr(IMPL->createAttribute(name)); +} + +/*! + Creates a new entity reference called \a name that can be inserted + into the document, e.g. using QDomNode::appendChild(). + + If \a name is not a valid XML name, the behavior of this function is governed by + QDomImplementation::InvalidDataPolicy. + + \sa QDomNode::appendChild() QDomNode::insertBefore() QDomNode::insertAfter() +*/ +QDomEntityReference QDomDocument::createEntityReference(const QString& name) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomEntityReference(IMPL->createEntityReference(name)); +} + +/*! + Returns a QDomNodeList, that contains all the elements in the + document with the name \a tagname. The order of the node list is + the order they are encountered in a preorder traversal of the + element tree. + + \sa elementsByTagNameNS() QDomElement::elementsByTagName() +*/ +QDomNodeList QDomDocument::elementsByTagName(const QString& tagname) const +{ + return QDomNodeList(new QDomNodeListPrivate(impl, tagname)); +} + +/*! + Imports the node \a importedNode from another document to this + document. \a importedNode remains in the original document; this + function creates a copy that can be used within this document. + + This function returns the imported node that belongs to this + document. The returned node has no parent. It is not possible to + import QDomDocument and QDomDocumentType nodes. In those cases + this function returns a \link QDomNode::isNull() null node\endlink. + + If \a deep is true, this function imports not only the node \a + importedNode but its whole subtree; if it is false, only the \a + importedNode is imported. The argument \a deep has no effect on + QDomAttr and QDomEntityReference nodes, since the descendants of + QDomAttr nodes are always imported and those of + QDomEntityReference nodes are never imported. + + The behavior of this function is slightly different depending on + the node types: + \table + \header \i Node Type \i Behavior + \row \i QDomAttr + \i The owner element is set to 0 and the specified flag is + set to true in the generated attribute. The whole subtree + of \a importedNode is always imported for attribute nodes: + \a deep has no effect. + \row \i QDomDocument + \i Document nodes cannot be imported. + \row \i QDomDocumentFragment + \i If \a deep is true, this function imports the whole + document fragment; otherwise it only generates an empty + document fragment. + \row \i QDomDocumentType + \i Document type nodes cannot be imported. + \row \i QDomElement + \i Attributes for which QDomAttr::specified() is true are + also imported, other attributes are not imported. If \a + deep is true, this function also imports the subtree of \a + importedNode; otherwise it imports only the element node + (and some attributes, see above). + \row \i QDomEntity + \i Entity nodes can be imported, but at the moment there is + no way to use them since the document type is read-only in + DOM level 2. + \row \i QDomEntityReference + \i Descendants of entity reference nodes are never imported: + \a deep has no effect. + \row \i QDomNotation + \i Notation nodes can be imported, but at the moment there is + no way to use them since the document type is read-only in + DOM level 2. + \row \i QDomProcessingInstruction + \i The target and value of the processing instruction is + copied to the new node. + \row \i QDomText + \i The text is copied to the new node. + \row \i QDomCDATASection + \i The text is copied to the new node. + \row \i QDomComment + \i The text is copied to the new node. + \endtable + + \sa QDomElement::setAttribute() QDomNode::insertBefore() + QDomNode::insertAfter() QDomNode::replaceChild() QDomNode::removeChild() + QDomNode::appendChild() +*/ +QDomNode QDomDocument::importNode(const QDomNode& importedNode, bool deep) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomNode(IMPL->importNode(importedNode.impl, deep)); +} + +/*! + Creates a new element with namespace support that can be inserted + into the DOM tree. The name of the element is \a qName and the + namespace URI is \a nsURI. This function also sets + QDomNode::prefix() and QDomNode::localName() to appropriate values + (depending on \a qName). + + If \a qName is an empty string, returns a null element regardless of + whether the invalid data policy is set. + + \sa createElement() +*/ +QDomElement QDomDocument::createElementNS(const QString& nsURI, const QString& qName) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomElement(IMPL->createElementNS(nsURI, qName)); +} + +/*! + Creates a new attribute with namespace support that can be + inserted into an element. The name of the attribute is \a qName + and the namespace URI is \a nsURI. This function also sets + QDomNode::prefix() and QDomNode::localName() to appropriate values + (depending on \a qName). + + If \a qName is not a valid XML name, the behavior of this function is governed by + QDomImplementation::InvalidDataPolicy. + + \sa createAttribute() +*/ +QDomAttr QDomDocument::createAttributeNS(const QString& nsURI, const QString& qName) +{ + if (!impl) + impl = new QDomDocumentPrivate(); + return QDomAttr(IMPL->createAttributeNS(nsURI, qName)); +} + +/*! + Returns a QDomNodeList that contains all the elements in the + document with the local name \a localName and a namespace URI of + \a nsURI. The order of the node list is the order they are + encountered in a preorder traversal of the element tree. + + \sa elementsByTagName() QDomElement::elementsByTagNameNS() +*/ +QDomNodeList QDomDocument::elementsByTagNameNS(const QString& nsURI, const QString& localName) +{ + return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName)); +} + +/*! + Returns the element whose ID is equal to \a elementId. If no + element with the ID was found, this function returns a \link + QDomNode::isNull() null element\endlink. + + Since the QDomClasses do not know which attributes are element + IDs, this function returns always a \link QDomNode::isNull() null + element\endlink. This may change in a future version. +*/ +QDomElement QDomDocument::elementById(const QString& /*elementId*/) +{ + qWarning("elementById() is not implemented and will always return a null node."); + return QDomElement(); +} + +/*! + \fn QDomNode::NodeType QDomDocument::nodeType() const + + Returns \c DocumentNode. +*/ + +#undef IMPL + +/************************************************************** + * + * Node casting functions + * + **************************************************************/ + +/*! + Converts a QDomNode into a QDomAttr. If the node is not an + attribute, the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isAttr() +*/ +QDomAttr QDomNode::toAttr() const +{ + if (impl && impl->isAttr()) + return QDomAttr(((QDomAttrPrivate*)impl)); + return QDomAttr(); +} + +/*! + Converts a QDomNode into a QDomCDATASection. If the node is not a + CDATA section, the returned object will be \link + QDomNode::isNull() null\endlink. + + \sa isCDATASection() +*/ +QDomCDATASection QDomNode::toCDATASection() const +{ + if (impl && impl->isCDATASection()) + return QDomCDATASection(((QDomCDATASectionPrivate*)impl)); + return QDomCDATASection(); +} + +/*! + Converts a QDomNode into a QDomDocumentFragment. If the node is + not a document fragment the returned object will be \link + QDomNode::isNull() null\endlink. + + \sa isDocumentFragment() +*/ +QDomDocumentFragment QDomNode::toDocumentFragment() const +{ + if (impl && impl->isDocumentFragment()) + return QDomDocumentFragment(((QDomDocumentFragmentPrivate*)impl)); + return QDomDocumentFragment(); +} + +/*! + Converts a QDomNode into a QDomDocument. If the node is not a + document the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isDocument() +*/ +QDomDocument QDomNode::toDocument() const +{ + if (impl && impl->isDocument()) + return QDomDocument(((QDomDocumentPrivate*)impl)); + return QDomDocument(); +} + +/*! + Converts a QDomNode into a QDomDocumentType. If the node is not a + document type the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isDocumentType() +*/ +QDomDocumentType QDomNode::toDocumentType() const +{ + if (impl && impl->isDocumentType()) + return QDomDocumentType(((QDomDocumentTypePrivate*)impl)); + return QDomDocumentType(); +} + +/*! + Converts a QDomNode into a QDomElement. If the node is not an + element the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isElement() +*/ +QDomElement QDomNode::toElement() const +{ + if (impl && impl->isElement()) + return QDomElement(((QDomElementPrivate*)impl)); + return QDomElement(); +} + +/*! + Converts a QDomNode into a QDomEntityReference. If the node is not + an entity reference, the returned object will be \link + QDomNode::isNull() null\endlink. + + \sa isEntityReference() +*/ +QDomEntityReference QDomNode::toEntityReference() const +{ + if (impl && impl->isEntityReference()) + return QDomEntityReference(((QDomEntityReferencePrivate*)impl)); + return QDomEntityReference(); +} + +/*! + Converts a QDomNode into a QDomText. If the node is not a text, + the returned object will be \link QDomNode::isNull() null\endlink. + + \sa isText() +*/ +QDomText QDomNode::toText() const +{ + if (impl && impl->isText()) + return QDomText(((QDomTextPrivate*)impl)); + return QDomText(); +} + +/*! + Converts a QDomNode into a QDomEntity. If the node is not an + entity the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isEntity() +*/ +QDomEntity QDomNode::toEntity() const +{ + if (impl && impl->isEntity()) + return QDomEntity(((QDomEntityPrivate*)impl)); + return QDomEntity(); +} + +/*! + Converts a QDomNode into a QDomNotation. If the node is not a + notation the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isNotation() +*/ +QDomNotation QDomNode::toNotation() const +{ + if (impl && impl->isNotation()) + return QDomNotation(((QDomNotationPrivate*)impl)); + return QDomNotation(); +} + +/*! + Converts a QDomNode into a QDomProcessingInstruction. If the node + is not a processing instruction the returned object will be \link + QDomNode::isNull() null\endlink. + + \sa isProcessingInstruction() +*/ +QDomProcessingInstruction QDomNode::toProcessingInstruction() const +{ + if (impl && impl->isProcessingInstruction()) + return QDomProcessingInstruction(((QDomProcessingInstructionPrivate*)impl)); + return QDomProcessingInstruction(); +} + +/*! + Converts a QDomNode into a QDomCharacterData. If the node is not a + character data node the returned object will be \link + QDomNode::isNull() null\endlink. + + \sa isCharacterData() +*/ +QDomCharacterData QDomNode::toCharacterData() const +{ + if (impl && impl->isCharacterData()) + return QDomCharacterData(((QDomCharacterDataPrivate*)impl)); + return QDomCharacterData(); +} + +/*! + Converts a QDomNode into a QDomComment. If the node is not a + comment the returned object will be \link QDomNode::isNull() + null\endlink. + + \sa isComment() +*/ +QDomComment QDomNode::toComment() const +{ + if (impl && impl->isComment()) + return QDomComment(((QDomCommentPrivate*)impl)); + return QDomComment(); +} + +/************************************************************** + * + * QDomHandler + * + **************************************************************/ + +QDomHandler::QDomHandler(QDomDocumentPrivate* adoc, bool namespaceProcessing) +{ + doc = adoc; + node = doc; + cdata = false; + nsProcessing = namespaceProcessing; +} + +QDomHandler::~QDomHandler() +{ +} + +bool QDomHandler::endDocument() +{ + // ### is this really necessary? (rms) + if (node != doc) + return false; + return true; +} + +bool QDomHandler::startDTD(const QString& name, const QString& publicId, const QString& systemId) +{ + doc->doctype()->name = name; + doc->doctype()->publicId = publicId; + doc->doctype()->systemId = systemId; + return true; +} + +bool QDomHandler::startElement(const QString& nsURI, const QString&, const QString& qName, const QXmlAttributes& atts) +{ + // tag name + QDomNodePrivate* n; + if (nsProcessing) { + n = doc->createElementNS(nsURI, qName); + } else { + n = doc->createElement(qName); + } + n->setLocation(locator->lineNumber(), locator->columnNumber()); + + node->appendChild(n); + node = n; + + // attributes + for (int i=0; i<atts.length(); i++) + { + if (nsProcessing) { + ((QDomElementPrivate*)node)->setAttributeNS(atts.uri(i), atts.qName(i), atts.value(i)); + } else { + ((QDomElementPrivate*)node)->setAttribute(atts.qName(i), atts.value(i)); + } + } + + return true; +} + +bool QDomHandler::endElement(const QString&, const QString&, const QString&) +{ + if (node == doc) + return false; + node = node->parent(); + + return true; +} + +bool QDomHandler::characters(const QString& ch) +{ + // No text as child of some document + if (node == doc) + return false; + + QDomNodePrivate *n; + if (cdata) { + n = doc->createCDATASection(ch); + } else if (!entityName.isEmpty()) { + QDomEntityPrivate* e = new QDomEntityPrivate(doc, 0, entityName, + QString(), QString(), QString()); + e->value = ch; + doc->doctype()->appendChild(e); + n = doc->createEntityReference(entityName); + } else { + n = doc->createTextNode(ch); + } + n->setLocation(locator->lineNumber(), locator->columnNumber()); + node->appendChild(n); + + return true; +} + +bool QDomHandler::processingInstruction(const QString& target, const QString& data) +{ + QDomNodePrivate *n; + n = doc->createProcessingInstruction(target, data); + if (n) { + n->setLocation(locator->lineNumber(), locator->columnNumber()); + node->appendChild(n); + return true; + } + else + return false; +} + +extern bool qt_xml_skipped_entity_in_content; +bool QDomHandler::skippedEntity(const QString& name) +{ + // we can only handle inserting entity references into content + if (!qt_xml_skipped_entity_in_content) + return true; + + QDomNodePrivate *n = doc->createEntityReference(name); + n->setLocation(locator->lineNumber(), locator->columnNumber()); + node->appendChild(n); + return true; +} + +bool QDomHandler::fatalError(const QXmlParseException& exception) +{ + errorMsg = exception.message(); + errorLine = exception.lineNumber(); + errorColumn = exception.columnNumber(); + return QXmlDefaultHandler::fatalError(exception); +} + +bool QDomHandler::startCDATA() +{ + cdata = true; + return true; +} + +bool QDomHandler::endCDATA() +{ + cdata = false; + return true; +} + +bool QDomHandler::startEntity(const QString &name) +{ + entityName = name; + return true; +} + +bool QDomHandler::endEntity(const QString &) +{ + entityName.clear(); + return true; +} + +bool QDomHandler::comment(const QString& ch) +{ + QDomNodePrivate *n; + n = doc->createComment(ch); + n->setLocation(locator->lineNumber(), locator->columnNumber()); + node->appendChild(n); + return true; +} + +bool QDomHandler::unparsedEntityDecl(const QString &name, const QString &publicId, const QString &systemId, const QString ¬ationName) +{ + QDomEntityPrivate* e = new QDomEntityPrivate(doc, 0, name, + publicId, systemId, notationName); + doc->doctype()->appendChild(e); + return true; +} + +bool QDomHandler::externalEntityDecl(const QString &name, const QString &publicId, const QString &systemId) +{ + return unparsedEntityDecl(name, publicId, systemId, QString()); +} + +bool QDomHandler::notationDecl(const QString & name, const QString & publicId, const QString & systemId) +{ + QDomNotationPrivate* n = new QDomNotationPrivate(doc, 0, name, publicId, systemId); + doc->doctype()->appendChild(n); + return true; +} + +void QDomHandler::setDocumentLocator(QXmlLocator *locator) +{ + this->locator = locator; +} + +QT_END_NAMESPACE + +#endif // QT_NO_DOM diff --git a/src/xml/dom/qdom.h b/src/xml/dom/qdom.h new file mode 100644 index 0000000..f72361f --- /dev/null +++ b/src/xml/dom/qdom.h @@ -0,0 +1,681 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXml 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 QDOM_H +#define QDOM_H + +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Xml) + +#ifndef QT_NO_DOM + +class QIODevice; +class QTextStream; + +class QXmlInputSource; +class QXmlReader; + +class QDomDocumentPrivate; +class QDomDocumentTypePrivate; +class QDomDocumentFragmentPrivate; +class QDomNodePrivate; +class QDomNodeListPrivate; +class QDomImplementationPrivate; +class QDomElementPrivate; +class QDomNotationPrivate; +class QDomEntityPrivate; +class QDomEntityReferencePrivate; +class QDomProcessingInstructionPrivate; +class QDomAttrPrivate; +class QDomCharacterDataPrivate; +class QDomTextPrivate; +class QDomCommentPrivate; +class QDomCDATASectionPrivate; +class QDomNamedNodeMapPrivate; +class QDomImplementationPrivate; + +class QDomNodeList; +class QDomElement; +class QDomText; +class QDomComment; +class QDomCDATASection; +class QDomProcessingInstruction; +class QDomAttr; +class QDomEntityReference; +class QDomDocument; +class QDomNamedNodeMap; +class QDomDocument; +class QDomDocumentFragment; +class QDomDocumentType; +class QDomImplementation; +class QDomNode; +class QDomEntity; +class QDomNotation; +class QDomCharacterData; + +class Q_XML_EXPORT QDomImplementation +{ +public: + QDomImplementation(); + QDomImplementation(const QDomImplementation&); + ~QDomImplementation(); + QDomImplementation& operator= (const QDomImplementation&); + bool operator== (const QDomImplementation&) const; + bool operator!= (const QDomImplementation&) const; + + // functions + bool hasFeature(const QString& feature, const QString& version) const; + QDomDocumentType createDocumentType(const QString& qName, const QString& publicId, const QString& systemId); + QDomDocument createDocument(const QString& nsURI, const QString& qName, const QDomDocumentType& doctype); + + enum InvalidDataPolicy { AcceptInvalidChars = 0, DropInvalidChars, ReturnNullNode }; + static InvalidDataPolicy invalidDataPolicy(); + static void setInvalidDataPolicy(InvalidDataPolicy policy); + + // Qt extension + bool isNull(); + +private: + QDomImplementationPrivate* impl; + QDomImplementation(QDomImplementationPrivate*); + + friend class QDomDocument; +}; + +class Q_XML_EXPORT QDomNode +{ +public: + enum NodeType { + ElementNode = 1, + AttributeNode = 2, + TextNode = 3, + CDATASectionNode = 4, + EntityReferenceNode = 5, + EntityNode = 6, + ProcessingInstructionNode = 7, + CommentNode = 8, + DocumentNode = 9, + DocumentTypeNode = 10, + DocumentFragmentNode = 11, + NotationNode = 12, + BaseNode = 21,// this is not in the standard + CharacterDataNode = 22 // this is not in the standard + }; + + enum EncodingPolicy + { + EncodingFromDocument = 1, + EncodingFromTextStream = 2 + }; + + QDomNode(); + QDomNode(const QDomNode&); + QDomNode& operator= (const QDomNode&); + bool operator== (const QDomNode&) const; + bool operator!= (const QDomNode&) const; + ~QDomNode(); + + // DOM functions + QDomNode insertBefore(const QDomNode& newChild, const QDomNode& refChild); + QDomNode insertAfter(const QDomNode& newChild, const QDomNode& refChild); + QDomNode replaceChild(const QDomNode& newChild, const QDomNode& oldChild); + QDomNode removeChild(const QDomNode& oldChild); + QDomNode appendChild(const QDomNode& newChild); + bool hasChildNodes() const; + QDomNode cloneNode(bool deep = true) const; + void normalize(); + bool isSupported(const QString& feature, const QString& version) const; + + // DOM read-only attributes + QString nodeName() const; + NodeType nodeType() const; + QDomNode parentNode() const; + QDomNodeList childNodes() const; + QDomNode firstChild() const; + QDomNode lastChild() const; + QDomNode previousSibling() const; + QDomNode nextSibling() const; + QDomNamedNodeMap attributes() const; + QDomDocument ownerDocument() const; + QString namespaceURI() const; + QString localName() const; + bool hasAttributes() const; + + // DOM attributes + QString nodeValue() const; + void setNodeValue(const QString&); + QString prefix() const; + void setPrefix(const QString& pre); + + // Qt extensions + bool isAttr() const; + bool isCDATASection() const; + bool isDocumentFragment() const; + bool isDocument() const; + bool isDocumentType() const; + bool isElement() const; + bool isEntityReference() const; + bool isText() const; + bool isEntity() const; + bool isNotation() const; + bool isProcessingInstruction() const; + bool isCharacterData() const; + bool isComment() const; + + /** + * Shortcut to avoid dealing with QDomNodeList + * all the time. + */ + QDomNode namedItem(const QString& name) const; + + bool isNull() const; + void clear(); + + QDomAttr toAttr() const; + QDomCDATASection toCDATASection() const; + QDomDocumentFragment toDocumentFragment() const; + QDomDocument toDocument() const; + QDomDocumentType toDocumentType() const; + QDomElement toElement() const; + QDomEntityReference toEntityReference() const; + QDomText toText() const; + QDomEntity toEntity() const; + QDomNotation toNotation() const; + QDomProcessingInstruction toProcessingInstruction() const; + QDomCharacterData toCharacterData() const; + QDomComment toComment() const; + + void save(QTextStream&, int) const; + void save(QTextStream&, int, EncodingPolicy) const; // ### Qt 5: Merge overload(if we at all keep this) + + QDomElement firstChildElement(const QString &tagName = QString()) const; + QDomElement lastChildElement(const QString &tagName = QString()) const; + QDomElement previousSiblingElement(const QString &tagName = QString()) const; + QDomElement nextSiblingElement(const QString &taName = QString()) const; + + int lineNumber() const; + int columnNumber() const; + +protected: + QDomNodePrivate* impl; + QDomNode(QDomNodePrivate*); + +private: + friend class QDomDocument; + friend class QDomDocumentType; + friend class QDomNodeList; + friend class QDomNamedNodeMap; +}; + +class Q_XML_EXPORT QDomNodeList +{ +public: + QDomNodeList(); + QDomNodeList(const QDomNodeList&); + QDomNodeList& operator= (const QDomNodeList&); + bool operator== (const QDomNodeList&) const; + bool operator!= (const QDomNodeList&) const; + ~QDomNodeList(); + + // DOM functions + QDomNode item(int index) const; + inline QDomNode at(int index) const { return item(index); } // Qt API consistency + + // DOM read only attributes + uint length() const; + inline int count() const { return length(); } // Qt API consitancy + inline int size() const { return length(); } // Qt API consistency + inline bool isEmpty() const { return length() == 0; } // Qt API consistency + +private: + QDomNodeListPrivate* impl; + QDomNodeList(QDomNodeListPrivate*); + + friend class QDomNode; + friend class QDomElement; + friend class QDomDocument; +}; + +class Q_XML_EXPORT QDomDocumentType : public QDomNode +{ +public: + QDomDocumentType(); + QDomDocumentType(const QDomDocumentType& x); + QDomDocumentType& operator= (const QDomDocumentType&); + + // DOM read only attributes + QString name() const; + QDomNamedNodeMap entities() const; + QDomNamedNodeMap notations() const; + QString publicId() const; + QString systemId() const; + QString internalSubset() const; + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return DocumentTypeNode; } + +private: + QDomDocumentType(QDomDocumentTypePrivate*); + + friend class QDomImplementation; + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomDocument : public QDomNode +{ +public: + QDomDocument(); + explicit QDomDocument(const QString& name); + explicit QDomDocument(const QDomDocumentType& doctype); + QDomDocument(const QDomDocument& x); + QDomDocument& operator= (const QDomDocument&); + ~QDomDocument(); + + // DOM functions + QDomElement createElement(const QString& tagName); + QDomDocumentFragment createDocumentFragment(); + QDomText createTextNode(const QString& data); + QDomComment createComment(const QString& data); + QDomCDATASection createCDATASection(const QString& data); + QDomProcessingInstruction createProcessingInstruction(const QString& target, const QString& data); + QDomAttr createAttribute(const QString& name); + QDomEntityReference createEntityReference(const QString& name); + QDomNodeList elementsByTagName(const QString& tagname) const; + QDomNode importNode(const QDomNode& importedNode, bool deep); + QDomElement createElementNS(const QString& nsURI, const QString& qName); + QDomAttr createAttributeNS(const QString& nsURI, const QString& qName); + QDomNodeList elementsByTagNameNS(const QString& nsURI, const QString& localName); + QDomElement elementById(const QString& elementId); + + // DOM read only attributes + QDomDocumentType doctype() const; + QDomImplementation implementation() const; + QDomElement documentElement() const; + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return DocumentNode; } + + // Qt extensions + bool setContent(const QByteArray& text, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(const QString& text, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(QIODevice* dev, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(QXmlInputSource *source, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(const QByteArray& text, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(const QString& text, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(QIODevice* dev, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + bool setContent(QXmlInputSource *source, QXmlReader *reader, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0 ); + + // Qt extensions + QString toString(int = 1) const; + QByteArray toByteArray(int = 1) const; + +private: + QDomDocument(QDomDocumentPrivate*); + + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomNamedNodeMap +{ +public: + QDomNamedNodeMap(); + QDomNamedNodeMap(const QDomNamedNodeMap&); + QDomNamedNodeMap& operator= (const QDomNamedNodeMap&); + bool operator== (const QDomNamedNodeMap&) const; + bool operator!= (const QDomNamedNodeMap&) const; + ~QDomNamedNodeMap(); + + // DOM functions + QDomNode namedItem(const QString& name) const; + QDomNode setNamedItem(const QDomNode& newNode); + QDomNode removeNamedItem(const QString& name); + QDomNode item(int index) const; + QDomNode namedItemNS(const QString& nsURI, const QString& localName) const; + QDomNode setNamedItemNS(const QDomNode& newNode); + QDomNode removeNamedItemNS(const QString& nsURI, const QString& localName); + + // DOM read only attributes + uint length() const; + int count() const { return length(); } // Qt API consitancy + inline int size() const { return length(); } // Qt API consistency + inline bool isEmpty() const { return length() == 0; } // Qt API consistency + + // Qt extension + bool contains(const QString& name) const; + +private: + QDomNamedNodeMapPrivate* impl; + QDomNamedNodeMap(QDomNamedNodeMapPrivate*); + + friend class QDomNode; + friend class QDomDocumentType; + friend class QDomElement; +}; + +class Q_XML_EXPORT QDomDocumentFragment : public QDomNode +{ +public: + QDomDocumentFragment(); + QDomDocumentFragment(const QDomDocumentFragment& x); + QDomDocumentFragment& operator= (const QDomDocumentFragment&); + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return DocumentFragmentNode; } + +private: + QDomDocumentFragment(QDomDocumentFragmentPrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomCharacterData : public QDomNode +{ +public: + QDomCharacterData(); + QDomCharacterData(const QDomCharacterData& x); + QDomCharacterData& operator= (const QDomCharacterData&); + + // DOM functions + QString substringData(unsigned long offset, unsigned long count); + void appendData(const QString& arg); + void insertData(unsigned long offset, const QString& arg); + void deleteData(unsigned long offset, unsigned long count); + void replaceData(unsigned long offset, unsigned long count, const QString& arg); + + // DOM read only attributes + uint length() const; + + // DOM attributes + QString data() const; + void setData(const QString&); + + // Overridden from QDomNode + QDomNode::NodeType nodeType() const; + +private: + QDomCharacterData(QDomCharacterDataPrivate*); + + friend class QDomDocument; + friend class QDomText; + friend class QDomComment; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomAttr : public QDomNode +{ +public: + QDomAttr(); + QDomAttr(const QDomAttr& x); + QDomAttr& operator= (const QDomAttr&); + + // DOM read only attributes + QString name() const; + bool specified() const; + QDomElement ownerElement() const; + + // DOM attributes + QString value() const; + void setValue(const QString&); + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return AttributeNode; } + +private: + QDomAttr(QDomAttrPrivate*); + + friend class QDomDocument; + friend class QDomElement; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomElement : public QDomNode +{ +public: + QDomElement(); + QDomElement(const QDomElement& x); + QDomElement& operator= (const QDomElement&); + + // DOM functions + QString attribute(const QString& name, const QString& defValue = QString() ) const; + void setAttribute(const QString& name, const QString& value); + void setAttribute(const QString& name, qlonglong value); + void setAttribute(const QString& name, qulonglong value); + inline void setAttribute(const QString& name, int value) + { setAttribute(name, qlonglong(value)); } + inline void setAttribute(const QString& name, uint value) + { setAttribute(name, qulonglong(value)); } + void setAttribute(const QString& name, float value); + void setAttribute(const QString& name, double value); + void removeAttribute(const QString& name); + QDomAttr attributeNode(const QString& name); + QDomAttr setAttributeNode(const QDomAttr& newAttr); + QDomAttr removeAttributeNode(const QDomAttr& oldAttr); + QDomNodeList elementsByTagName(const QString& tagname) const; + bool hasAttribute(const QString& name) const; + + QString attributeNS(const QString nsURI, const QString& localName, const QString& defValue = QString()) const; + void setAttributeNS(const QString nsURI, const QString& qName, const QString& value); + inline void setAttributeNS(const QString nsURI, const QString& qName, int value) + { setAttributeNS(nsURI, qName, qlonglong(value)); } + inline void setAttributeNS(const QString nsURI, const QString& qName, uint value) + { setAttributeNS(nsURI, qName, qulonglong(value)); } + void setAttributeNS(const QString nsURI, const QString& qName, qlonglong value); + void setAttributeNS(const QString nsURI, const QString& qName, qulonglong value); + void setAttributeNS(const QString nsURI, const QString& qName, double value); + void removeAttributeNS(const QString& nsURI, const QString& localName); + QDomAttr attributeNodeNS(const QString& nsURI, const QString& localName); + QDomAttr setAttributeNodeNS(const QDomAttr& newAttr); + QDomNodeList elementsByTagNameNS(const QString& nsURI, const QString& localName) const; + bool hasAttributeNS(const QString& nsURI, const QString& localName) const; + + // DOM read only attributes + QString tagName() const; + void setTagName(const QString& name); // Qt extension + + // Overridden from QDomNode + QDomNamedNodeMap attributes() const; + inline QDomNode::NodeType nodeType() const { return ElementNode; } + + QString text() const; + +private: + QDomElement(QDomElementPrivate*); + + friend class QDomDocument; + friend class QDomNode; + friend class QDomAttr; +}; + +class Q_XML_EXPORT QDomText : public QDomCharacterData +{ +public: + QDomText(); + QDomText(const QDomText& x); + QDomText& operator= (const QDomText&); + + // DOM functions + QDomText splitText(int offset); + + // Overridden from QDomCharacterData + inline QDomNode::NodeType nodeType() const { return TextNode; } + +private: + QDomText(QDomTextPrivate*); + + friend class QDomCDATASection; + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomComment : public QDomCharacterData +{ +public: + QDomComment(); + QDomComment(const QDomComment& x); + QDomComment& operator= (const QDomComment&); + + // Overridden from QDomCharacterData + inline QDomNode::NodeType nodeType() const { return CommentNode; } + +private: + QDomComment(QDomCommentPrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomCDATASection : public QDomText +{ +public: + QDomCDATASection(); + QDomCDATASection(const QDomCDATASection& x); + QDomCDATASection& operator= (const QDomCDATASection&); + + // Overridden from QDomText + inline QDomNode::NodeType nodeType() const { return CDATASectionNode; } + +private: + QDomCDATASection(QDomCDATASectionPrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomNotation : public QDomNode +{ +public: + QDomNotation(); + QDomNotation(const QDomNotation& x); + QDomNotation& operator= (const QDomNotation&); + + // DOM read only attributes + QString publicId() const; + QString systemId() const; + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return NotationNode; } + +private: + QDomNotation(QDomNotationPrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomEntity : public QDomNode +{ +public: + QDomEntity(); + QDomEntity(const QDomEntity& x); + QDomEntity& operator= (const QDomEntity&); + + // DOM read only attributes + QString publicId() const; + QString systemId() const; + QString notationName() const; + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return EntityNode; } + +private: + QDomEntity(QDomEntityPrivate*); + + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomEntityReference : public QDomNode +{ +public: + QDomEntityReference(); + QDomEntityReference(const QDomEntityReference& x); + QDomEntityReference& operator= (const QDomEntityReference&); + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return EntityReferenceNode; } + +private: + QDomEntityReference(QDomEntityReferencePrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + +class Q_XML_EXPORT QDomProcessingInstruction : public QDomNode +{ +public: + QDomProcessingInstruction(); + QDomProcessingInstruction(const QDomProcessingInstruction& x); + QDomProcessingInstruction& operator= (const QDomProcessingInstruction&); + + // DOM read only attributes + QString target() const; + + // DOM attributes + QString data() const; + void setData(const QString& d); + + // Overridden from QDomNode + inline QDomNode::NodeType nodeType() const { return ProcessingInstructionNode; } + +private: + QDomProcessingInstruction(QDomProcessingInstructionPrivate*); + + friend class QDomDocument; + friend class QDomNode; +}; + + +Q_XML_EXPORT QTextStream& operator<<(QTextStream&, const QDomNode&); + +#endif // QT_NO_DOM + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDOM_H diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp new file mode 100644 index 0000000..c78d4ba --- /dev/null +++ b/src/xml/sax/qxml.cpp @@ -0,0 +1,8114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXml 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 "qxml.h" +#include "qtextcodec.h" +#include "qbuffer.h" +#include "qregexp.h" +#include "qmap.h" +#include "qstack.h" +#include <qdebug.h> + + +#ifdef Q_CC_BOR // borland 6 finds bogus warnings when building this file in uic3 +# pragma warn -8080 +#endif + +//#define QT_QXML_DEBUG + +// Error strings for the XML reader +#define XMLERR_OK QT_TRANSLATE_NOOP("QXml", "no error occurred") +#define XMLERR_ERRORBYCONSUMER QT_TRANSLATE_NOOP("QXml", "error triggered by consumer") +#define XMLERR_UNEXPECTEDEOF QT_TRANSLATE_NOOP("QXml", "unexpected end of file") +#define XMLERR_MORETHANONEDOCTYPE QT_TRANSLATE_NOOP("QXml", "more than one document type definition") +#define XMLERR_ERRORPARSINGELEMENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing element") +#define XMLERR_TAGMISMATCH QT_TRANSLATE_NOOP("QXml", "tag mismatch") +#define XMLERR_ERRORPARSINGCONTENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing content") +#define XMLERR_UNEXPECTEDCHARACTER QT_TRANSLATE_NOOP("QXml", "unexpected character") +#define XMLERR_INVALIDNAMEFORPI QT_TRANSLATE_NOOP("QXml", "invalid name for processing instruction") +#define XMLERR_VERSIONEXPECTED QT_TRANSLATE_NOOP("QXml", "version expected while reading the XML declaration") +#define XMLERR_WRONGVALUEFORSDECL QT_TRANSLATE_NOOP("QXml", "wrong value for standalone declaration") +#define XMLERR_EDECLORSDDECLEXPECTED QT_TRANSLATE_NOOP("QXml", "encoding declaration or standalone declaration expected while reading the XML declaration") +#define XMLERR_SDDECLEXPECTED QT_TRANSLATE_NOOP("QXml", "standalone declaration expected while reading the XML declaration") +#define XMLERR_ERRORPARSINGDOCTYPE QT_TRANSLATE_NOOP("QXml", "error occurred while parsing document type definition") +#define XMLERR_LETTEREXPECTED QT_TRANSLATE_NOOP("QXml", "letter is expected") +#define XMLERR_ERRORPARSINGCOMMENT QT_TRANSLATE_NOOP("QXml", "error occurred while parsing comment") +#define XMLERR_ERRORPARSINGREFERENCE QT_TRANSLATE_NOOP("QXml", "error occurred while parsing reference") +#define XMLERR_INTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "internal general entity reference not allowed in DTD") +#define XMLERR_EXTERNALGENERALENTITYINAV QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in attribute value") +#define XMLERR_EXTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in DTD") +#define XMLERR_UNPARSEDENTITYREFERENCE QT_TRANSLATE_NOOP("QXml", "unparsed entity reference in wrong context") +#define XMLERR_RECURSIVEENTITIES QT_TRANSLATE_NOOP("QXml", "recursive entities") +#define XMLERR_ERRORINTEXTDECL QT_TRANSLATE_NOOP("QXml", "error in the text declaration of an external entity") + +QT_BEGIN_NAMESPACE + +// the constants for the lookup table +static const signed char cltWS = 0; // white space +static const signed char cltPer = 1; // % +static const signed char cltAmp = 2; // & +static const signed char cltGt = 3; // > +static const signed char cltLt = 4; // < +static const signed char cltSlash = 5; // / +static const signed char cltQm = 6; // ? +static const signed char cltEm = 7; // ! +static const signed char cltDash = 8; // - +static const signed char cltCB = 9; // ] +static const signed char cltOB = 10; // [ +static const signed char cltEq = 11; // = +static const signed char cltDq = 12; // " +static const signed char cltSq = 13; // ' +static const signed char cltUnknown = 14; + +// Hack for letting QDom know where the skipped entity occurred +// ### Qt5: the use of this variable means the code isn't reentrant. +bool qt_xml_skipped_entity_in_content; + +// character lookup table +static const signed char charLookupTable[256]={ + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07 + cltUnknown, // 0x08 + cltWS, // 0x09 \t + cltWS, // 0x0A \n + cltUnknown, // 0x0B + cltUnknown, // 0x0C + cltWS, // 0x0D \r + cltUnknown, // 0x0E + cltUnknown, // 0x0F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F + cltWS, // 0x20 Space + cltEm, // 0x21 ! + cltDq, // 0x22 " + cltUnknown, // 0x23 + cltUnknown, // 0x24 + cltPer, // 0x25 % + cltAmp, // 0x26 & + cltSq, // 0x27 ' + cltUnknown, // 0x28 + cltUnknown, // 0x29 + cltUnknown, // 0x2A + cltUnknown, // 0x2B + cltUnknown, // 0x2C + cltDash, // 0x2D - + cltUnknown, // 0x2E + cltSlash, // 0x2F / + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37 + cltUnknown, // 0x38 + cltUnknown, // 0x39 + cltUnknown, // 0x3A + cltUnknown, // 0x3B + cltLt, // 0x3C < + cltEq, // 0x3D = + cltGt, // 0x3E > + cltQm, // 0x3F ? + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57 + cltUnknown, // 0x58 + cltUnknown, // 0x59 + cltUnknown, // 0x5A + cltOB, // 0x5B [ + cltUnknown, // 0x5C + cltCB, // 0x5D] + cltUnknown, // 0x5E + cltUnknown, // 0x5F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown // 0xF8 - 0xFF +}; + +// +// local helper functions +// + +/* + This function strips the TextDecl [77] ("<?xml ...?>") from the string \a + str. The stripped version is stored in \a str. If this function finds an + invalid TextDecl, it returns false, otherwise true. + + This function is used for external entities since those can include an + TextDecl that must be stripped before inserting the entity. +*/ +static bool stripTextDecl(QString& str) +{ + QString textDeclStart(QLatin1String("<?xml")); + if (str.startsWith(textDeclStart)) { + QRegExp textDecl(QString::fromLatin1( + "^<\\?xml\\s+" + "(version\\s*=\\s*((['\"])[-a-zA-Z0-9_.:]+\\3))?" + "\\s*" + "(encoding\\s*=\\s*((['\"])[A-Za-z][-a-zA-Z0-9_.]*\\6))?" + "\\s*\\?>" + )); + QString strTmp = str.replace(textDecl, QLatin1String("")); + if (strTmp.length() != str.length()) + return false; // external entity has wrong TextDecl + str = strTmp; + } + return true; +} + + +class QXmlAttributesPrivate +{ +}; + +/* \class QXmlInputSourcePrivate + \internal + + There's a slight misdesign in this class that can + be worth to keep in mind: the `str' member is + a buffer which QXmlInputSource::next() returns from, + and which is populated from the input device or input + stream. However, when the input is a QString(the user called + QXmlInputSource::setData()), `str' has two roles: it's the + buffer, but also the source. This /seems/ to be no problem + because in the case of having no device or stream, the QString + is read in one go. + */ +class QXmlInputSourcePrivate +{ +public: + QIODevice *inputDevice; + QTextStream *inputStream; + + QString str; + const QChar *unicode; + int pos; + int length; + bool nextReturnedEndOfData; +#ifndef QT_NO_TEXTCODEC + QTextDecoder *encMapper; +#endif + + QByteArray encodingDeclBytes; + QString encodingDeclChars; + bool lookingForEncodingDecl; +}; +class QXmlParseExceptionPrivate +{ +public: + QString msg; + int column; + int line; + QString pub; + QString sys; + +}; + +class QXmlLocatorPrivate +{ +}; + +class QXmlDefaultHandlerPrivate +{ +}; + +class QXmlSimpleReaderPrivate +{ +private: + // functions + QXmlSimpleReaderPrivate(); + ~QXmlSimpleReaderPrivate(); + void initIncrementalParsing(); + + // used to determine if elements are correctly nested + QStack<QString> tags; + + // used by parseReference() and parsePEReference() + enum EntityRecognitionContext { InContent, InAttributeValue, InEntityValue, InDTD }; + + // used for entity declarations + struct ExternParameterEntity + { + ExternParameterEntity() {} + ExternParameterEntity(const QString &p, const QString &s) + : publicId(p), systemId(s) {} + QString publicId; + QString systemId; + + Q_DUMMY_COMPARISON_OPERATOR(ExternParameterEntity) + }; + struct ExternEntity + { + ExternEntity() {} + ExternEntity(const QString &p, const QString &s, const QString &n) + : publicId(p), systemId(s), notation(n) {} + QString publicId; + QString systemId; + QString notation; + Q_DUMMY_COMPARISON_OPERATOR(ExternEntity) + }; + QMap<QString,ExternParameterEntity> externParameterEntities; + QMap<QString,QString> parameterEntities; + QMap<QString,ExternEntity> externEntities; + QMap<QString,QString> entities; + + // used for parsing of entity references + struct XmlRef { + XmlRef(const QString &_name = QString(), const QString &_value = QString()) + : name(_name), value(_value), index(0) {} + bool isEmpty() const { return index == value.length(); } + QChar next() { return value.at(index++); } + QString name; + QString value; + int index; + }; + QStack<XmlRef> xmlRefStack; + + // used for standalone declaration + enum Standalone { Yes, No, Unknown }; + + QString doctype; // only used for the doctype + QString xmlVersion; // only used to store the version information + QString encoding; // only used to store the encoding + Standalone standalone; // used to store the value of the standalone declaration + + QString publicId; // used by parseExternalID() to store the public ID + QString systemId; // used by parseExternalID() to store the system ID + + // Since publicId/systemId is used as temporary variables by parseExternalID(), it + // might overwrite the PUBLIC/SYSTEM for the document we're parsing. In effect, we would + // possibly send off an QXmlParseException that has the PUBLIC/SYSTEM of a entity declaration + // instead of those of the current document. + // Hence we have these two variables for storing the document's data. + QString thisPublicId; + QString thisSystemId; + + QString attDeclEName; // use by parseAttlistDecl() + QString attDeclAName; // use by parseAttlistDecl() + + // flags for some features support + bool useNamespaces; + bool useNamespacePrefixes; + bool reportWhitespaceCharData; + bool reportEntities; + + // used to build the attribute list + QXmlAttributes attList; + + // used in QXmlSimpleReader::parseContent() to decide whether character + // data was read + bool contentCharDataRead; + + // helper classes + QXmlLocator *locator; + QXmlNamespaceSupport namespaceSupport; + + // error string + QString error; + + // arguments for parse functions (this is needed to allow incremental + // parsing) + bool parsePI_xmldecl; + bool parseName_useRef; + bool parseReference_charDataRead; + EntityRecognitionContext parseReference_context; + bool parseExternalID_allowPublicID; + EntityRecognitionContext parsePEReference_context; + QString parseString_s; + + // for incremental parsing + struct ParseState { + typedef bool (QXmlSimpleReaderPrivate::*ParseFunction)(); + ParseFunction function; + int state; + }; + QStack<ParseState> *parseStack; + + // used in parseProlog() + bool xmldecl_possible; + bool doctype_read; + + // used in parseDoctype() + bool startDTDwasReported; + + // used in parseString() + signed char Done; + + + // variables + QXmlContentHandler *contentHnd; + QXmlErrorHandler *errorHnd; + QXmlDTDHandler *dtdHnd; + QXmlEntityResolver *entityRes; + QXmlLexicalHandler *lexicalHnd; + QXmlDeclHandler *declHnd; + + QXmlInputSource *inputSource; + + QChar c; // the character at reading position + int lineNr; // number of line + int columnNr; // position in line + + QChar nameArray[256]; // only used for names + QString nameValue; // only used for names + int nameArrayPos; + int nameValueLen; + QChar refArray[256]; // only used for references + QString refValue; // only used for references + int refArrayPos; + int refValueLen; + QChar stringArray[256]; // used for any other strings that are parsed + QString stringValue; // used for any other strings that are parsed + int stringArrayPos; + int stringValueLen; + QString emptyStr; + + const QString &string(); + void stringClear(); + void stringAddC(QChar); + inline void stringAddC() { stringAddC(c); } + const QString &name(); + void nameClear(); + void nameAddC(QChar); + inline void nameAddC() { nameAddC(c); } + const QString &ref(); + void refClear(); + void refAddC(QChar); + inline void refAddC() { refAddC(c); } + + // private functions + bool eat_ws(); + bool next_eat_ws(); + + void QT_FASTCALL next(); + bool atEnd(); + + void init(const QXmlInputSource* i); + void initData(); + + bool entityExist(const QString&) const; + + bool parseBeginOrContinue(int state, bool incremental); + + bool parseProlog(); + bool parseElement(); + bool processElementEmptyTag(); + bool processElementETagBegin2(); + bool processElementAttribute(); + bool parseMisc(); + bool parseContent(); + + bool parsePI(); + bool parseDoctype(); + bool parseComment(); + + bool parseName(); + bool parseNmtoken(); + bool parseAttribute(); + bool parseReference(); + bool processReference(); + + bool parseExternalID(); + bool parsePEReference(); + bool parseMarkupdecl(); + bool parseAttlistDecl(); + bool parseAttType(); + bool parseAttValue(); + bool parseElementDecl(); + bool parseNotationDecl(); + bool parseChoiceSeq(); + bool parseEntityDecl(); + bool parseEntityValue(); + + bool parseString(); + + bool insertXmlRef(const QString&, const QString&, bool); + + bool reportEndEntities(); + void reportParseError(const QString& error); + + typedef bool (QXmlSimpleReaderPrivate::*ParseFunction) (); + void unexpectedEof(ParseFunction where, int state); + void parseFailed(ParseFunction where, int state); + void pushParseState(ParseFunction function, int state); + + Q_DECLARE_PUBLIC(QXmlSimpleReader) + QXmlSimpleReader *q_ptr; + + friend class QXmlSimpleReaderLocator; +}; + +/*! + \class QXmlParseException + \reentrant + \brief The QXmlParseException class is used to report errors with + the QXmlErrorHandler interface. + + \inmodule QtXml + \ingroup xml-tools + + The XML subsystem constructs an instance of this class when it + detects an error. You can retrieve the place where the error + occurred using systemId(), publicId(), lineNumber() and + columnNumber(), along with the error message(). The possible error + messages are: + + + \list + \o "no error occurred" + \o "error triggered by consumer" + \o "unexpected end of file" + \o "more than one document type definition" + \o "error occurred while parsing element" + \o "tag mismatch" + \o "error occurred while parsing content" + \o "unexpected character" + \o "invalid name for processing instruction" + \o "version expected while reading the XML declaration" + \o "wrong value for standalone declaration" + \o "encoding declaration or standalone declaration expected while reading the XML declaration" + \o "standalone declaration expected while reading the XML declaration" + \o "error occurred while parsing document type definition" + \o "letter is expected" + \o "error occurred while parsing comment" + \o "error occurred while parsing reference" + \o "internal general entity reference not allowed in DTD" + \o "external parsed general entity reference not allowed in attribute value" + \o "external parsed general entity reference not allowed in DTD" + \o "unparsed entity reference n wrong context" + \o "recursive entities" + \o "error in the text declaration of an external entity" + \endlist + + Note that, if you want to display these error messages to your + application's users, they will be displayed in English unless + they are explicitly translated. + + \sa QXmlErrorHandler, QXmlReader +*/ + +/*! + Constructs a parse exception with the error string \a name for + column \a c and line \a l for the public identifier \a p and the + system identifier \a s. +*/ + +QXmlParseException::QXmlParseException(const QString& name, int c, int l, + const QString& p, const QString& s) +{ + d = new QXmlParseExceptionPrivate; + d->msg = name; + d->column = c; + d->line = l; + d->pub = p; + d->sys = s; +} + +/*! + Destroys the QXmlParseException. +*/ +QXmlParseException::~QXmlParseException() +{ + delete d; +} + +/*! + Returns the error message. +*/ +QString QXmlParseException::message() const +{ + return d->msg; +} +/*! + Returns the column number where the error occurred. +*/ +int QXmlParseException::columnNumber() const +{ + return d->column; +} +/*! + Returns the line number where the error occurred. +*/ +int QXmlParseException::lineNumber() const +{ + return d->line; +} +/*! + Returns the public identifier where the error occurred. +*/ +QString QXmlParseException::publicId() const +{ + return d->pub; +} +/*! + Returns the system identifier where the error occurred. +*/ +QString QXmlParseException::systemId() const +{ + return d->sys; +} + + +/*! + \class QXmlLocator + \reentrant + \brief The QXmlLocator class provides the XML handler classes with + information about the parsing position within a file. + + \inmodule QtXml + \ingroup xml-tools + + The reader reports a QXmlLocator to the content handler before it + starts to parse the document. This is done with the + QXmlContentHandler::setDocumentLocator() function. The handler + classes can now use this locator to get the position (lineNumber() + and columnNumber()) that the reader has reached. +*/ + +/*! + Constructor. +*/ +QXmlLocator::QXmlLocator() +{ +} + +/*! + Destructor. +*/ +QXmlLocator::~QXmlLocator() +{ +} + +/*! + \fn int QXmlLocator::columnNumber() const + + Returns the column number (starting at 1) or -1 if there is no + column number available. +*/ + +/*! + \fn int QXmlLocator::lineNumber() const + + Returns the line number (starting at 1) or -1 if there is no line + number available. +*/ + +class QXmlSimpleReaderLocator : public QXmlLocator +{ +public: + QXmlSimpleReaderLocator(QXmlSimpleReader* parent) + { + reader = parent; + } + ~QXmlSimpleReaderLocator() + { + } + + int columnNumber() const + { + return (reader->d_ptr->columnNr == -1 ? -1 : reader->d_ptr->columnNr + 1); + } + int lineNumber() const + { + return (reader->d_ptr->lineNr == -1 ? -1 : reader->d_ptr->lineNr + 1); + } +// QString getPublicId() +// QString getSystemId() + +private: + QXmlSimpleReader *reader; +}; + +/********************************************* + * + * QXmlNamespaceSupport + * + *********************************************/ + +typedef QMap<QString, QString> NamespaceMap; + +class QXmlNamespaceSupportPrivate +{ +public: + QXmlNamespaceSupportPrivate() + { + ns.insert(QLatin1String("xml"), QLatin1String("http://www.w3.org/XML/1998/namespace")); // the XML namespace + } + + ~QXmlNamespaceSupportPrivate() + { + } + + QStack<NamespaceMap> nsStack; + NamespaceMap ns; +}; + +/*! + \class QXmlNamespaceSupport + \since 4.4 + \reentrant + \brief The QXmlNamespaceSupport class is a helper class for XML + readers which want to include namespace support. + + \inmodule QtXml + \ingroup xml-tools + + You can set the prefix for the current namespace with setPrefix(), + and get the list of current prefixes (or those for a given URI) + with prefixes(). The namespace URI is available from uri(). Use + pushContext() to start a new namespace context, and popContext() + to return to the previous namespace context. Use splitName() or + processName() to split a name into its prefix and local name. + + \sa {Namespace Support via Features} +*/ + +/*! + Constructs a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::QXmlNamespaceSupport() +{ + d = new QXmlNamespaceSupportPrivate; +} + +/*! + Destroys a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::~QXmlNamespaceSupport() +{ + delete d; +} + +/*! + This function declares a prefix \a pre in the current namespace + context to be the namespace URI \a uri. The prefix remains in + force until this context is popped, unless it is shadowed in a + descendant context. + + Note that there is an asymmetry in this library. prefix() does not + return the default "" prefix, even if you have declared one; to + check for a default prefix, you must look it up explicitly using + uri(). This asymmetry exists to make it easier to look up prefixes + for attribute names, where the default prefix is not allowed. +*/ +void QXmlNamespaceSupport::setPrefix(const QString& pre, const QString& uri) +{ + if(pre.isNull()) { + d->ns.insert(QLatin1String(""), uri); + } else { + d->ns.insert(pre, uri); + } +} + +/*! + Returns one of the prefixes mapped to the namespace URI \a uri. + + If more than one prefix is currently mapped to the same URI, this + function makes an arbitrary selection; if you want all of the + prefixes, use prefixes() instead. + + Note: to check for a default prefix, use the uri() function with + an argument of "". +*/ +QString QXmlNamespaceSupport::prefix(const QString& uri) const +{ + NamespaceMap::const_iterator itc, it = d->ns.constBegin(); + while ((itc=it) != d->ns.constEnd()) { + ++it; + if (*itc == uri && !itc.key().isEmpty()) + return itc.key(); + } + return QLatin1String(""); +} + +/*! + Looks up the prefix \a prefix in the current context and returns + the currently-mapped namespace URI. Use the empty string ("") for + the default namespace. +*/ +QString QXmlNamespaceSupport::uri(const QString& prefix) const +{ + return d->ns[prefix]; +} + +/*! + Splits the name \a qname at the ':' and returns the prefix in \a + prefix and the local name in \a localname. + + \sa processName() +*/ +void QXmlNamespaceSupport::splitName(const QString& qname, QString& prefix, + QString& localname) const +{ + int pos = qname.indexOf(QLatin1Char(':')); + if (pos == -1) + pos = qname.size(); + + prefix = qname.left(pos); + localname = qname.mid(pos+1); +} + +/*! + Processes a raw XML 1.0 name in the current context by removing + the prefix and looking it up among the prefixes currently + declared. + + \a qname is the raw XML 1.0 name to be processed. \a isAttribute + is true if the name is an attribute name. + + This function stores the namespace URI in \a nsuri (which will be + set to an empty string if the raw name has an undeclared prefix), + and stores the local name (without prefix) in \a localname (which + will be set to an empty string if no namespace is in use). + + Note that attribute names are processed differently than element + names: an unprefixed element name gets the default namespace (if + any), while an unprefixed attribute name does not. +*/ +void QXmlNamespaceSupport::processName(const QString& qname, + bool isAttribute, + QString& nsuri, QString& localname) const +{ + int len = qname.size(); + const QChar *data = qname.constData(); + for (int pos = 0; pos < len; ++pos) { + if (data[pos] == QLatin1Char(':')) { + nsuri = uri(qname.left(pos)); + localname = qname.mid(pos + 1); + return; + } + } + + // there was no ':' + nsuri.clear(); + // attributes don't take default namespace + if (!isAttribute && !d->ns.isEmpty()) { + /* + We want to access d->ns.value(""), but as an optimization + we use the fact that "" compares less than any other + string, so it's either first in the map or not there. + */ + NamespaceMap::const_iterator first = d->ns.constBegin(); + if (first.key().isEmpty()) + nsuri = first.value(); // get default namespace + } + localname = qname; +} + +/*! + Returns a list of all the prefixes currently declared. + + If there is a default prefix, this function does not return it in + the list; check for the default prefix using uri() with an + argument of "". +*/ +QStringList QXmlNamespaceSupport::prefixes() const +{ + QStringList list; + + NamespaceMap::const_iterator itc, it = d->ns.constBegin(); + while ((itc=it) != d->ns.constEnd()) { + ++it; + if (!itc.key().isEmpty()) + list.append(itc.key()); + } + return list; +} + +/*! + \overload + + Returns a list of all prefixes currently declared for the + namespace URI \a uri. + + The "xml:" prefix is included. If you only want one prefix that is + mapped to the namespace URI, and you don't care which one you get, + use the prefix() function instead. + + Note: The empty (default) prefix is never included in this list; + to check for the presence of a default namespace, call uri() with + "" as the argument. +*/ +QStringList QXmlNamespaceSupport::prefixes(const QString& uri) const +{ + QStringList list; + + NamespaceMap::const_iterator itc, it = d->ns.constBegin(); + while ((itc=it) != d->ns.constEnd()) { + ++it; + if (*itc == uri && !itc.key().isEmpty()) + list.append(itc.key()); + } + return list; +} + +/*! + Starts a new namespace context. + + Normally, you should push a new context at the beginning of each + XML element: the new context automatically inherits the + declarations of its parent context, and it also keeps track of + which declarations were made within this context. + + \sa popContext() +*/ +void QXmlNamespaceSupport::pushContext() +{ + d->nsStack.push(d->ns); +} + +/*! + Reverts to the previous namespace context. + + Normally, you should pop the context at the end of each XML + element. After popping the context, all namespace prefix mappings + that were previously in force are restored. + + \sa pushContext() +*/ +void QXmlNamespaceSupport::popContext() +{ + d->ns.clear(); + if(!d->nsStack.isEmpty()) + d->ns = d->nsStack.pop(); +} + +/*! + Resets this namespace support object ready for reuse. +*/ +void QXmlNamespaceSupport::reset() +{ + delete d; + d = new QXmlNamespaceSupportPrivate; +} + + + +/********************************************* + * + * QXmlAttributes + * + *********************************************/ + +/*! + \class QXmlAttributes + \reentrant + \brief The QXmlAttributes class provides XML attributes. + + \inmodule QtXml + \ingroup xml-tools + + If attributes are reported by QXmlContentHandler::startElement() + this class is used to pass the attribute values. + + Use index() to locate the position of an attribute in the list, + count() to retrieve the number of attributes, and clear() to + remove the attributes. New attributes can be added with append(). + Use type() to get an attribute's type and value() to get its + value. The attribute's name is available from localName() or + qName(), and its namespace URI from uri(). + +*/ + +/*! + \fn QXmlAttributes::QXmlAttributes() + + Constructs an empty attribute list. +*/ + +/*! + \fn QXmlAttributes::~QXmlAttributes() + + Destroys the attributes object. +*/ + +/*! + Looks up the index of an attribute by the qualified name \a qName. + + Returns the index of the attribute or -1 if it wasn't found. + + \sa {Namespace Support via Features} +*/ +int QXmlAttributes::index(const QString& qName) const +{ + for (int i = 0; i < attList.size(); ++i) { + if (attList.at(i).qname == qName) + return i; + } + return -1; +} + +/*! \overload + */ +int QXmlAttributes::index(const QLatin1String& qName) const +{ + for (int i = 0; i < attList.size(); ++i) { + if (attList.at(i).qname == qName) + return i; + } + return -1; +} + +/*! + \overload + + Looks up the index of an attribute by a namespace name. + + \a uri specifies the namespace URI, or an empty string if the name + has no namespace URI. \a localPart specifies the attribute's local + name. + + Returns the index of the attribute, or -1 if it wasn't found. + + \sa {Namespace Support via Features} +*/ +int QXmlAttributes::index(const QString& uri, const QString& localPart) const +{ + for (int i = 0; i < attList.size(); ++i) { + const Attribute &att = attList.at(i); + if (att.uri == uri && att.localname == localPart) + return i; + } + return -1; +} + +/*! + Returns the number of attributes in the list. + + \sa count() +*/ +int QXmlAttributes::length() const +{ + return attList.count(); +} + +/*! + \fn int QXmlAttributes::count() const + + Returns the number of attributes in the list. This function is + equivalent to length(). +*/ + +/*! + Looks up an attribute's local name for the attribute at position + \a index. If no namespace processing is done, the local name is + an empty string. + + \sa {Namespace Support via Features} +*/ +QString QXmlAttributes::localName(int index) const +{ + return attList.at(index).localname; +} + +/*! + Looks up an attribute's XML 1.0 qualified name for the attribute + at position \a index. + + \sa {Namespace Support via Features} +*/ +QString QXmlAttributes::qName(int index) const +{ + return attList.at(index).qname; +} + +/*! + Looks up an attribute's namespace URI for the attribute at + position \a index. If no namespace processing is done or if the + attribute has no namespace, the namespace URI is an empty string. + + \sa {Namespace Support via Features} +*/ +QString QXmlAttributes::uri(int index) const +{ + return attList.at(index).uri; +} + +/*! + Looks up an attribute's type for the attribute at position \a + index. + + Currently only "CDATA" is returned. +*/ +QString QXmlAttributes::type(int) const +{ + return QLatin1String("CDATA"); +} + +/*! + \overload + + Looks up an attribute's type for the qualified name \a qName. + + Currently only "CDATA" is returned. +*/ +QString QXmlAttributes::type(const QString&) const +{ + return QLatin1String("CDATA"); +} + +/*! + \overload + + Looks up an attribute's type by namespace name. + + \a uri specifies the namespace URI and \a localName specifies the + local name. If the name has no namespace URI, use an empty string + for \a uri. + + Currently only "CDATA" is returned. +*/ +QString QXmlAttributes::type(const QString&, const QString&) const +{ + return QLatin1String("CDATA"); +} + +/*! + Returns an attribute's value for the attribute at position \a + index. The index must be a valid position + (i.e., 0 <= \a index < count()). +*/ +QString QXmlAttributes::value(int index) const +{ + return attList.at(index).value; +} + +/*! + \overload + + Returns an attribute's value for the qualified name \a qName, or an + empty string if no attribute exists for the name given. + + \sa {Namespace Support via Features} +*/ +QString QXmlAttributes::value(const QString& qName) const +{ + int i = index(qName); + if (i == -1) + return QString(); + return attList.at(i).value; +} + +/*! + \overload + + Returns an attribute's value for the qualified name \a qName, or an + empty string if no attribute exists for the name given. + + \sa {Namespace Support via Features} +*/ +QString QXmlAttributes::value(const QLatin1String& qName) const +{ + int i = index(qName); + if (i == -1) + return QString(); + return attList.at(i).value; +} + +/*! + \overload + + Returns an attribute's value by namespace name. + + \a uri specifies the namespace URI, or an empty string if the name + has no namespace URI. \a localName specifies the attribute's local + name. +*/ +QString QXmlAttributes::value(const QString& uri, const QString& localName) const +{ + int i = index(uri, localName); + if (i == -1) + return QString(); + return attList.at(i).value; +} + +/*! + Clears the list of attributes. + + \sa append() +*/ +void QXmlAttributes::clear() +{ + attList.clear(); +} + +/*! + Appends a new attribute entry to the list of attributes. The + qualified name of the attribute is \a qName, the namespace URI is + \a uri and the local name is \a localPart. The value of the + attribute is \a value. + + \sa qName() uri() localName() value() +*/ +void QXmlAttributes::append(const QString &qName, const QString &uri, const QString &localPart, const QString &value) +{ + Attribute att; + att.qname = qName; + att.uri = uri; + att.localname = localPart; + att.value = value; + + attList.append(att); +} + + +/********************************************* + * + * QXmlInputSource + * + *********************************************/ + +/*! + \class QXmlInputSource + \reentrant + \brief The QXmlInputSource class provides the input data for the + QXmlReader subclasses. + + \inmodule QtXml + \ingroup xml-tools + + All subclasses of QXmlReader read the input XML document from this + class. + + This class recognizes the encoding of the data by reading the + encoding declaration in the XML file if it finds one, and reading + the data using the corresponding encoding. If it does not find an + encoding declaration, then it assumes that the data is either in + UTF-8 or UTF-16, depending on whether it can find a byte-order + mark. + + There are two ways to populate the input source with data: you can + construct it with a QIODevice* so that the input source reads the + data from that device. Or you can set the data explicitly with one + of the setData() functions. + + Usually you either construct a QXmlInputSource that works on a + QIODevice* or you construct an empty QXmlInputSource and set the + data with setData(). There are only rare occasions where you would + want to mix both methods. + + The QXmlReader subclasses use the next() function to read the + input character by character. If you want to start from the + beginning again, use reset(). + + The functions data() and fetchData() are useful if you want to do + something with the data other than parsing, e.g. displaying the + raw XML file. The benefit of using the QXmlInputClass in such + cases is that it tries to use the correct encoding. + + \sa QXmlReader QXmlSimpleReader +*/ + +// the following two are guaranteed not to be a character +const ushort QXmlInputSource::EndOfData = 0xfffe; +const ushort QXmlInputSource::EndOfDocument = 0xffff; + +/* + Common part of the constructors. +*/ +void QXmlInputSource::init() +{ + d = new QXmlInputSourcePrivate; + + d->inputDevice = 0; + d->inputStream = 0; + + setData(QString()); +#ifndef QT_NO_TEXTCODEC + d->encMapper = 0; +#endif + d->nextReturnedEndOfData = true; // first call to next() will call fetchData() + + d->encodingDeclBytes.clear(); + d->encodingDeclChars.clear(); + d->lookingForEncodingDecl = true; +} + +/*! + Constructs an input source which contains no data. + + \sa setData() +*/ +QXmlInputSource::QXmlInputSource() +{ + init(); +} + +/*! + Constructs an input source and gets the data from device \a dev. + If \a dev is not open, it is opened in read-only mode. If \a dev + is 0 or it is not possible to read from the device, the input + source will contain no data. + + \sa setData() fetchData() QIODevice +*/ +QXmlInputSource::QXmlInputSource(QIODevice *dev) +{ + init(); + d->inputDevice = dev; + d->inputDevice->setTextModeEnabled(false); +} + +#ifdef QT3_SUPPORT +/*! + Use the QXmlInputSource(QIODevice *) constructor instead, with + the device used by \a stream. + + \sa QTextStream::device() +*/ +QXmlInputSource::QXmlInputSource(QTextStream& stream) +{ + init(); + d->inputStream = &stream; +} + +/*! + Use QXmlInputSource(&\a file) instead. +*/ +QXmlInputSource::QXmlInputSource(QFile& file) +{ + init(); + d->inputDevice = &file; +} +#endif + +/*! + Destructor. +*/ +QXmlInputSource::~QXmlInputSource() +{ + // ### Qt 5: close the input device. See task 153111 +#ifndef QT_NO_TEXTCODEC + delete d->encMapper; +#endif + delete d; +} + +/*! +Returns the next character of the input source. If this function +reaches the end of available data, it returns +QXmlInputSource::EndOfData. If you call next() after that, it +tries to fetch more data by calling fetchData(). If the +fetchData() call results in new data, this function returns the +first character of that data; otherwise it returns +QXmlInputSource::EndOfDocument. + +Readers, such as QXmlSimpleReader, will assume that the end of +the XML document has been reached if the this function returns +QXmlInputSource::EndOfDocument, and will check that the +supplied input is well-formed. Therefore, when reimplementing +this function, it is important to ensure that this behavior is +duplicated. + +\sa reset() fetchData() QXmlSimpleReader::parse() QXmlSimpleReader::parseContinue() +*/ +QChar QXmlInputSource::next() +{ + if (d->pos >= d->length) { + if (d->nextReturnedEndOfData) { + d->nextReturnedEndOfData = false; + fetchData(); + if (d->pos >= d->length) { + return EndOfDocument; + } + return next(); + } + d->nextReturnedEndOfData = true; + return EndOfData; + } + + // QXmlInputSource has no way to signal encoding errors. The best we can do + // is return EndOfDocument. We do *not* return EndOfData, because the reader + // will then just call this function again to get the next char. + QChar c = d->unicode[d->pos++]; + if (c.unicode() == EndOfData) + c = EndOfDocument; + return c; +} + +/*! + This function sets the position used by next() to the beginning of + the data returned by data(). This is useful if you want to use the + input source for more than one parse. + + \note In the case that the underlying data source is a QIODevice, + the current position in the device is not automatically set to the + start of input. Call QIODevice::seek(0) on the device to do this. + + \sa next() +*/ +void QXmlInputSource::reset() +{ + d->nextReturnedEndOfData = false; + d->pos = 0; +} + +/*! + Returns the data the input source contains or an empty string if the + input source does not contain any data. + + \sa setData() QXmlInputSource() fetchData() +*/ +QString QXmlInputSource::data() const +{ + if (d->nextReturnedEndOfData) { + QXmlInputSource *that = const_cast<QXmlInputSource*>(this); + that->d->nextReturnedEndOfData = false; + that->fetchData(); + } + return d->str; +} + +/*! + Sets the data of the input source to \a dat. + + If the input source already contains data, this function deletes + that data first. + + \sa data() +*/ +void QXmlInputSource::setData(const QString& dat) +{ + d->str = dat; + d->unicode = dat.unicode(); + d->pos = 0; + d->length = d->str.length(); + d->nextReturnedEndOfData = false; +} + +/*! + \overload + + The data \a dat is passed through the correct text-codec, before + it is set. +*/ +void QXmlInputSource::setData(const QByteArray& dat) +{ + setData(fromRawData(dat)); +} + +/*! + This function reads more data from the device that was set during + construction. If the input source already contained data, this + function deletes that data first. + + This object contains no data after a call to this function if the + object was constructed without a device to read data from or if + this function was not able to get more data from the device. + + There are two occasions where a fetch is done implicitly by + another function call: during construction (so that the object + starts out with some initial data where available), and during a + call to next() (if the data had run out). + + You don't normally need to use this function if you use next(). + + \sa data() next() QXmlInputSource() +*/ + +void QXmlInputSource::fetchData() +{ + enum + { + BufferSize = 1024 + }; + + QByteArray rawData; + + if (d->inputDevice || d->inputStream) { + QIODevice *device = d->inputDevice ? d->inputDevice : d->inputStream->device(); + + if (!device) { + if (d->inputStream && d->inputStream->string()) { + QString *s = d->inputStream->string(); + rawData = QByteArray((const char *) s->constData(), s->size() * sizeof(QChar)); + } + } else if (device->isOpen() || device->open(QIODevice::ReadOnly)) { + rawData.resize(BufferSize); + qint64 size = device->read(rawData.data(), BufferSize); + + if (size != -1) { + // We don't want to give fromRawData() less than four bytes if we can avoid it. + while (size < 4) { + if (!device->waitForReadyRead(-1)) + break; + int ret = device->read(rawData.data() + size, BufferSize - size); + if (ret <= 0) + break; + size += ret; + } + } + + rawData.resize(qMax(qint64(0), size)); + } + + /* We do this inside the "if (d->inputDevice ..." scope + * because if we're not using a stream or device, that is, + * the user set a QString manually, we don't want to set + * d->str. */ + setData(fromRawData(rawData)); + } +} + +#ifndef QT_NO_TEXTCODEC +static QString extractEncodingDecl(const QString &text, bool *needMoreText) +{ + *needMoreText = false; + + int l = text.length(); + QString snip = QString::fromLatin1("<?xml").left(l); + if (l > 0 && !text.startsWith(snip)) + return QString(); + + int endPos = text.indexOf(QLatin1Char('>')); + if (endPos == -1) { + *needMoreText = l < 255; // we won't look forever + return QString(); + } + + int pos = text.indexOf(QLatin1String("encoding")); + if (pos == -1 || pos >= endPos) + return QString(); + + while (pos < endPos) { + ushort uc = text.at(pos).unicode(); + if (uc == '\'' || uc == '"') + break; + ++pos; + } + + if (pos == endPos) + return QString(); + + QString encoding; + ++pos; + while (pos < endPos) { + ushort uc = text.at(pos).unicode(); + if (uc == '\'' || uc == '"') + break; + encoding.append(uc); + ++pos; + } + + return encoding; +} +#endif // QT_NO_TEXTCODEC + +/*! + This function reads the XML file from \a data and tries to + recognize the encoding. It converts the raw data \a data into a + QString and returns it. It tries its best to get the correct + encoding for the XML file. + + If \a beginning is true, this function assumes that the data + starts at the beginning of a new XML document and looks for an + encoding declaration. If \a beginning is false, it converts the + raw data using the encoding determined from prior calls. +*/ +QString QXmlInputSource::fromRawData(const QByteArray &data, bool beginning) +{ +#ifdef QT_NO_TEXTCODEC + Q_UNUSED(beginning); + return QString::fromAscii(data.constData(), data.size()); +#else + if (data.size() == 0) + return QString(); + if (beginning) { + delete d->encMapper; + d->encMapper = 0; + } + + int mib = 106; // UTF-8 + + // This is the initial UTF codec we will read the encoding declaration with + if (d->encMapper == 0) { + d->encodingDeclBytes.clear(); + d->encodingDeclChars.clear(); + d->lookingForEncodingDecl = true; + + // look for byte order mark and read the first 5 characters + if (data.size() >= 4) { + uchar ch1 = data.at(0); + uchar ch2 = data.at(1); + uchar ch3 = data.at(2); + uchar ch4 = data.at(3); + + if ((ch1 == 0 && ch2 == 0 && ch3 == 0xfe && ch4 == 0xff) || + (ch1 == 0xff && ch2 == 0xfe && ch3 == 0 && ch4 == 0)) + mib = 1017; // UTF-32 with byte order mark + else if (ch1 == 0x3c && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x00) + mib = 1019; // UTF-32LE + else if (ch1 == 0x00 && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x3c) + mib = 1018; // UTF-32BE + } + if (mib == 106 && data.size() >= 2) { + uchar ch1 = data.at(0); + uchar ch2 = data.at(1); + + if ((ch1 == 0xfe && ch2 == 0xff) || (ch1 == 0xff && ch2 == 0xfe)) + mib = 1015; // UTF-16 with byte order mark + else if (ch1 == 0x3c && ch2 == 0x00) + mib = 1014; // UTF-16LE + else if (ch1 == 0x00 && ch2 == 0x3c) + mib = 1013; // UTF-16BE + } + + QTextCodec *codec = QTextCodec::codecForMib(mib); + Q_ASSERT(codec); + + d->encMapper = codec->makeDecoder(); + } + + QString input = d->encMapper->toUnicode(data, data.size()); + + if (d->lookingForEncodingDecl) { + d->encodingDeclChars += input; + + bool needMoreText; + QString encoding = extractEncodingDecl(d->encodingDeclChars, &needMoreText); + + if (!encoding.isEmpty()) { + if (QTextCodec *codec = QTextCodec::codecForName(encoding.toLatin1())) { + /* If the encoding is the same, we don't have to do toUnicode() all over again. */ + if(codec->mibEnum() != mib) { + delete d->encMapper; + d->encMapper = codec->makeDecoder(); + + /* The variable input can potentially be large, so we deallocate + * it before calling toUnicode() in order to avoid having two + * large QStrings in memory simultaneously. */ + input.clear(); + + // prime the decoder with the data so far + d->encMapper->toUnicode(d->encodingDeclBytes, d->encodingDeclBytes.size()); + // now feed it the new data + input = d->encMapper->toUnicode(data, data.size()); + } + } + } + + d->encodingDeclBytes += data; + d->lookingForEncodingDecl = needMoreText; + } + + return input; +#endif +} + + +/********************************************* + * + * QXmlDefaultHandler + * + *********************************************/ + +/*! + \class QXmlContentHandler + \reentrant + \brief The QXmlContentHandler class provides an interface to + report the logical content of XML data. + + \inmodule QtXml + \ingroup xml-tools + + If the application needs to be informed of basic parsing events, + it can implement this interface and activate it using + QXmlReader::setContentHandler(). The reader can then report basic + document-related events like the start and end of elements and + character data through this interface. + + The order of events in this interface is very important, and + mirrors the order of information in the document itself. For + example, all of an element's content (character data, processing + instructions, and sub-elements) appears, in order, between the + startElement() event and the corresponding endElement() event. + + The class QXmlDefaultHandler provides a default implementation for + this interface; subclassing from the QXmlDefaultHandler class is + very convenient if you only want to be informed of some parsing + events. + + The startDocument() function is called at the start of the + document, and endDocument() is called at the end. Before parsing + begins setDocumentLocator() is called. For each element + startElement() is called, with endElement() being called at the + end of each element. The characters() function is called with + chunks of character data; ignorableWhitespace() is called with + chunks of whitespace and processingInstruction() is called with + processing instructions. If an entity is skipped skippedEntity() + is called. At the beginning of prefix-URI scopes + startPrefixMapping() is called. + + \sa QXmlDTDHandler, QXmlDeclHandler, QXmlEntityResolver, QXmlErrorHandler, + QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlContentHandler::~QXmlContentHandler() + + Destroys the content handler. +*/ + +/*! + \fn void QXmlContentHandler::setDocumentLocator(QXmlLocator* locator) + + The reader calls this function before it starts parsing the + document. The argument \a locator is a pointer to a QXmlLocator + which allows the application to get the parsing position within + the document. + + Do not destroy the \a locator; it is destroyed when the reader is + destroyed. (Do not use the \a locator after the reader is + destroyed). +*/ + +/*! + \fn bool QXmlContentHandler::startDocument() + + The reader calls this function when it starts parsing the + document. The reader calls this function just once, after the call + to setDocumentLocator(), and before any other functions in this + class or in the QXmlDTDHandler class are called. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endDocument() +*/ + +/*! + \fn bool QXmlContentHandler::endDocument() + + The reader calls this function after it has finished parsing. It + is called just once, and is the last handler function called. It + is called after the reader has read all input or has abandoned + parsing because of a fatal error. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa startDocument() +*/ + +/*! + \fn bool QXmlContentHandler::startPrefixMapping(const QString& prefix, const QString& uri) + + The reader calls this function to signal the begin of a prefix-URI + namespace mapping scope. This information is not necessary for + normal namespace processing since the reader automatically + replaces prefixes for element and attribute names. + + Note that startPrefixMapping() and endPrefixMapping() calls are + not guaranteed to be properly nested relative to each other: all + startPrefixMapping() events occur before the corresponding + startElement() event, and all endPrefixMapping() events occur + after the corresponding endElement() event, but their order is not + otherwise guaranteed. + + The argument \a prefix is the namespace prefix being declared and + the argument \a uri is the namespace URI the prefix is mapped to. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endPrefixMapping(), {Namespace Support via Features} +*/ + +/*! + \fn bool QXmlContentHandler::endPrefixMapping(const QString& prefix) + + The reader calls this function to signal the end of a prefix + mapping for the prefix \a prefix. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa startPrefixMapping(), {Namespace Support via Features} +*/ + +/*! + \fn bool QXmlContentHandler::startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts) + + The reader calls this function when it has parsed a start element + tag. + + There is a corresponding endElement() call when the corresponding + end element tag is read. The startElement() and endElement() calls + are always nested correctly. Empty element tags (e.g. \c{<x/>}) + cause a startElement() call to be immediately followed by an + endElement() call. + + The attribute list provided only contains attributes with explicit + values. The attribute list contains attributes used for namespace + declaration (i.e. attributes starting with xmlns) only if the + namespace-prefix property of the reader is true. + + The argument \a namespaceURI is the namespace URI, or + an empty string if the element has no namespace URI or if no + namespace processing is done. \a localName is the local name + (without prefix), or an empty string if no namespace processing is + done, \a qName is the qualified name (with prefix) and \a atts are + the attributes attached to the element. If there are no + attributes, \a atts is an empty attributes object. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endElement(), {Namespace Support via Features} +*/ + +/*! + \fn bool QXmlContentHandler::endElement(const QString& namespaceURI, const QString& localName, const QString& qName) + + The reader calls this function when it has parsed an end element + tag with the qualified name \a qName, the local name \a localName + and the namespace URI \a namespaceURI. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa startElement(), {Namespace Support via Features} +*/ + +/*! + \fn bool QXmlContentHandler::characters(const QString& ch) + + The reader calls this function when it has parsed a chunk of + character data (either normal character data or character data + inside a CDATA section; if you need to distinguish between those + two types you must use QXmlLexicalHandler::startCDATA() and + QXmlLexicalHandler::endCDATA()). The character data is reported in + \a ch. + + Some readers report whitespace in element content using the + ignorableWhitespace() function rather than using this one. + + A reader may report the character data of an element in more than + one chunk; e.g. a reader might want to report "a\<b" in three + characters() events ("a ", "\<" and " b"). + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlContentHandler::ignorableWhitespace(const QString& ch) + + Some readers may use this function to report each chunk of + whitespace in element content. The whitespace is reported in \a ch. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlContentHandler::processingInstruction(const QString& target, const QString& data) + + The reader calls this function when it has parsed a processing + instruction. + + \a target is the target name of the processing instruction and \a + data is the data in the processing instruction. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlContentHandler::skippedEntity(const QString& name) + + Some readers may skip entities if they have not seen the + declarations (e.g. because they are in an external DTD). If they + do so they report that they skipped the entity called \a name by + calling this function. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn QString QXmlContentHandler::errorString() const + + The reader calls this function to get an error string, e.g. if any + of the handler functions returns false. +*/ + + +/*! + \class QXmlErrorHandler + \reentrant + \brief The QXmlErrorHandler class provides an interface to report + errors in XML data. + + \inmodule QtXml + \ingroup xml-tools + + If you want your application to report errors to the user or to + perform customized error handling, you should subclass this class. + + You can set the error handler with QXmlReader::setErrorHandler(). + + Errors can be reported using warning(), error() and fatalError(), + with the error text being reported with errorString(). + + \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, + QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlErrorHandler::~QXmlErrorHandler() + + Destroys the error handler. +*/ + +/*! + \fn bool QXmlErrorHandler::warning(const QXmlParseException& exception) + + A reader might use this function to report a warning. Warnings are + conditions that are not errors or fatal errors as defined by the + XML 1.0 specification. Details of the warning are stored in \a + exception. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlErrorHandler::error(const QXmlParseException& exception) + + A reader might use this function to report a recoverable error. A + recoverable error corresponds to the definiton of "error" in + section 1.2 of the XML 1.0 specification. Details of the error are + stored in \a exception. + + The reader must continue to provide normal parsing events after + invoking this function. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! +\fn bool QXmlErrorHandler::fatalError(const QXmlParseException& exception) + +A reader must use this function to report a non-recoverable error. +Details of the error are stored in \a exception. + +If this function returns true the reader might try to go on +parsing and reporting further errors, but no regular parsing +events are reported. +*/ + +/*! + \fn QString QXmlErrorHandler::errorString() const + + The reader calls this function to get an error string if any of + the handler functions returns false. +*/ + + +/*! + \class QXmlDTDHandler + \reentrant + \brief The QXmlDTDHandler class provides an interface to report + DTD content of XML data. + + \inmodule QtXml + \ingroup xml-tools + + If an application needs information about notations and unparsed + entities, it can implement this interface and register an instance + with QXmlReader::setDTDHandler(). + + Note that this interface includes only those DTD events that the + XML recommendation requires processors to report, i.e. notation + and unparsed entity declarations using notationDecl() and + unparsedEntityDecl() respectively. + + \sa QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler, + QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlDTDHandler::~QXmlDTDHandler() + + Destroys the DTD handler. +*/ + +/*! + \fn bool QXmlDTDHandler::notationDecl(const QString& name, const QString& publicId, const QString& systemId) + + The reader calls this function when it has parsed a notation + declaration. + + The argument \a name is the notation name, \a publicId is the + notation's public identifier and \a systemId is the notation's + system identifier. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlDTDHandler::unparsedEntityDecl(const QString& name, const QString& publicId, const QString& systemId, const QString& notationName) + + The reader calls this function when it finds an unparsed entity + declaration. + + The argument \a name is the unparsed entity's name, \a publicId is + the entity's public identifier, \a systemId is the entity's system + identifier and \a notationName is the name of the associated + notation. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn QString QXmlDTDHandler::errorString() const + + The reader calls this function to get an error string if any of + the handler functions returns false. +*/ + + +/*! + \class QXmlEntityResolver + \reentrant + \brief The QXmlEntityResolver class provides an interface to + resolve external entities contained in XML data. + + \inmodule QtXml + \ingroup xml-tools + + If an application needs to implement customized handling for + external entities, it must implement this interface, i.e. + resolveEntity(), and register it with + QXmlReader::setEntityResolver(). + + \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlErrorHandler, + QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlEntityResolver::~QXmlEntityResolver() + + Destroys the entity resolver. +*/ + +/*! + \fn bool QXmlEntityResolver::resolveEntity(const QString& publicId, const QString& systemId, QXmlInputSource*& ret) + + The reader calls this function before it opens any external + entity, except the top-level document entity. The application may + request the reader to resolve the entity itself (\a ret is 0) or + to use an entirely different input source (\a ret points to the + input source). + + The reader deletes the input source \a ret when it no longer needs + it, so you should allocate it on the heap with \c new. + + The argument \a publicId is the public identifier of the external + entity, \a systemId is the system identifier of the external + entity and \a ret is the return value of this function. If \a ret + is 0 the reader should resolve the entity itself, if it is + non-zero it must point to an input source which the reader uses + instead. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn QString QXmlEntityResolver::errorString() const + + The reader calls this function to get an error string if any of + the handler functions returns false. +*/ + + +/*! + \class QXmlLexicalHandler + \reentrant + \brief The QXmlLexicalHandler class provides an interface to + report the lexical content of XML data. + + \inmodule QtXml + \ingroup xml-tools + + The events in the lexical handler apply to the entire document, + not just to the document element, and all lexical handler events + appear between the content handler's startDocument and endDocument + events. + + You can set the lexical handler with + QXmlReader::setLexicalHandler(). + + This interface's design is based on the the SAX2 extension + LexicalHandler. + + The interface provides the startDTD(), endDTD(), startEntity(), + endEntity(), startCDATA(), endCDATA() and comment() functions. + + \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, + QXmlErrorHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlLexicalHandler::~QXmlLexicalHandler() + + Destroys the lexical handler. +*/ + +/*! + \fn bool QXmlLexicalHandler::startDTD(const QString& name, const QString& publicId, const QString& systemId) + + The reader calls this function to report the start of a DTD + declaration, if any. It reports the name of the document type in + \a name, the public identifier in \a publicId and the system + identifier in \a systemId. + + If the public identifier is missing, \a publicId is set to + an empty string. If the system identifier is missing, \a systemId is + set to an empty string. Note that it is not valid XML to have a + public identifier but no system identifier; in such cases a parse + error will occur. + + All declarations reported through QXmlDTDHandler or + QXmlDeclHandler appear between the startDTD() and endDTD() calls. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endDTD() +*/ + +/*! + \fn bool QXmlLexicalHandler::endDTD() + + The reader calls this function to report the end of a DTD + declaration, if any. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa startDTD() +*/ + +/*! + \fn bool QXmlLexicalHandler::startEntity(const QString& name) + + The reader calls this function to report the start of an entity + called \a name. + + Note that if the entity is unknown, the reader reports it through + QXmlContentHandler::skippedEntity() and not through this + function. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endEntity(), QXmlSimpleReader::setFeature() +*/ + +/*! + \fn bool QXmlLexicalHandler::endEntity(const QString& name) + + The reader calls this function to report the end of an entity + called \a name. + + For every startEntity() call, there is a corresponding endEntity() + call. The calls to startEntity() and endEntity() are properly + nested. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa startEntity(), QXmlContentHandler::skippedEntity(), QXmlSimpleReader::setFeature() +*/ + +/*! + \fn bool QXmlLexicalHandler::startCDATA() + + The reader calls this function to report the start of a CDATA + section. The content of the CDATA section is reported through the + QXmlContentHandler::characters() function. This function is + intended only to report the boundary. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. + + \sa endCDATA() +*/ + +/*! + \fn bool QXmlLexicalHandler::endCDATA() + + The reader calls this function to report the end of a CDATA + section. + + If this function returns false the reader stops parsing and reports + an error. The reader uses the function errorString() to get the error + message. + + \sa startCDATA(), QXmlContentHandler::characters() +*/ + +/*! + \fn bool QXmlLexicalHandler::comment(const QString& ch) + + The reader calls this function to report an XML comment anywhere + in the document. It reports the text of the comment in \a ch. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn QString QXmlLexicalHandler::errorString() const + + The reader calls this function to get an error string if any of + the handler functions returns false. +*/ + + +/*! + \class QXmlDeclHandler + \reentrant + \brief The QXmlDeclHandler class provides an interface to report declaration + content of XML data. + + \inmodule QtXml + \ingroup xml-tools + + You can set the declaration handler with + QXmlReader::setDeclHandler(). + + This interface is based on the SAX2 extension DeclHandler. + + The interface provides attributeDecl(), internalEntityDecl() and + externalEntityDecl() functions. + + \sa QXmlDTDHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler, + QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlDeclHandler::~QXmlDeclHandler() + + Destroys the declaration handler. +*/ + +/*! + \fn bool QXmlDeclHandler::attributeDecl(const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value) + + The reader calls this function to report an attribute type + declaration. Only the effective (first) declaration for an + attribute is reported. + + The reader passes the name of the associated element in \a eName + and the name of the attribute in \a aName. It passes a string that + represents the attribute type in \a type and a string that + represents the attribute default in \a valueDefault. This string + is one of "#IMPLIED", "#REQUIRED", "#FIXED" or an empty string (if + none of the others applies). The reader passes the attribute's + default value in \a value. If no default value is specified in the + XML file, \a value is an empty string. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlDeclHandler::internalEntityDecl(const QString& name, const QString& value) + + The reader calls this function to report an internal entity + declaration. Only the effective (first) declaration is reported. + + The reader passes the name of the entity in \a name and the value + of the entity in \a value. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn bool QXmlDeclHandler::externalEntityDecl(const QString& name, const QString& publicId, const QString& systemId) + + The reader calls this function to report a parsed external entity + declaration. Only the effective (first) declaration for each + entity is reported. + + The reader passes the name of the entity in \a name, the public + identifier in \a publicId and the system identifier in \a + systemId. If there is no public identifier specified, it passes + an empty string in \a publicId. + + If this function returns false the reader stops parsing and + reports an error. The reader uses the function errorString() to + get the error message. +*/ + +/*! + \fn QString QXmlDeclHandler::errorString() const + + The reader calls this function to get an error string if any of + the handler functions returns false. +*/ + + +/*! + \class QXmlDefaultHandler + \reentrant + \brief The QXmlDefaultHandler class provides a default implementation of all + the XML handler classes. + + \inmodule QtXml + \ingroup xml-tools + + This class gathers together the features of + the specialized handler classes, making it a convenient + starting point when implementing custom handlers for + subclasses of QXmlReader, particularly QXmlSimpleReader. + The virtual functions from each of the base classes are + reimplemented in this class, providing sensible default behavior + for many common cases. By subclassing this class, and + overriding these functions, you can concentrate + on implementing the parts of the handler relevant to your + application. + + The XML reader must be told which handler to use for different + kinds of events during parsing. This means that, although + QXmlDefaultHandler provides default implementations of functions + inherited from all its base classes, we can still use specialized + handlers for particular kinds of events. + + For example, QXmlDefaultHandler subclasses both + QXmlContentHandler and QXmlErrorHandler, so by subclassing + it we can use the same handler for both of the following + reader functions: + + \snippet doc/src/snippets/xml/rsslisting/rsslisting.cpp 0 + + Since the reader will inform the handler of parsing errors, it is + necessary to reimplement QXmlErrorHandler::fatalError() if, for + example, we want to stop parsing when such an error occurs: + + \snippet doc/src/snippets/xml/rsslisting/handler.cpp 0 + + The above function returns false, which tells the reader to stop + parsing. To continue to use the same reader, + it is necessary to create a new handler instance, and set up the + reader to use it in the manner described above. + + It is useful to examine some of the functions inherited by + QXmlDefaultHandler, and consider why they might be + reimplemented in a custom handler. + Custom handlers will typically reimplement + QXmlContentHandler::startDocument() to prepare the handler for + new content. Document elements and the text within them can be + processed by reimplementing QXmlContentHandler::startElement(), + QXmlContentHandler::endElement(), and + QXmlContentHandler::characters(). + You may want to reimplement QXmlContentHandler::endDocument() + to perform some finalization or validation on the content once the + document has been read completely. + + \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, + QXmlErrorHandler, QXmlLexicalHandler, {Introduction to SAX2} +*/ + +/*! + \fn QXmlDefaultHandler::QXmlDefaultHandler() + + Constructs a handler for use with subclasses of QXmlReader. +*/ +/*! + \fn QXmlDefaultHandler::~QXmlDefaultHandler() + + Destroys the handler. +*/ + +/*! + \reimp + + Does nothing. +*/ +void QXmlDefaultHandler::setDocumentLocator(QXmlLocator*) +{ +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startDocument() +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endDocument() +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startPrefixMapping(const QString&, const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endPrefixMapping(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startElement(const QString&, const QString&, + const QString&, const QXmlAttributes&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endElement(const QString&, const QString&, + const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::characters(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::ignorableWhitespace(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::processingInstruction(const QString&, + const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::skippedEntity(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::warning(const QXmlParseException&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::error(const QXmlParseException&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::fatalError(const QXmlParseException&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::notationDecl(const QString&, const QString&, + const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::unparsedEntityDecl(const QString&, const QString&, + const QString&, const QString&) +{ + return true; +} + +/*! + \reimp + + Sets \a ret to 0, so that the reader uses the system identifier + provided in the XML document. +*/ +bool QXmlDefaultHandler::resolveEntity(const QString&, const QString&, + QXmlInputSource*& ret) +{ + ret = 0; + return true; +} + +/*! + \reimp + + Returns the default error string. +*/ +QString QXmlDefaultHandler::errorString() const +{ + return QString::fromLatin1(XMLERR_ERRORBYCONSUMER); +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startDTD(const QString&, const QString&, const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endDTD() +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startEntity(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endEntity(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::startCDATA() +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::endCDATA() +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::comment(const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::attributeDecl(const QString&, const QString&, const QString&, const QString&, const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::internalEntityDecl(const QString&, const QString&) +{ + return true; +} + +/*! + \reimp + + Does nothing. +*/ +bool QXmlDefaultHandler::externalEntityDecl(const QString&, const QString&, const QString&) +{ + return true; +} + + +/********************************************* + * + * QXmlSimpleReaderPrivate + * + *********************************************/ + +inline bool QXmlSimpleReaderPrivate::atEnd() +{ + return (c.unicode()|0x0001) == 0xffff; +} + +inline void QXmlSimpleReaderPrivate::stringClear() +{ + stringValueLen = 0; stringArrayPos = 0; +} +inline void QXmlSimpleReaderPrivate::nameClear() +{ + nameValueLen = 0; nameArrayPos = 0; +} + +inline void QXmlSimpleReaderPrivate::refClear() +{ + refValueLen = 0; refArrayPos = 0; +} + +QXmlSimpleReaderPrivate::QXmlSimpleReaderPrivate() +{ + parseStack = 0; +} + +QXmlSimpleReaderPrivate::~QXmlSimpleReaderPrivate() +{ + delete parseStack; +} + +void QXmlSimpleReaderPrivate::initIncrementalParsing() +{ + delete parseStack; + parseStack = new QStack<ParseState>; +} + +/********************************************* + * + * QXmlSimpleReader + * + *********************************************/ + +/*! + \class QXmlReader + \reentrant + \brief The QXmlReader class provides an interface for XML readers (i.e. + parsers). + + \inmodule QtXml + \ingroup xml-tools + + This abstract class provides an interface for all of Qt's XML + readers. Currently there is only one implementation of a reader + included in Qt's XML module: QXmlSimpleReader. In future releases + there might be more readers with different properties available + (e.g. a validating parser). + + The design of the XML classes follows the \link + http://www.saxproject.org/ SAX2 Java interface\endlink, with + the names adapted to fit Qt naming conventions. It should be very + easy for anybody who has worked with SAX2 to get started with the + Qt XML classes. + + All readers use the class QXmlInputSource to read the input + document. Since you are normally interested in particular content + in the XML document, the reader reports the content through + special handler classes (QXmlDTDHandler, QXmlDeclHandler, + QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler and + QXmlLexicalHandler), which you must subclass, if you want to + process the contents. + + Since the handler classes only describe interfaces you must + implement all the functions. We provide the QXmlDefaultHandler + class to make this easier: it implements a default behavior (do + nothing) for all functions, so you can subclass it and just + implement the functions you are interested in. + + Features and properties of the reader can be set with setFeature() + and setProperty() respectively. You can set the reader to use your + own subclasses with setEntityResolver(), setDTDHandler(), + setContentHandler(), setErrorHandler(), setLexicalHandler() and + setDeclHandler(). The parse itself is started with a call to + parse(). + + \sa QXmlSimpleReader +*/ + +/*! + \fn QXmlReader::~QXmlReader() + + Destroys the reader. +*/ + +/*! + \fn bool QXmlReader::feature(const QString& name, bool *ok) const + + If the reader has the feature called \a name, the feature's value + is returned. If no such feature exists the return value is + undefined. + + If \a ok is not 0: \c{*}\a{ok} is set to true if the reader has the + feature called \a name; otherwise \c{*}\a{ok} is set to false. + + \sa setFeature(), hasFeature() +*/ + +/*! + \fn void QXmlReader::setFeature(const QString& name, bool value) + + Sets the feature called \a name to the given \a value. If the + reader doesn't have the feature nothing happens. + + \sa feature(), hasFeature() +*/ + +/*! + \fn bool QXmlReader::hasFeature(const QString& name) const + + Returns \c true if the reader has the feature called \a name; + otherwise returns false. + + \sa feature(), setFeature() +*/ + +/*! + \fn void* QXmlReader::property(const QString& name, bool *ok) const + + If the reader has the property \a name, this function returns the + value of the property; otherwise the return value is undefined. + + If \a ok is not 0: if the reader has the \a name property + \c{*}\a{ok} is set to true; otherwise \c{*}\a{ok} is set to false. + + \sa setProperty(), hasProperty() +*/ + +/*! + \fn void QXmlReader::setProperty(const QString& name, void* value) + + Sets the property \a name to \a value. If the reader doesn't have + the property nothing happens. + + \sa property(), hasProperty() +*/ + +/*! + \fn bool QXmlReader::hasProperty(const QString& name) const + + Returns true if the reader has the property \a name; otherwise + returns false. + + \sa property(), setProperty() +*/ + +/*! + \fn void QXmlReader::setEntityResolver(QXmlEntityResolver* handler) + + Sets the entity resolver to \a handler. + + \sa entityResolver() +*/ + +/*! + \fn QXmlEntityResolver* QXmlReader::entityResolver() const + + Returns the entity resolver or 0 if none was set. + + \sa setEntityResolver() +*/ + +/*! + \fn void QXmlReader::setDTDHandler(QXmlDTDHandler* handler) + + Sets the DTD handler to \a handler. + + \sa DTDHandler() +*/ + +/*! + \fn QXmlDTDHandler* QXmlReader::DTDHandler() const + + Returns the DTD handler or 0 if none was set. + + \sa setDTDHandler() +*/ + +/*! + \fn void QXmlReader::setContentHandler(QXmlContentHandler* handler) + + Sets the content handler to \a handler. + + \sa contentHandler() +*/ + +/*! + \fn QXmlContentHandler* QXmlReader::contentHandler() const + + Returns the content handler or 0 if none was set. + + \sa setContentHandler() +*/ + +/*! + \fn void QXmlReader::setErrorHandler(QXmlErrorHandler* handler) + + Sets the error handler to \a handler. Clears the error handler if + \a handler is 0. + + \sa errorHandler() +*/ + +/*! + \fn QXmlErrorHandler* QXmlReader::errorHandler() const + + Returns the error handler or 0 if none is set. + + \sa setErrorHandler() +*/ + +/*! + \fn void QXmlReader::setLexicalHandler(QXmlLexicalHandler* handler) + + Sets the lexical handler to \a handler. + + \sa lexicalHandler() +*/ + +/*! + \fn QXmlLexicalHandler* QXmlReader::lexicalHandler() const + + Returns the lexical handler or 0 if none was set. + + \sa setLexicalHandler() +*/ + +/*! + \fn void QXmlReader::setDeclHandler(QXmlDeclHandler* handler) + + Sets the declaration handler to \a handler. + + \sa declHandler() +*/ + +/*! + \fn QXmlDeclHandler* QXmlReader::declHandler() const + + Returns the declaration handler or 0 if none was set. + + \sa setDeclHandler() +*/ + +/*! + \fn bool QXmlReader::parse(const QXmlInputSource &input) + + \obsolete + + Parses the given \a input. +*/ + +/*! + \fn bool QXmlReader::parse(const QXmlInputSource *input) + + Reads an XML document from \a input and parses it. Returns true if + the parsing was successful; otherwise returns false. +*/ + + +/*! + \class QXmlSimpleReader + \nonreentrant + \brief The QXmlSimpleReader class provides an implementation of a + simple XML parser. + + \inmodule QtXml + \ingroup xml-tools + \mainclass + + This XML reader is suitable for a wide range of applications. It + is able to parse well-formed XML and can report the namespaces of + elements to a content handler; however, it does not parse any + external entities. For historical reasons, Attribute Value + Normalization and End-of-Line Handling as described in the XML 1.0 + specification is not performed. + + The easiest pattern of use for this class is to create a reader + instance, define an input source, specify the handlers to be used + by the reader, and parse the data. + + For example, we could use a QFile to supply the input. Here, we + create a reader, and define an input source to be used by the + reader: + + \snippet doc/src/snippets/xml/simpleparse/main.cpp 0 + + A handler lets us perform actions when the reader encounters + certain types of content, or if errors in the input are found. The + reader must be told which handler to use for each type of + event. For many common applications, we can create a custom + handler by subclassing QXmlDefaultHandler, and use this to handle + both error and content events: + + \snippet doc/src/snippets/xml/simpleparse/main.cpp 1 + + If you don't set at least the content and error handlers, the + parser will fall back on its default behavior---and will do + nothing. + + The most convenient way to handle the input is to read it in a + single pass using the parse() function with an argument that + specifies the input source: + + \snippet doc/src/snippets/xml/simpleparse/main.cpp 2 + + If you can't parse the entire input in one go (for example, it is + huge, or is being delivered over a network connection), data can + be fed to the parser in pieces. This is achieved by telling + parse() to work incrementally, and making subsequent calls to the + parseContinue() function, until all the data has been processed. + + A common way to perform incremental parsing is to connect the + \c readyRead() signal of the input source to a slot, and handle the + incoming data there. For example, the following code shows how a + parser for \l{http://web.resource.org/rss/1.0/}{RSS feeds} can be + used to incrementally parse data that it receives from a QHttp + object: + + \snippet doc/src/snippets/xml/rsslisting/rsslisting.cpp 1 + + Aspects of the parsing behavior can be adapted using setFeature() + and setProperty(). For example, the following code could be used + to enable reporting of namespace prefixes to the content handler: + + QXmlSimpleReader is not reentrant. If you want to use the class + in threaded code, lock the code using QXmlSimpleReader with a + locking mechanism, such as a QMutex. + + \snippet doc/src/snippets/code/src_xml_sax_qxml.cpp 0 +*/ + +static inline bool is_S(QChar ch) +{ + ushort uc = ch.unicode(); + return (uc == ' ' || uc == '\t' || uc == '\n' || uc == '\r'); +} + +enum NameChar { NameBeginning, NameNotBeginning, NotName }; + +static const char Begi = (char)NameBeginning; +static const char NtBg = (char)NameNotBeginning; +static const char NotN = (char)NotName; + +static const char nameCharTable[128] = +{ +// 0x00 + NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN, + NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN, +// 0x10 + NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN, + NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN, +// 0x20 (0x2D is '-', 0x2E is '.') + NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN, + NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN, +// 0x30 (0x30..0x39 are '0'..'9', 0x3A is ':') + NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, + NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN, +// 0x40 (0x41..0x5A are 'A'..'Z') + NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi, + Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi, +// 0x50 (0x5F is '_') + Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi, + Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi, +// 0x60 (0x61..0x7A are 'a'..'z') + NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi, + Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi, +// 0x70 + Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi, + Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN +}; + +static inline NameChar fastDetermineNameChar(QChar ch) +{ + ushort uc = ch.unicode(); + if (!(uc & ~0x7f)) // uc < 128 + return (NameChar)nameCharTable[uc]; + + QChar::Category cat = ch.category(); + // ### some these categories might be slightly wrong + if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other) + || cat == QChar::Number_Letter) + return NameBeginning; + if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other) + || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing)) + return NameNotBeginning; + return NotName; +} + +static NameChar determineNameChar(QChar ch) +{ + return fastDetermineNameChar(ch); +} + +/*! + Constructs a simple XML reader. + +*/ +QXmlSimpleReader::QXmlSimpleReader() +{ + d_ptr = new QXmlSimpleReaderPrivate(); + Q_D(QXmlSimpleReader); + d->q_ptr = this; + + d->locator = new QXmlSimpleReaderLocator(this); + + d->entityRes = 0; + d->dtdHnd = 0; + d->contentHnd = 0; + d->errorHnd = 0; + d->lexicalHnd = 0; + d->declHnd = 0; + + // default feature settings + d->useNamespaces = true; + d->useNamespacePrefixes = false; + d->reportWhitespaceCharData = true; + d->reportEntities = false; +} + +/*! + Destroys the simple XML reader. +*/ +QXmlSimpleReader::~QXmlSimpleReader() +{ + Q_D(QXmlSimpleReader); + delete d->locator; + delete d; +} + +/*! + \reimp +*/ +bool QXmlSimpleReader::feature(const QString& name, bool *ok) const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + + // Qt5 ###: Change these strings to qtsoftware.com + if (ok != 0) + *ok = true; + if (name == QLatin1String("http://xml.org/sax/features/namespaces")) { + return d->useNamespaces; + } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) { + return d->useNamespacePrefixes; + } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData")) { // Shouldn't change in Qt 4 + return d->reportWhitespaceCharData; + } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity")) { // Shouldn't change in Qt 4 + return d->reportEntities; + } else { + qWarning("Unknown feature %s", name.toLatin1().data()); + if (ok != 0) + *ok = false; + } + return false; +} + +/*! + Turns on the feature \a name if \a enable is true; otherwise turns it off. + + The \a name parameter must be one of the following strings: + \table + \header \i Feature \i Default \i Notes + \row \i \e http://xml.org/sax/features/namespaces + \i true + \i If enabled, namespaces are reported to the content handler. + \row \i \e http://xml.org/sax/features/namespace-prefixes + \i false + \i If enabled, the original prefixed names + and attributes used for namespace declarations are + reported. + \row \i \e http://trolltech.com/xml/features/report-whitespace-only-CharData + \i true + \i If enabled, CharData that consist of + only whitespace characters are reported + using QXmlContentHandler::characters(). If disabled, whitespace is silently + discarded. + \row \i \e http://trolltech.com/xml/features/report-start-end-entity + \i false + \i If enabled, the parser reports + QXmlContentHandler::startEntity() and + QXmlContentHandler::endEntity() events, so character data + might be reported in chunks. + If disabled, the parser does not report these events, but + silently substitutes the entities, and reports the character + data in one chunk. + \endtable + + \sa feature(), hasFeature(), {SAX2 Features} +*/ +void QXmlSimpleReader::setFeature(const QString& name, bool enable) +{ + Q_D(QXmlSimpleReader); + // Qt5 ###: Change these strings to qtsoftware.com + if (name == QLatin1String("http://xml.org/sax/features/namespaces")) { + d->useNamespaces = enable; + } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) { + d->useNamespacePrefixes = enable; + } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData")) { // Shouldn't change in Qt 4 + d->reportWhitespaceCharData = enable; + } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity")) { // Shouldn't change in Qt 4 + d->reportEntities = enable; + } else { + qWarning("Unknown feature %s", name.toLatin1().data()); + } +} + +/*! \reimp +*/ +bool QXmlSimpleReader::hasFeature(const QString& name) const +{ + // Qt5 ###: Change these strings to qtsoftware.com + if (name == QLatin1String("http://xml.org/sax/features/namespaces") + || name == QLatin1String("http://xml.org/sax/features/namespace-prefixes") + || name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // Shouldn't change in Qt 4 + || name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity")) { // Shouldn't change in Qt 4 + return true; + } else { + return false; + } +} + +/*! \reimp +*/ +void* QXmlSimpleReader::property(const QString&, bool *ok) const +{ + if (ok != 0) + *ok = false; + return 0; +} + +/*! \reimp +*/ +void QXmlSimpleReader::setProperty(const QString&, void*) +{ +} + +/*! + \reimp +*/ +bool QXmlSimpleReader::hasProperty(const QString&) const +{ + return false; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setEntityResolver(QXmlEntityResolver* handler) +{ + Q_D(QXmlSimpleReader); + d->entityRes = handler; +} + +/*! + \reimp +*/ +QXmlEntityResolver* QXmlSimpleReader::entityResolver() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->entityRes; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setDTDHandler(QXmlDTDHandler* handler) +{ + Q_D(QXmlSimpleReader); + d->dtdHnd = handler; +} + +/*! + \reimp +*/ +QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->dtdHnd; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setContentHandler(QXmlContentHandler* handler) +{ + Q_D(QXmlSimpleReader); + d->contentHnd = handler; +} + +/*! + \reimp +*/ +QXmlContentHandler* QXmlSimpleReader::contentHandler() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->contentHnd; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setErrorHandler(QXmlErrorHandler* handler) +{ + Q_D(QXmlSimpleReader); + d->errorHnd = handler; +} + +/*! + \reimp +*/ +QXmlErrorHandler* QXmlSimpleReader::errorHandler() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->errorHnd; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setLexicalHandler(QXmlLexicalHandler* handler) +{ + Q_D(QXmlSimpleReader); + d->lexicalHnd = handler; +} + +/*! + \reimp +*/ +QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->lexicalHnd; +} + +/*! + \reimp +*/ +void QXmlSimpleReader::setDeclHandler(QXmlDeclHandler* handler) +{ + Q_D(QXmlSimpleReader); + d->declHnd = handler; +} + +/*! + \reimp +*/ +QXmlDeclHandler* QXmlSimpleReader::declHandler() const +{ + const QXmlSimpleReaderPrivate *d = d_func(); + return d->declHnd; +} + + + +/*! + \reimp +*/ +bool QXmlSimpleReader::parse(const QXmlInputSource& input) +{ + return parse(&input, false); +} + +/*! + Reads an XML document from \a input and parses it in one pass (non-incrementally). + Returns true if the parsing was successful; otherwise returns false. +*/ +bool QXmlSimpleReader::parse(const QXmlInputSource* input) +{ + return parse(input, false); +} + +/*! + Reads an XML document from \a input and parses it. Returns true + if the parsing is completed successfully; otherwise returns false, + indicating that an error occurred. + + If \a incremental is false, this function will return false if the XML + file is not read completely. The parsing cannot be continued in this + case. + + If \a incremental is true, the parser does not return false if + it reaches the end of the \a input before reaching the end + of the XML file. Instead, it stores the state of the parser so that + parsing can be continued later when more data is available. + In such a case, you can use the function parseContinue() to + continue with parsing. This class stores a pointer to the input + source \a input and the parseContinue() function tries to read from + that input source. Therefore, you should not delete the input + source \a input until you no longer need to call parseContinue(). + + If this function is called with \a incremental set to true + while an incremental parse is in progress, a new parsing + session will be started, and the previous session will be lost. + + \sa parseContinue(), QTcpSocket +*/ +bool QXmlSimpleReader::parse(const QXmlInputSource *input, bool incremental) +{ + Q_D(QXmlSimpleReader); + + if (incremental) { + d->initIncrementalParsing(); + } else { + delete d->parseStack; + d->parseStack = 0; + } + d->init(input); + + // call the handler + if (d->contentHnd) { + d->contentHnd->setDocumentLocator(d->locator); + if (!d->contentHnd->startDocument()) { + d->reportParseError(d->contentHnd->errorString()); + d->tags.clear(); + return false; + } + } + qt_xml_skipped_entity_in_content = false; + return d->parseBeginOrContinue(0, incremental); +} + +/*! + Continues incremental parsing, taking input from the + QXmlInputSource that was specified with the most recent + call to parse(). To use this function, you \e must have called + parse() with the incremental argument set to true. + + Returns false if a parsing error occurs; otherwise returns true, + even if the end of the XML file has not been reached. You can + continue parsing at a later stage by calling this function again + when there is more data available to parse. + + Calling this function when there is no data available in the input + source indicates to the reader that the end of the XML file has + been reached. If the input supplied up to this point was + not well-formed then a parsing error occurs, and false is returned. + If the input supplied was well-formed, true is returned. + It is important to end the input in this way because it allows you + to reuse the reader to parse other XML files. + + Calling this function after the end of file has been reached, but + without available data will cause false to be returned whether the + previous input was well-formed or not. + + \sa parse(), QXmlInputSource::data(), QXmlInputSource::next() +*/ +bool QXmlSimpleReader::parseContinue() +{ + Q_D(QXmlSimpleReader); + if (d->parseStack == 0 || d->parseStack->isEmpty()) + return false; + d->initData(); + int state = d->parseStack->pop().state; + return d->parseBeginOrContinue(state, true); +} + +/* + Common part of parse() and parseContinue() +*/ +bool QXmlSimpleReaderPrivate::parseBeginOrContinue(int state, bool incremental) +{ + bool atEndOrig = atEnd(); + + if (state==0) { + if (!parseProlog()) { + if (incremental && error.isNull()) { + pushParseState(0, 0); + return true; + } else { + tags.clear(); + return false; + } + } + state = 1; + } + if (state==1) { + if (!parseElement()) { + if (incremental && error.isNull()) { + pushParseState(0, 1); + return true; + } else { + tags.clear(); + return false; + } + } + state = 2; + } + // parse Misc* + while (!atEnd()) { + if (!parseMisc()) { + if (incremental && error.isNull()) { + pushParseState(0, 2); + return true; + } else { + tags.clear(); + return false; + } + } + } + if (!atEndOrig && incremental) { + // we parsed something at all, so be prepared to come back later + pushParseState(0, 2); + return true; + } + // is stack empty? + if (!tags.isEmpty() && !error.isNull()) { + reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF)); + tags.clear(); + return false; + } + // call the handler + if (contentHnd) { + delete parseStack; + parseStack = 0; + if (!contentHnd->endDocument()) { + reportParseError(contentHnd->errorString()); + return false; + } + } + return true; +} + +// +// The following private parse functions have another semantics for the return +// value: They return true iff parsing has finished successfully (i.e. the end +// of the XML file must be reached!). If one of these functions return false, +// there is only an error when d->error.isNULL() is also false. +// + +/* + For the incremental parsing, it is very important that the parse...() + functions have a certain structure. Since it might be hard to understand how + they work, here is a description of the layout of these functions: + + bool QXmlSimpleReader::parse...() + { +(1) const signed char Init = 0; + ... + +(2) const signed char Inp... = 0; + ... + +(3) static const signed char table[3][2] = { + ... + }; + signed char state; + signed char input; + +(4) if (d->parseStack == 0 || d->parseStack->isEmpty()) { +(4a) ... + } else { +(4b) ... + } + + for (; ;) { +(5) switch (state) { + ... + } + +(6) +(6a) if (atEnd()) { + unexpectedEof(&QXmlSimpleReader::parseNmtoken, state); + return false; + } +(6b) if (determineNameChar(c) != NotName) { + ... + } +(7) state = table[state][input]; + +(8) switch (state) { + ... + } + } + } + + Explanation: + ad 1: constants for the states (used in the transition table) + ad 2: constants for the input (used in the transition table) + ad 3: the transition table for the state machine + ad 4: test if we are in a parseContinue() step + a) if no, do inititalizations + b) if yes, restore the state and call parse functions recursively + ad 5: Do some actions according to the state; from the logical execution + order, this code belongs after 8 (see there for an explanation) + ad 6: Check the character that is at the actual "cursor" position: + a) If we reached the EOF, report either error or push the state (in the + case of incremental parsing). + b) Otherwise, set the input character constant for the transition + table. + ad 7: Get the new state according to the input that was read. + ad 8: Do some actions according to the state. The last line in every case + statement reads new data (i.e. it move the cursor). This can also be + done by calling another parse...() function. If you need processing for + this state after that, you have to put it into the switch statement 5. + This ensures that you have a well defined re-entry point, when you ran + out of data. +*/ + +/* + Parses the prolog [22]. +*/ + +bool QXmlSimpleReaderPrivate::parseProlog() +{ + const signed char Init = 0; + const signed char EatWS = 1; // eat white spaces + const signed char Lt = 2; // '<' read + const signed char Em = 3; // '!' read + const signed char DocType = 4; // read doctype + const signed char Comment = 5; // read comment + const signed char CommentR = 6; // same as Comment, but already reported + const signed char PInstr = 7; // read PI + const signed char PInstrR = 8; // same as PInstr, but already reported + const signed char Done = 9; + + const signed char InpWs = 0; + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpD = 4; // D + const signed char InpDash = 5; // - + const signed char InpUnknown = 6; + + static const signed char table[9][7] = { + /* InpWs InpLt InpQm InpEm InpD InpDash InpUnknown */ + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Init + { -1, Lt, -1, -1, -1, -1, -1 }, // EatWS + { -1, -1, PInstr,Em, Done, -1, Done }, // Lt + { -1, -1, -1, -1, DocType, Comment, -1 }, // Em + { EatWS, Lt, -1, -1, -1, -1, -1 }, // DocType + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Comment + { EatWS, Lt, -1, -1, -1, -1, -1 }, // CommentR + { EatWS, Lt, -1, -1, -1, -1, -1 }, // PInstr + { EatWS, Lt, -1, -1, -1, -1, -1 } // PInstrR + }; + signed char state; + signed char input; + + if (parseStack == 0 || parseStack->isEmpty()) { + xmldecl_possible = true; + doctype_read = false; + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseProlog (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case DocType: + if (doctype_read) { + reportParseError(QLatin1String(XMLERR_MORETHANONEDOCTYPE)); + return false; + } else { + doctype_read = false; + } + break; + case Comment: + if (lexicalHnd) { + if (!lexicalHnd->comment(string())) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + state = CommentR; + break; + case PInstr: + // call the handler + if (contentHnd) { + if (xmldecl_possible && !xmlVersion.isEmpty()) { + QString value(QLatin1String("version='")); + value += xmlVersion; + value += QLatin1Char('\''); + if (!encoding.isEmpty()) { + value += QLatin1String(" encoding='"); + value += encoding; + value += QLatin1Char('\''); + } + if (standalone == QXmlSimpleReaderPrivate::Yes) { + value += QLatin1String(" standalone='yes'"); + } else if (standalone == QXmlSimpleReaderPrivate::No) { + value += QLatin1String(" standalone='no'"); + } + if (!contentHnd->processingInstruction(QLatin1String("xml"), value)) { + reportParseError(contentHnd->errorString()); + return false; + } + } else { + if (!contentHnd->processingInstruction(name(), string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + // XML declaration only on first position possible + xmldecl_possible = false; + state = PInstrR; + break; + case Done: + return true; + case -1: + reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('<')) { + input = InpLt; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else if (c == QLatin1Char('!')) { + input = InpEm; + } else if (c == QLatin1Char('D')) { + input = InpD; + } else if (c == QLatin1Char('-')) { + input = InpDash; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case EatWS: + // XML declaration only on first position possible + xmldecl_possible = false; + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + break; + case Lt: + next(); + break; + case Em: + // XML declaration only on first position possible + xmldecl_possible = false; + next(); + break; + case DocType: + if (!parseDoctype()) { + parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + break; + case Comment: + case CommentR: + if (!parseComment()) { + parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + break; + case PInstr: + case PInstrR: + parsePI_xmldecl = xmldecl_possible; + if (!parsePI()) { + parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state); + return false; + } + break; + } + } + return false; +} + +/* + Parse an element [39]. + + Precondition: the opening '<' is already read. +*/ +bool QXmlSimpleReaderPrivate::parseElement() +{ + const int Init = 0; + const int ReadName = 1; + const int Ws1 = 2; + const int STagEnd = 3; + const int STagEnd2 = 4; + const int ETagBegin = 5; + const int ETagBegin2 = 6; + const int Ws2 = 7; + const int EmptyTag = 8; + const int Attrib = 9; + const int AttribPro = 10; // like Attrib, but processAttribute was already called + const int Ws3 = 11; + const int Done = 12; + + const int InpWs = 0; // whitespace + const int InpNameBe = 1; // NameBeginning + const int InpGt = 2; // > + const int InpSlash = 3; // / + const int InpUnknown = 4; + + static const int table[12][5] = { + /* InpWs InpNameBe InpGt InpSlash InpUnknown */ + { -1, ReadName, -1, -1, -1 }, // Init + { Ws1, Attrib, STagEnd, EmptyTag, -1 }, // ReadName + { -1, Attrib, STagEnd, EmptyTag, -1 }, // Ws1 + { STagEnd2, STagEnd2, STagEnd2, STagEnd2, STagEnd2 }, // STagEnd + { -1, -1, -1, ETagBegin, -1 }, // STagEnd2 + { -1, ETagBegin2, -1, -1, -1 }, // ETagBegin + { Ws2, -1, Done, -1, -1 }, // ETagBegin2 + { -1, -1, Done, -1, -1 }, // Ws2 + { -1, -1, Done, -1, -1 }, // EmptyTag + { Ws3, Attrib, STagEnd, EmptyTag, -1 }, // Attrib + { Ws3, Attrib, STagEnd, EmptyTag, -1 }, // AttribPro + { -1, Attrib, STagEnd, EmptyTag, -1 } // Ws3 + }; + int state; + int input; + + if (parseStack == 0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseElement (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case ReadName: + // store it on the stack + tags.push(name()); + // empty the attributes + attList.clear(); + if (useNamespaces) + namespaceSupport.pushContext(); + break; + case ETagBegin2: + if (!processElementETagBegin2()) + return false; + break; + case Attrib: + if (!processElementAttribute()) + return false; + state = AttribPro; + break; + case Done: + return true; + case -1: + reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + if (fastDetermineNameChar(c) == NameBeginning) { + input = InpNameBe; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('/')) { + input = InpSlash; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case ReadName: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + break; + case Ws1: + case Ws2: + case Ws3: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + break; + case STagEnd: + // call the handler + if (contentHnd) { + const QString &tagsTop = tags.top(); + if (useNamespaces) { + QString uri, lname; + namespaceSupport.processName(tagsTop, false, uri, lname); + if (!contentHnd->startElement(uri, lname, tagsTop, attList)) { + reportParseError(contentHnd->errorString()); + return false; + } + } else { + if (!contentHnd->startElement(QString(), QString(), tagsTop, attList)) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + next(); + break; + case STagEnd2: + if (!parseContent()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + break; + case ETagBegin: + next(); + break; + case ETagBegin2: + // get the name of the tag + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + break; + case EmptyTag: + if (tags.isEmpty()) { + reportParseError(QLatin1String(XMLERR_TAGMISMATCH)); + return false; + } + if (!processElementEmptyTag()) + return false; + next(); + break; + case Attrib: + case AttribPro: + // get name and value of attribute + if (!parseAttribute()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElement, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Helper to break down the size of the code in the case statement. + Return false on error, otherwise true. +*/ +bool QXmlSimpleReaderPrivate::processElementEmptyTag() +{ + QString uri, lname; + // pop the stack and call the handler + if (contentHnd) { + if (useNamespaces) { + // report startElement first... + namespaceSupport.processName(tags.top(), false, uri, lname); + if (!contentHnd->startElement(uri, lname, tags.top(), attList)) { + reportParseError(contentHnd->errorString()); + return false; + } + // ... followed by endElement... + if (!contentHnd->endElement(uri, lname, tags.pop())) { + reportParseError(contentHnd->errorString()); + return false; + } + // ... followed by endPrefixMapping + QStringList prefixesBefore, prefixesAfter; + if (contentHnd) { + prefixesBefore = namespaceSupport.prefixes(); + } + namespaceSupport.popContext(); + // call the handler for prefix mapping + prefixesAfter = namespaceSupport.prefixes(); + for (QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it) { + if (!prefixesAfter.contains(*it)) { + if (!contentHnd->endPrefixMapping(*it)) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + } else { + // report startElement first... + if (!contentHnd->startElement(QString(), QString(), tags.top(), attList)) { + reportParseError(contentHnd->errorString()); + return false; + } + // ... followed by endElement + if (!contentHnd->endElement(QString(), QString(), tags.pop())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } else { + tags.pop_back(); + namespaceSupport.popContext(); + } + return true; +} +/* + Helper to break down the size of the code in the case statement. + Return false on error, otherwise true. +*/ +bool QXmlSimpleReaderPrivate::processElementETagBegin2() +{ + const QString &name = QXmlSimpleReaderPrivate::name(); + + // pop the stack and compare it with the name + if (tags.pop() != name) { + reportParseError(QLatin1String(XMLERR_TAGMISMATCH)); + return false; + } + // call the handler + if (contentHnd) { + QString uri, lname; + + if (useNamespaces) + namespaceSupport.processName(name, false, uri, lname); + if (!contentHnd->endElement(uri, lname, name)) { + reportParseError(contentHnd->errorString()); + return false; + } + } + if (useNamespaces) { + NamespaceMap prefixesBefore, prefixesAfter; + if (contentHnd) + prefixesBefore = namespaceSupport.d->ns; + + namespaceSupport.popContext(); + // call the handler for prefix mapping + if (contentHnd) { + prefixesAfter = namespaceSupport.d->ns; + if (prefixesBefore.size() != prefixesAfter.size()) { + for (NamespaceMap::const_iterator it = prefixesBefore.constBegin(); it != prefixesBefore.constEnd(); ++it) { + if (!it.key().isEmpty() && !prefixesAfter.contains(it.key())) { + if (!contentHnd->endPrefixMapping(it.key())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + } + } + } + return true; +} +/* + Helper to break down the size of the code in the case statement. + Return false on error, otherwise true. +*/ +bool QXmlSimpleReaderPrivate::processElementAttribute() +{ + QString uri, lname, prefix; + const QString &name = QXmlSimpleReaderPrivate::name(); + const QString &string = QXmlSimpleReaderPrivate::string(); + + // add the attribute to the list + if (useNamespaces) { + // is it a namespace declaration? + namespaceSupport.splitName(name, prefix, lname); + if (prefix == QLatin1String("xmlns")) { + // namespace declaration + namespaceSupport.setPrefix(lname, string); + if (useNamespacePrefixes) { + // according to http://www.w3.org/2000/xmlns/, the "prefix" + // xmlns maps to the namespace name + // http://www.w3.org/2000/xmlns/ + attList.append(name, QLatin1String("http://www.w3.org/2000/xmlns/"), lname, string); + } + // call the handler for prefix mapping + if (contentHnd) { + if (!contentHnd->startPrefixMapping(lname, string)) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } else { + // no namespace delcaration + namespaceSupport.processName(name, true, uri, lname); + attList.append(name, uri, lname, string); + } + } else { + // no namespace support + attList.append(name, uri, lname, string); + } + return true; +} + +/* + Parse a content [43]. + + A content is only used between tags. If a end tag is found the < is already + read and the head stand on the '/' of the end tag '</name>'. +*/ +bool QXmlSimpleReaderPrivate::parseContent() +{ + const signed char Init = 0; + const signed char ChD = 1; // CharData + const signed char ChD1 = 2; // CharData help state + const signed char ChD2 = 3; // CharData help state + const signed char Ref = 4; // Reference + const signed char Lt = 5; // '<' read + const signed char PInstr = 6; // PI + const signed char PInstrR = 7; // same as PInstr, but already reported + const signed char Elem = 8; // Element + const signed char Em = 9; // '!' read + const signed char Com = 10; // Comment + const signed char ComR = 11; // same as Com, but already reported + const signed char CDS = 12; // CDSect + const signed char CDS1 = 13; // read a CDSect + const signed char CDS2 = 14; // read a CDSect (help state) + const signed char CDS3 = 15; // read a CDSect (help state) + const signed char Done = 16; // finished reading content + + const signed char InpLt = 0; // < + const signed char InpGt = 1; // > + const signed char InpSlash = 2; // / + const signed char InpQMark = 3; // ? + const signed char InpEMark = 4; // ! + const signed char InpAmp = 5; // & + const signed char InpDash = 6; // - + const signed char InpOpenB = 7; // [ + const signed char InpCloseB = 8; //] + const signed char InpUnknown = 9; + + static const signed char mapCLT2FSMChar[] = { + InpUnknown, // white space + InpUnknown, // % + InpAmp, // & + InpGt, // > + InpLt, // < + InpSlash, // / + InpQMark, // ? + InpEMark, // ! + InpDash, // - + InpCloseB, //] + InpOpenB, // [ + InpUnknown, // = + InpUnknown, // " + InpUnknown, // ' + InpUnknown // unknown + }; + + static const signed char table[16][10] = { + /* InpLt InpGt InpSlash InpQMark InpEMark InpAmp InpDash InpOpenB InpCloseB InpUnknown */ + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // Init + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // ChD + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD1 + { Lt, -1, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD2 + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Ref (same as Init) + { -1, -1, Done, PInstr, Em, -1, -1, -1, -1, Elem }, // Lt + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PInstr (same as Init) + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PInstrR + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Elem (same as Init) + { -1, -1, -1, -1, -1, -1, Com, CDS, -1, -1 }, // Em + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Com (same as Init) + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // ComR + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS1 + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 }, // CDS2 + { CDS1, Init, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 } // CDS3 + }; + signed char state; + signed char input; + + if (parseStack == 0 || parseStack->isEmpty()) { + contentCharDataRead = false; + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseContent (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Ref: + if (!contentCharDataRead) + contentCharDataRead = parseReference_charDataRead; + break; + case PInstr: + if (contentHnd) { + if (!contentHnd->processingInstruction(name(),string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + state = PInstrR; + break; + case Com: + if (lexicalHnd) { + if (!lexicalHnd->comment(string())) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + state = ComR; + break; + case CDS: + stringClear(); + break; + case CDS2: + if (!atEnd() && c != QLatin1Char(']')) + stringAddC(QLatin1Char(']')); + break; + case CDS3: + // test if this skipping was legal + if (!atEnd()) { + if (c == QLatin1Char('>')) { + // the end of the CDSect + if (lexicalHnd) { + if (!lexicalHnd->startCDATA()) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + if (contentHnd) { + if (!contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + if (lexicalHnd) { + if (!lexicalHnd->endCDATA()) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + } else if (c == QLatin1Char(']')) { + // three or more ']' + stringAddC(QLatin1Char(']')); + } else { + // after ']]' comes another character + stringAddC(QLatin1Char(']')); + stringAddC(QLatin1Char(']')); + } + } + break; + case Done: + // call the handler for CharData + if (contentHnd) { + if (contentCharDataRead) { + if (reportWhitespaceCharData || !string().simplified().isEmpty()) { + if (!contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + } + // Done + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_ERRORPARSINGCONTENT)); + return false; + } + + // get input (use lookup-table instead of nested ifs for performance + // reasons) + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + if (c.row()) { + input = InpUnknown; + } else { + input = mapCLT2FSMChar[charLookupTable[c.cell()]]; + } + state = table[state][input]; + + switch (state) { + case Init: + // skip the ending '>' of a CDATASection + next(); + break; + case ChD: + // on first call: clear string + if (!contentCharDataRead) { + contentCharDataRead = true; + stringClear(); + } + stringAddC(); + if (reportEntities) { + if (!reportEndEntities()) + return false; + } + next(); + break; + case ChD1: + // on first call: clear string + if (!contentCharDataRead) { + contentCharDataRead = true; + stringClear(); + } + stringAddC(); + if (reportEntities) { + if (!reportEndEntities()) + return false; + } + next(); + break; + case ChD2: + stringAddC(); + if (reportEntities) { + if (!reportEndEntities()) + return false; + } + next(); + break; + case Ref: + if (!contentCharDataRead) { + // reference may be CharData; so clear string to be safe + stringClear(); + parseReference_context = InContent; + if (!parseReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + } else { + if (reportEntities) { + // report character data in chunks + if (contentHnd) { + if (reportWhitespaceCharData || !string().simplified().isEmpty()) { + if (!contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + stringClear(); + } + parseReference_context = InContent; + if (!parseReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + } + break; + case Lt: + // call the handler for CharData + if (contentHnd) { + if (contentCharDataRead) { + if (reportWhitespaceCharData || !string().simplified().isEmpty()) { + if (!contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + } + contentCharDataRead = false; + next(); + break; + case PInstr: + case PInstrR: + parsePI_xmldecl = false; + if (!parsePI()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + break; + case Elem: + if (!parseElement()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + break; + case Em: + next(); + break; + case Com: + case ComR: + if (!parseComment()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + break; + case CDS: + parseString_s = QLatin1String("[CDATA["); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseContent, state); + return false; + } + break; + case CDS1: + stringAddC(); + next(); + break; + case CDS2: + // skip ']' + next(); + break; + case CDS3: + // skip ']'... + next(); + break; + } + } + return false; +} + +bool QXmlSimpleReaderPrivate::reportEndEntities() +{ + int count = (int)xmlRefStack.count(); + while (count != 0 && xmlRefStack.top().isEmpty()) { + if (contentHnd) { + if (reportWhitespaceCharData || !string().simplified().isEmpty()) { + if (!contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } + stringClear(); + if (lexicalHnd) { + if (!lexicalHnd->endEntity(xmlRefStack.top().name)) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + xmlRefStack.pop_back(); + count--; + } + return true; +} + +/* + Parse Misc [27]. +*/ +bool QXmlSimpleReaderPrivate::parseMisc() +{ + const signed char Init = 0; + const signed char Lt = 1; // '<' was read + const signed char Comment = 2; // read comment + const signed char eatWS = 3; // eat whitespaces + const signed char PInstr = 4; // read PI + const signed char Comment2 = 5; // read comment + + const signed char InpWs = 0; // S + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpUnknown = 4; + + static const signed char table[3][5] = { + /* InpWs InpLt InpQm InpEm InpUnknown */ + { eatWS, Lt, -1, -1, -1 }, // Init + { -1, -1, PInstr,Comment, -1 }, // Lt + { -1, -1, -1, -1, Comment2 } // Comment + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseMisc (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case eatWS: + return true; + case PInstr: + if (contentHnd) { + if (!contentHnd->processingInstruction(name(),string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + return true; + case Comment2: + if (lexicalHnd) { + if (!lexicalHnd->comment(string())) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseMisc, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('<')) { + input = InpLt; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else if (c == QLatin1Char('!')) { + input = InpEm; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case eatWS: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state); + return false; + } + break; + case Lt: + next(); + break; + case PInstr: + parsePI_xmldecl = false; + if (!parsePI()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state); + return false; + } + break; + case Comment: + next(); + break; + case Comment2: + if (!parseComment()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state); + return false; + } + break; + } + } + return false; +} + +/* + Parse a processing instruction [16]. + + If xmldec is true, it tries to parse a PI or a XML declaration [23]. + + Precondition: the beginning '<' of the PI is already read and the head stand + on the '?' of '<?'. + + If this funktion was successful, the head-position is on the first + character after the PI. +*/ +bool QXmlSimpleReaderPrivate::parsePI() +{ + const signed char Init = 0; + const signed char QmI = 1; // ? was read + const signed char Name = 2; // read Name + const signed char XMLDecl = 3; // read XMLDecl + const signed char Ws1 = 4; // eat ws after "xml" of XMLDecl + const signed char PInstr = 5; // read PI + const signed char Ws2 = 6; // eat ws after Name of PI + const signed char Version = 7; // read versionInfo + const signed char Ws3 = 8; // eat ws after versionInfo + const signed char EorSD = 9; // read EDecl or SDDecl + const signed char Ws4 = 10; // eat ws after EDecl or SDDecl + const signed char SD = 11; // read SDDecl + const signed char Ws5 = 12; // eat ws after SDDecl + const signed char ADone = 13; // almost done + const signed char Char = 14; // Char was read + const signed char Qm = 15; // Qm was read + const signed char Done = 16; // finished reading content + + const signed char InpWs = 0; // whitespace + const signed char InpNameBe = 1; // NameBeginning + const signed char InpGt = 2; // > + const signed char InpQm = 3; // ? + const signed char InpUnknown = 4; + + static const signed char table[16][5] = { + /* InpWs, InpNameBe InpGt InpQm InpUnknown */ + { -1, -1, -1, QmI, -1 }, // Init + { -1, Name, -1, -1, -1 }, // QmI + { -1, -1, -1, -1, -1 }, // Name (this state is left not through input) + { Ws1, -1, -1, -1, -1 }, // XMLDecl + { -1, Version, -1, -1, -1 }, // Ws1 + { Ws2, -1, -1, Qm, -1 }, // PInstr + { Char, Char, Char, Qm, Char }, // Ws2 + { Ws3, -1, -1, ADone, -1 }, // Version + { -1, EorSD, -1, ADone, -1 }, // Ws3 + { Ws4, -1, -1, ADone, -1 }, // EorSD + { -1, SD, -1, ADone, -1 }, // Ws4 + { Ws5, -1, -1, ADone, -1 }, // SD + { -1, -1, -1, ADone, -1 }, // Ws5 + { -1, -1, Done, -1, -1 }, // ADone + { Char, Char, Char, Qm, Char }, // Char + { Char, Char, Done, Qm, Char }, // Qm + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parsePI (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Name: + // test what name was read and determine the next state + // (not very beautiful, I admit) + if (name().toLower() == QLatin1String("xml")) { + if (parsePI_xmldecl && name() == QLatin1String("xml")) { + state = XMLDecl; + } else { + reportParseError(QLatin1String(XMLERR_INVALIDNAMEFORPI)); + return false; + } + } else { + state = PInstr; + stringClear(); + } + break; + case Version: + // get version (syntax like an attribute) + if (name() != QLatin1String("version")) { + reportParseError(QLatin1String(XMLERR_VERSIONEXPECTED)); + return false; + } + xmlVersion = string(); + break; + case EorSD: + // get the EDecl or SDDecl (syntax like an attribute) + if (name() == QLatin1String("standalone")) { + if (string()== QLatin1String("yes")) { + standalone = QXmlSimpleReaderPrivate::Yes; + } else if (string() == QLatin1String("no")) { + standalone = QXmlSimpleReaderPrivate::No; + } else { + reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL)); + return false; + } + } else if (name() == QLatin1String("encoding")) { + encoding = string(); + } else { + reportParseError(QLatin1String(XMLERR_EDECLORSDDECLEXPECTED)); + return false; + } + break; + case SD: + if (name() != QLatin1String("standalone")) { + reportParseError(QLatin1String(XMLERR_SDDECLEXPECTED)); + return false; + } + if (string() == QLatin1String("yes")) { + standalone = QXmlSimpleReaderPrivate::Yes; + } else if (string() == QLatin1String("no")) { + standalone = QXmlSimpleReaderPrivate::No; + } else { + reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL)); + return false; + } + break; + case Qm: + // test if the skipping was legal + if (!atEnd() && c != QLatin1Char('>')) + stringAddC(QLatin1Char('?')); + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (determineNameChar(c) == NameBeginning) { + input = InpNameBe; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case QmI: + next(); + break; + case Name: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + case Ws5: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + break; + case Version: + if (!parseAttribute()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + break; + case EorSD: + if (!parseAttribute()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + break; + case SD: + // get the SDDecl (syntax like an attribute) + if (standalone != QXmlSimpleReaderPrivate::Unknown) { + // already parsed the standalone declaration + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + if (!parseAttribute()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePI, state); + return false; + } + break; + case ADone: + next(); + break; + case Char: + stringAddC(); + next(); + break; + case Qm: + // skip the '?' + next(); + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a document type definition (doctypedecl [28]). + + Precondition: the beginning '<!' of the doctype is already read the head + stands on the 'D' of '<!DOCTYPE'. + + If this function was successful, the head-position is on the first + character after the document type definition. +*/ +bool QXmlSimpleReaderPrivate::parseDoctype() +{ + const signed char Init = 0; + const signed char Doctype = 1; // read the doctype + const signed char Ws1 = 2; // eat_ws + const signed char Doctype2 = 3; // read the doctype, part 2 + const signed char Ws2 = 4; // eat_ws + const signed char Sys = 5; // read SYSTEM or PUBLIC + const signed char Ws3 = 6; // eat_ws + const signed char MP = 7; // markupdecl or PEReference + const signed char MPR = 8; // same as MP, but already reported + const signed char PER = 9; // PERReference + const signed char Mup = 10; // markupdecl + const signed char Ws4 = 11; // eat_ws + const signed char MPE = 12; // end of markupdecl or PEReference + const signed char Done = 13; + + const signed char InpWs = 0; + const signed char InpD = 1; // 'D' + const signed char InpS = 2; // 'S' or 'P' + const signed char InpOB = 3; // [ + const signed char InpCB = 4; //] + const signed char InpPer = 5; // % + const signed char InpGt = 6; // > + const signed char InpUnknown = 7; + + static const signed char table[13][8] = { + /* InpWs, InpD InpS InpOB InpCB InpPer InpGt InpUnknown */ + { -1, Doctype, -1, -1, -1, -1, -1, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1, -1, -1 }, // Doctype + { -1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Ws1 + { Ws2, -1, Sys, MP, -1, -1, Done, -1 }, // Doctype2 + { -1, -1, Sys, MP, -1, -1, Done, -1 }, // Ws2 + { Ws3, -1, -1, MP, -1, -1, Done, -1 }, // Sys + { -1, -1, -1, MP, -1, -1, Done, -1 }, // Ws3 + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MP + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MPR + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // PER + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // Mup + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // Ws4 + { -1, -1, -1, -1, -1, -1, Done, -1 } // MPE + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + startDTDwasReported = false; + systemId.clear(); + publicId.clear(); + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseDoctype (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Doctype2: + doctype = name(); + break; + case MP: + if (!startDTDwasReported && lexicalHnd ) { + startDTDwasReported = true; + if (!lexicalHnd->startDTD(doctype, publicId, systemId)) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + state = MPR; + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_ERRORPARSINGDOCTYPE)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('D')) { + input = InpD; + } else if (c == QLatin1Char('S')) { + input = InpS; + } else if (c == QLatin1Char('P')) { + input = InpS; + } else if (c == QLatin1Char('[')) { + input = InpOB; + } else if (c == QLatin1Char(']')) { + input = InpCB; + } else if (c == QLatin1Char('%')) { + input = InpPer; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Doctype: + parseString_s = QLatin1String("DOCTYPE"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case Doctype2: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case Sys: + parseExternalID_allowPublicID = false; + if (!parseExternalID()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + thisPublicId = publicId; + thisSystemId = systemId; + break; + case MP: + case MPR: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case PER: + parsePEReference_context = InDTD; + if (!parsePEReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case Mup: + if (!parseMarkupdecl()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case MPE: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); + return false; + } + break; + case Done: + if (lexicalHnd) { + if (!startDTDwasReported) { + startDTDwasReported = true; + if (!lexicalHnd->startDTD(doctype, publicId, systemId)) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + if (!lexicalHnd->endDTD()) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + next(); + break; + } + } + return false; +} + +/* + Parse a ExternalID [75]. + + If allowPublicID is true parse ExternalID [75] or PublicID [83]. +*/ +bool QXmlSimpleReaderPrivate::parseExternalID() +{ + const signed char Init = 0; + const signed char Sys = 1; // parse 'SYSTEM' + const signed char SysWS = 2; // parse the whitespace after 'SYSTEM' + const signed char SysSQ = 3; // parse SystemLiteral with ' + const signed char SysSQ2 = 4; // parse SystemLiteral with ' + const signed char SysDQ = 5; // parse SystemLiteral with " + const signed char SysDQ2 = 6; // parse SystemLiteral with " + const signed char Pub = 7; // parse 'PUBLIC' + const signed char PubWS = 8; // parse the whitespace after 'PUBLIC' + const signed char PubSQ = 9; // parse PubidLiteral with ' + const signed char PubSQ2 = 10; // parse PubidLiteral with ' + const signed char PubDQ = 11; // parse PubidLiteral with " + const signed char PubDQ2 = 12; // parse PubidLiteral with " + const signed char PubE = 13; // finished parsing the PubidLiteral + const signed char PubWS2 = 14; // parse the whitespace after the PubidLiteral + const signed char PDone = 15; // done if allowPublicID is true + const signed char Done = 16; + + const signed char InpSQ = 0; // ' + const signed char InpDQ = 1; // " + const signed char InpS = 2; // S + const signed char InpP = 3; // P + const signed char InpWs = 4; // white space + const signed char InpUnknown = 5; + + static const signed char table[15][6] = { + /* InpSQ InpDQ InpS InpP InpWs InpUnknown */ + { -1, -1, Sys, Pub, -1, -1 }, // Init + { -1, -1, -1, -1, SysWS, -1 }, // Sys + { SysSQ, SysDQ, -1, -1, -1, -1 }, // SysWS + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ2 + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ2 + { -1, -1, -1, -1, PubWS, -1 }, // Pub + { PubSQ, PubDQ, -1, -1, -1, -1 }, // PubWS + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ2 + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ2 + { PDone, PDone, PDone, PDone, PubWS2, PDone }, // PubE + { SysSQ, SysDQ, PDone, PDone, PDone, PDone } // PubWS2 + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + systemId.clear(); + publicId.clear(); + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseExternalID (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case PDone: + if (parseExternalID_allowPublicID) { + publicId = string(); + return true; + } else { + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('\'')) { + input = InpSQ; + } else if (c == QLatin1Char('"')) { + input = InpDQ; + } else if (c == QLatin1Char('S')) { + input = InpS; + } else if (c == QLatin1Char('P')) { + input = InpP; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Sys: + parseString_s = QLatin1String("SYSTEM"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + break; + case SysWS: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + break; + case SysSQ: + case SysDQ: + stringClear(); + next(); + break; + case SysSQ2: + case SysDQ2: + stringAddC(); + next(); + break; + case Pub: + parseString_s = QLatin1String("PUBLIC"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + break; + case PubWS: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + break; + case PubSQ: + case PubDQ: + stringClear(); + next(); + break; + case PubSQ2: + case PubDQ2: + stringAddC(); + next(); + break; + case PubE: + next(); + break; + case PubWS2: + publicId = string(); + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state); + return false; + } + break; + case Done: + systemId = string(); + next(); + break; + } + } + return false; +} + +/* + Parse a markupdecl [29]. +*/ +bool QXmlSimpleReaderPrivate::parseMarkupdecl() +{ + const signed char Init = 0; + const signed char Lt = 1; // < was read + const signed char Em = 2; // ! was read + const signed char CE = 3; // E was read + const signed char Qm = 4; // ? was read + const signed char Dash = 5; // - was read + const signed char CA = 6; // A was read + const signed char CEL = 7; // EL was read + const signed char CEN = 8; // EN was read + const signed char CN = 9; // N was read + const signed char Done = 10; + + const signed char InpLt = 0; // < + const signed char InpQm = 1; // ? + const signed char InpEm = 2; // ! + const signed char InpDash = 3; // - + const signed char InpA = 4; // A + const signed char InpE = 5; // E + const signed char InpL = 6; // L + const signed char InpN = 7; // N + const signed char InpUnknown = 8; + + static const signed char table[4][9] = { + /* InpLt InpQm InpEm InpDash InpA InpE InpL InpN InpUnknown */ + { Lt, -1, -1, -1, -1, -1, -1, -1, -1 }, // Init + { -1, Qm, Em, -1, -1, -1, -1, -1, -1 }, // Lt + { -1, -1, -1, Dash, CA, CE, -1, CN, -1 }, // Em + { -1, -1, -1, -1, -1, -1, CEL, CEN, -1 } // CE + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseMarkupdecl (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Qm: + if (contentHnd) { + if (!contentHnd->processingInstruction(name(),string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + return true; + case Dash: + if (lexicalHnd) { + if (!lexicalHnd->comment(string())) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + return true; + case CA: + return true; + case CEL: + return true; + case CEN: + return true; + case CN: + return true; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + if (c == QLatin1Char('<')) { + input = InpLt; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else if (c == QLatin1Char('!')) { + input = InpEm; + } else if (c == QLatin1Char('-')) { + input = InpDash; + } else if (c == QLatin1Char('A')) { + input = InpA; + } else if (c == QLatin1Char('E')) { + input = InpE; + } else if (c == QLatin1Char('L')) { + input = InpL; + } else if (c == QLatin1Char('N')) { + input = InpN; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Lt: + next(); + break; + case Em: + next(); + break; + case CE: + next(); + break; + case Qm: + parsePI_xmldecl = false; + if (!parsePI()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + case Dash: + if (!parseComment()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + case CA: + if (!parseAttlistDecl()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + case CEL: + if (!parseElementDecl()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + case CEN: + if (!parseEntityDecl()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + case CN: + if (!parseNotationDecl()) { + parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state); + return false; + } + break; + } + } + return false; +} + +/* + Parse a PEReference [69] +*/ +bool QXmlSimpleReaderPrivate::parsePEReference() +{ + const signed char Init = 0; + const signed char Next = 1; + const signed char Name = 2; + const signed char NameR = 3; // same as Name, but already reported + const signed char Done = 4; + + const signed char InpSemi = 0; // ; + const signed char InpPer = 1; // % + const signed char InpUnknown = 2; + + static const signed char table[4][3] = { + /* InpSemi InpPer InpUnknown */ + { -1, Next, -1 }, // Init + { -1, -1, Name }, // Next + { Done, -1, -1 }, // Name + { Done, -1, -1 } // NameR + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parsePEReference (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePEReference, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Name: + { + bool skipIt = true; + QString xmlRefString; + + QMap<QString,QString>::Iterator it; + it = parameterEntities.find(ref()); + if (it != parameterEntities.end()) { + skipIt = false; + xmlRefString = *it; + } else if (entityRes) { + QMap<QString,QXmlSimpleReaderPrivate::ExternParameterEntity>::Iterator it2; + it2 = externParameterEntities.find(ref()); + QXmlInputSource *ret = 0; + if (it2 != externParameterEntities.end()) { + if (!entityRes->resolveEntity((*it2).publicId, (*it2).systemId, ret)) { + delete ret; + reportParseError(entityRes->errorString()); + return false; + } + if (ret) { + xmlRefString = ret->data(); + delete ret; + if (!stripTextDecl(xmlRefString)) { + reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL)); + return false; + } + skipIt = false; + } + } + } + + if (skipIt) { + if (contentHnd) { + if (!contentHnd->skippedEntity(QString::fromLatin1("%") + ref())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + } else { + if (parsePEReference_context == InEntityValue) { + // Included in literal + if (!insertXmlRef(xmlRefString, ref(), true)) + return false; + } else if (parsePEReference_context == InDTD) { + // Included as PE + if (!insertXmlRef(QString::fromLatin1(" ")+xmlRefString+QString::fromLatin1(" "), ref(), false)) + return false; + } + } + } + state = NameR; + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parsePEReference, state); + return false; + } + if (c == QLatin1Char(';')) { + input = InpSemi; + } else if (c == QLatin1Char('%')) { + input = InpPer; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Next: + next(); + break; + case Name: + case NameR: + parseName_useRef = true; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parsePEReference, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a AttlistDecl [52]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'A' of '<!ATTLIST' +*/ +bool QXmlSimpleReaderPrivate::parseAttlistDecl() +{ + const signed char Init = 0; + const signed char Attlist = 1; // parse the string "ATTLIST" + const signed char Ws = 2; // whitespace read + const signed char Name = 3; // parse name + const signed char Ws1 = 4; // whitespace read + const signed char Attdef = 5; // parse the AttDef + const signed char Ws2 = 6; // whitespace read + const signed char Atttype = 7; // parse the AttType + const signed char Ws3 = 8; // whitespace read + const signed char DDecH = 9; // DefaultDecl with # + const signed char DefReq = 10; // parse the string "REQUIRED" + const signed char DefImp = 11; // parse the string "IMPLIED" + const signed char DefFix = 12; // parse the string "FIXED" + const signed char Attval = 13; // parse the AttValue + const signed char Ws4 = 14; // whitespace read + const signed char Done = 15; + + const signed char InpWs = 0; // white space + const signed char InpGt = 1; // > + const signed char InpHash = 2; // # + const signed char InpA = 3; // A + const signed char InpI = 4; // I + const signed char InpF = 5; // F + const signed char InpR = 6; // R + const signed char InpUnknown = 7; + + static const signed char table[15][8] = { + /* InpWs InpGt InpHash InpA InpI InpF InpR InpUnknown */ + { -1, -1, -1, Attlist, -1, -1, -1, -1 }, // Init + { Ws, -1, -1, -1, -1, -1, -1, -1 }, // Attlist + { -1, -1, -1, Name, Name, Name, Name, Name }, // Ws + { Ws1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Name + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1 }, // Attdef + { -1, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype }, // Ws2 + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // Attype + { -1, Attval, DDecH, Attval, Attval, Attval, Attval, Attval }, // Ws3 + { -1, -1, -1, -1, DefImp, DefFix, DefReq, -1 }, // DDecH + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefReq + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefImp + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // DefFix + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // Attval + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef } // Ws4 + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseAttlistDecl (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Name: + attDeclEName = name(); + break; + case Attdef: + attDeclAName = name(); + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (c == QLatin1Char('#')) { + input = InpHash; + } else if (c == QLatin1Char('A')) { + input = InpA; + } else if (c == QLatin1Char('I')) { + input = InpI; + } else if (c == QLatin1Char('F')) { + input = InpF; + } else if (c == QLatin1Char('R')) { + input = InpR; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Attlist: + parseString_s = QLatin1String("ATTLIST"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Ws: + case Ws1: + case Ws2: + case Ws3: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Name: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Attdef: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Atttype: + if (!parseAttType()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case DDecH: + next(); + break; + case DefReq: + parseString_s = QLatin1String("REQUIRED"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case DefImp: + parseString_s = QLatin1String("IMPLIED"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case DefFix: + parseString_s = QLatin1String("FIXED"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Attval: + if (!parseAttValue()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Ws4: + if (declHnd) { + // ### not all values are computed yet... + if (!declHnd->attributeDecl(attDeclEName, attDeclAName, QLatin1String(""), QLatin1String(""), QLatin1String(""))) { + reportParseError(declHnd->errorString()); + return false; + } + } + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a AttType [54] +*/ +bool QXmlSimpleReaderPrivate::parseAttType() +{ + const signed char Init = 0; + const signed char ST = 1; // StringType + const signed char TTI = 2; // TokenizedType starting with 'I' + const signed char TTI2 = 3; // TokenizedType helpstate + const signed char TTI3 = 4; // TokenizedType helpstate + const signed char TTE = 5; // TokenizedType starting with 'E' + const signed char TTEY = 6; // TokenizedType starting with 'ENTITY' + const signed char TTEI = 7; // TokenizedType starting with 'ENTITI' + const signed char N = 8; // N read (TokenizedType or Notation) + const signed char TTNM = 9; // TokenizedType starting with 'NM' + const signed char TTNM2 = 10; // TokenizedType helpstate + const signed char NO = 11; // Notation + const signed char NO2 = 12; // Notation helpstate + const signed char NO3 = 13; // Notation helpstate + const signed char NOName = 14; // Notation, read name + const signed char NO4 = 15; // Notation helpstate + const signed char EN = 16; // Enumeration + const signed char ENNmt = 17; // Enumeration, read Nmtoken + const signed char EN2 = 18; // Enumeration helpstate + const signed char ADone = 19; // almost done (make next and accept) + const signed char Done = 20; + + const signed char InpWs = 0; // whitespace + const signed char InpOp = 1; // ( + const signed char InpCp = 2; //) + const signed char InpPipe = 3; // | + const signed char InpC = 4; // C + const signed char InpE = 5; // E + const signed char InpI = 6; // I + const signed char InpM = 7; // M + const signed char InpN = 8; // N + const signed char InpO = 9; // O + const signed char InpR = 10; // R + const signed char InpS = 11; // S + const signed char InpY = 12; // Y + const signed char InpUnknown = 13; + + static const signed char table[19][14] = { + /* InpWs InpOp InpCp InpPipe InpC InpE InpI InpM InpN InpO InpR InpS InpY InpUnknown */ + { -1, EN, -1, -1, ST, TTE, TTI, -1, N, -1, -1, -1, -1, -1 }, // Init + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // ST + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI2, Done, Done, Done }, // TTI + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI3, Done, Done }, // TTI2 + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTI3 + { -1, -1, -1, -1, -1, -1, TTEI, -1, -1, -1, -1, -1, TTEY, -1 }, // TTE + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEY + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEI + { -1, -1, -1, -1, -1, -1, -1, TTNM, -1, NO, -1, -1, -1, -1 }, // N + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTNM2, Done, Done }, // TTNM + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTNM2 + { NO2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO + { -1, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO2 + { NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName }, // NO3 + { NO4, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NOName + { -1, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO4 + { -1, -1, ENNmt, -1, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt }, // EN + { EN2, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // ENNmt + { -1, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // EN2 + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseAttType (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case ADone: + return true; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('(')) { + input = InpOp; + } else if (c == QLatin1Char(')')) { + input = InpCp; + } else if (c == QLatin1Char('|')) { + input = InpPipe; + } else if (c == QLatin1Char('C')) { + input = InpC; + } else if (c == QLatin1Char('E')) { + input = InpE; + } else if (c == QLatin1Char('I')) { + input = InpI; + } else if (c == QLatin1Char('M')) { + input = InpM; + } else if (c == QLatin1Char('N')) { + input = InpN; + } else if (c == QLatin1Char('O')) { + input = InpO; + } else if (c == QLatin1Char('R')) { + input = InpR; + } else if (c == QLatin1Char('S')) { + input = InpS; + } else if (c == QLatin1Char('Y')) { + input = InpY; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case ST: + parseString_s = QLatin1String("CDATA"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case TTI: + parseString_s = QLatin1String("ID"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case TTI2: + parseString_s = QLatin1String("REF"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case TTI3: + next(); // S + break; + case TTE: + parseString_s = QLatin1String("ENTIT"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case TTEY: + next(); // Y + break; + case TTEI: + parseString_s = QLatin1String("IES"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case N: + next(); // N + break; + case TTNM: + parseString_s = QLatin1String("MTOKEN"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case TTNM2: + next(); // S + break; + case NO: + parseString_s = QLatin1String("OTATION"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case NO2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case NO3: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case NOName: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case NO4: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case EN: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case ENNmt: + if (!parseNmtoken()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case EN2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state); + return false; + } + break; + case ADone: + next(); + break; + } + } + return false; +} + +/* + Parse a AttValue [10] + + Precondition: the head stands on the beginning " or ' + + If this function was successful, the head stands on the first + character after the closing " or ' and the value of the attribute + is in string(). +*/ +bool QXmlSimpleReaderPrivate::parseAttValue() +{ + const signed char Init = 0; + const signed char Dq = 1; // double quotes were read + const signed char DqRef = 2; // read references in double quotes + const signed char DqC = 3; // signed character read in double quotes + const signed char Sq = 4; // single quotes were read + const signed char SqRef = 5; // read references in single quotes + const signed char SqC = 6; // signed character read in single quotes + const signed char Done = 7; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpLt = 3; // < + const signed char InpUnknown = 4; + + static const signed char table[7][5] = { + /* InpDq InpSq InpAmp InpLt InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, -1, DqC }, // Dq + { Done, DqC, DqRef, -1, DqC }, // DqRef + { Done, DqC, DqRef, -1, DqC }, // DqC + { SqC, Done, SqRef, -1, SqC }, // Sq + { SqC, Done, SqRef, -1, SqC }, // SqRef + { SqC, Done, SqRef, -1, SqC } // SqRef + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseAttValue (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttValue, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseAttValue, state); + return false; + } + if (c == QLatin1Char('"')) { + input = InpDq; + } else if (c == QLatin1Char('\'')) { + input = InpSq; + } else if (c == QLatin1Char('&')) { + input = InpAmp; + } else if (c == QLatin1Char('<')) { + input = InpLt; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqRef: + case SqRef: + parseReference_context = InAttributeValue; + if (!parseReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttValue, state); + return false; + } + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a elementdecl [45]. + + Precondition: the beginning '<!E' is already read and the head + stands on the 'L' of '<!ELEMENT' +*/ +bool QXmlSimpleReaderPrivate::parseElementDecl() +{ + const signed char Init = 0; + const signed char Elem = 1; // parse the beginning string + const signed char Ws1 = 2; // whitespace required + const signed char Nam = 3; // parse Name + const signed char Ws2 = 4; // whitespace required + const signed char Empty = 5; // read EMPTY + const signed char Any = 6; // read ANY + const signed char Cont = 7; // read contentspec (except ANY or EMPTY) + const signed char Mix = 8; // read Mixed + const signed char Mix2 = 9; // + const signed char Mix3 = 10; // + const signed char MixN1 = 11; // + const signed char MixN2 = 12; // + const signed char MixN3 = 13; // + const signed char MixN4 = 14; // + const signed char Cp = 15; // parse cp + const signed char Cp2 = 16; // + const signed char WsD = 17; // eat whitespace before Done + const signed char Done = 18; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpPipe = 2; // | + const signed char InpOp = 3; // ( + const signed char InpCp = 4; //) + const signed char InpHash = 5; // # + const signed char InpQm = 6; // ? + const signed char InpAst = 7; // * + const signed char InpPlus = 8; // + + const signed char InpA = 9; // A + const signed char InpE = 10; // E + const signed char InpL = 11; // L + const signed char InpUnknown = 12; + + static const signed char table[18][13] = { + /* InpWs InpGt InpPipe InpOp InpCp InpHash InpQm InpAst InpPlus InpA InpE InpL InpUnknown */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Elem, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Elem + { -1, -1, -1, -1, -1, -1, -1, -1, -1, Nam, Nam, Nam, Nam }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Nam + { -1, -1, -1, Cont, -1, -1, -1, -1, -1, Any, Empty, -1, -1 }, // Ws2 + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Empty + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Any + { -1, -1, -1, Cp, Cp, Mix, -1, -1, -1, Cp, Cp, Cp, Cp }, // Cont + { Mix2, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix + { -1, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix2 + { WsD, Done, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // Mix3 + { -1, -1, -1, -1, -1, -1, -1, -1, -1, MixN2, MixN2, MixN2, MixN2 }, // MixN1 + { MixN3, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN2 + { -1, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN3 + { -1, -1, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // MixN4 + { WsD, Done, -1, -1, -1, -1, Cp2, Cp2, Cp2, -1, -1, -1, -1 }, // Cp + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Cp2 + { -1, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // WsD + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseElementDecl (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (c == QLatin1Char('|')) { + input = InpPipe; + } else if (c == QLatin1Char('(')) { + input = InpOp; + } else if (c == QLatin1Char(')')) { + input = InpCp; + } else if (c == QLatin1Char('#')) { + input = InpHash; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else if (c == QLatin1Char('*')) { + input = InpAst; + } else if (c == QLatin1Char('+')) { + input = InpPlus; + } else if (c == QLatin1Char('A')) { + input = InpA; + } else if (c == QLatin1Char('E')) { + input = InpE; + } else if (c == QLatin1Char('L')) { + input = InpL; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Elem: + parseString_s = QLatin1String("LEMENT"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Ws1: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Nam: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Ws2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Empty: + parseString_s = QLatin1String("EMPTY"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Any: + parseString_s = QLatin1String("ANY"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Cont: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Mix: + parseString_s = QLatin1String("#PCDATA"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Mix2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Mix3: + next(); + break; + case MixN1: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case MixN2: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case MixN3: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case MixN4: + next(); + break; + case Cp: + if (!parseChoiceSeq()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Cp2: + next(); + break; + case WsD: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a NotationDecl [82]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'N' of '<!NOTATION' +*/ +bool QXmlSimpleReaderPrivate::parseNotationDecl() +{ + const signed char Init = 0; + const signed char Not = 1; // read NOTATION + const signed char Ws1 = 2; // eat whitespaces + const signed char Nam = 3; // read Name + const signed char Ws2 = 4; // eat whitespaces + const signed char ExtID = 5; // parse ExternalID + const signed char ExtIDR = 6; // same as ExtID, but already reported + const signed char Ws3 = 7; // eat whitespaces + const signed char Done = 8; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpN = 2; // N + const signed char InpUnknown = 3; + + static const signed char table[8][4] = { + /* InpWs InpGt InpN InpUnknown */ + { -1, -1, Not, -1 }, // Init + { Ws1, -1, -1, -1 }, // Not + { -1, -1, Nam, Nam }, // Ws1 + { Ws2, Done, -1, -1 }, // Nam + { -1, Done, ExtID, ExtID }, // Ws2 + { Ws3, Done, -1, -1 }, // ExtID + { Ws3, Done, -1, -1 }, // ExtIDR + { -1, Done, -1, -1 } // Ws3 + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseNotationDecl (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case ExtID: + // call the handler + if (dtdHnd) { + if (!dtdHnd->notationDecl(name(), publicId, systemId)) { + reportParseError(dtdHnd->errorString()); + return false; + } + } + state = ExtIDR; + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (c == QLatin1Char('N')) { + input = InpN; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Not: + parseString_s = QLatin1String("NOTATION"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case Ws1: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case Nam: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case Ws2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case ExtID: + case ExtIDR: + parseExternalID_allowPublicID = true; + if (!parseExternalID()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case Ws3: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse choice [49] or seq [50]. + + Precondition: the beginning '('S? is already read and the head + stands on the first non-whitespace character after it. +*/ +bool QXmlSimpleReaderPrivate::parseChoiceSeq() +{ + const signed char Init = 0; + const signed char Ws1 = 1; // eat whitespace + const signed char CoS = 2; // choice or set + const signed char Ws2 = 3; // eat whitespace + const signed char More = 4; // more cp to read + const signed char Name = 5; // read name + const signed char Done = 6; // + + const signed char InpWs = 0; // S + const signed char InpOp = 1; // ( + const signed char InpCp = 2; //) + const signed char InpQm = 3; // ? + const signed char InpAst = 4; // * + const signed char InpPlus = 5; // + + const signed char InpPipe = 6; // | + const signed char InpComm = 7; // , + const signed char InpUnknown = 8; + + static const signed char table[6][9] = { + /* InpWs InpOp InpCp InpQm InpAst InpPlus InpPipe InpComm InpUnknown */ + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // Init + { -1, CoS, -1, -1, -1, -1, -1, -1, CoS }, // Ws1 + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 }, // CS + { -1, -1, Done, -1, -1, -1, More, More, -1 }, // Ws2 + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // More (same as Init) + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 } // Name (same as CS) + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseChoiceSeq (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('(')) { + input = InpOp; + } else if (c == QLatin1Char(')')) { + input = InpCp; + } else if (c == QLatin1Char('?')) { + input = InpQm; + } else if (c == QLatin1Char('*')) { + input = InpAst; + } else if (c == QLatin1Char('+')) { + input = InpPlus; + } else if (c == QLatin1Char('|')) { + input = InpPipe; + } else if (c == QLatin1Char(',')) { + input = InpComm; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Ws1: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + break; + case CoS: + if (!parseChoiceSeq()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + break; + case Ws2: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + break; + case More: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + break; + case Name: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a EntityDecl [70]. + + Precondition: the beginning '<!E' is already read and the head + stand on the 'N' of '<!ENTITY' +*/ +bool QXmlSimpleReaderPrivate::parseEntityDecl() +{ + const signed char Init = 0; + const signed char Ent = 1; // parse "ENTITY" + const signed char Ws1 = 2; // white space read + const signed char Name = 3; // parse name + const signed char Ws2 = 4; // white space read + const signed char EValue = 5; // parse entity value + const signed char EValueR = 6; // same as EValue, but already reported + const signed char ExtID = 7; // parse ExternalID + const signed char Ws3 = 8; // white space read + const signed char Ndata = 9; // parse "NDATA" + const signed char Ws4 = 10; // white space read + const signed char NNam = 11; // parse name + const signed char NNamR = 12; // same as NNam, but already reported + const signed char PEDec = 13; // parse PEDecl + const signed char Ws6 = 14; // white space read + const signed char PENam = 15; // parse name + const signed char Ws7 = 16; // white space read + const signed char PEVal = 17; // parse entity value + const signed char PEValR = 18; // same as PEVal, but already reported + const signed char PEEID = 19; // parse ExternalID + const signed char PEEIDR = 20; // same as PEEID, but already reported + const signed char WsE = 21; // white space read + const signed char Done = 22; + const signed char EDDone = 23; // done, but also report an external, unparsed entity decl + + const signed char InpWs = 0; // white space + const signed char InpPer = 1; // % + const signed char InpQuot = 2; // " or ' + const signed char InpGt = 3; // > + const signed char InpN = 4; // N + const signed char InpUnknown = 5; + + static const signed char table[22][6] = { + /* InpWs InpPer InpQuot InpGt InpN InpUnknown */ + { -1, -1, -1, -1, Ent, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1 }, // Ent + { -1, PEDec, -1, -1, Name, Name }, // Ws1 + { Ws2, -1, -1, -1, -1, -1 }, // Name + { -1, -1, EValue, -1, -1, ExtID }, // Ws2 + { WsE, -1, -1, Done, -1, -1 }, // EValue + { WsE, -1, -1, Done, -1, -1 }, // EValueR + { Ws3, -1, -1, EDDone,-1, -1 }, // ExtID + { -1, -1, -1, EDDone,Ndata, -1 }, // Ws3 + { Ws4, -1, -1, -1, -1, -1 }, // Ndata + { -1, -1, -1, -1, NNam, NNam }, // Ws4 + { WsE, -1, -1, Done, -1, -1 }, // NNam + { WsE, -1, -1, Done, -1, -1 }, // NNamR + { Ws6, -1, -1, -1, -1, -1 }, // PEDec + { -1, -1, -1, -1, PENam, PENam }, // Ws6 + { Ws7, -1, -1, -1, -1, -1 }, // PENam + { -1, -1, PEVal, -1, -1, PEEID }, // Ws7 + { WsE, -1, -1, Done, -1, -1 }, // PEVal + { WsE, -1, -1, Done, -1, -1 }, // PEValR + { WsE, -1, -1, Done, -1, -1 }, // PEEID + { WsE, -1, -1, Done, -1, -1 }, // PEEIDR + { -1, -1, -1, Done, -1, -1 } // WsE + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseEntityDecl (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case EValue: + if ( !entityExist(name())) { + entities.insert(name(), string()); + if (declHnd) { + if (!declHnd->internalEntityDecl(name(), string())) { + reportParseError(declHnd->errorString()); + return false; + } + } + } + state = EValueR; + break; + case NNam: + if ( !entityExist(name())) { + externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, ref())); + if (dtdHnd) { + if (!dtdHnd->unparsedEntityDecl(name(), publicId, systemId, ref())) { + reportParseError(declHnd->errorString()); + return false; + } + } + } + state = NNamR; + break; + case PEVal: + if ( !entityExist(name())) { + parameterEntities.insert(name(), string()); + if (declHnd) { + if (!declHnd->internalEntityDecl(QString::fromLatin1("%")+name(), string())) { + reportParseError(declHnd->errorString()); + return false; + } + } + } + state = PEValR; + break; + case PEEID: + if ( !entityExist(name())) { + externParameterEntities.insert(name(), QXmlSimpleReaderPrivate::ExternParameterEntity(publicId, systemId)); + if (declHnd) { + if (!declHnd->externalEntityDecl(QString::fromLatin1("%")+name(), publicId, systemId)) { + reportParseError(declHnd->errorString()); + return false; + } + } + } + state = PEEIDR; + break; + case EDDone: + if ( !entityExist(name())) { + externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, QString())); + if (declHnd) { + if (!declHnd->externalEntityDecl(name(), publicId, systemId)) { + reportParseError(declHnd->errorString()); + return false; + } + } + } + return true; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + if (is_S(c)) { + input = InpWs; + } else if (c == QLatin1Char('%')) { + input = InpPer; + } else if (c == QLatin1Char('"') || c == QLatin1Char('\'')) { + input = InpQuot; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else if (c == QLatin1Char('N')) { + input = InpN; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Ent: + parseString_s = QLatin1String("NTITY"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ws1: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Name: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ws2: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case EValue: + case EValueR: + if (!parseEntityValue()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case ExtID: + parseExternalID_allowPublicID = false; + if (!parseExternalID()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ws3: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ndata: + parseString_s = QLatin1String("NDATA"); + if (!parseString()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ws4: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case NNam: + case NNamR: + parseName_useRef = true; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case PEDec: + next(); + break; + case Ws6: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case PENam: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case Ws7: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case PEVal: + case PEValR: + if (!parseEntityValue()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case PEEID: + case PEEIDR: + parseExternalID_allowPublicID = false; + if (!parseExternalID()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case WsE: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state); + return false; + } + break; + case EDDone: + next(); + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a EntityValue [9] +*/ +bool QXmlSimpleReaderPrivate::parseEntityValue() +{ + const signed char Init = 0; + const signed char Dq = 1; // EntityValue is double quoted + const signed char DqC = 2; // signed character + const signed char DqPER = 3; // PERefence + const signed char DqRef = 4; // Reference + const signed char Sq = 5; // EntityValue is double quoted + const signed char SqC = 6; // signed character + const signed char SqPER = 7; // PERefence + const signed char SqRef = 8; // Reference + const signed char Done = 9; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpPer = 3; // % + const signed char InpUnknown = 4; + + static const signed char table[9][5] = { + /* InpDq InpSq InpAmp InpPer InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, DqPER, DqC }, // Dq + { Done, DqC, DqRef, DqPER, DqC }, // DqC + { Done, DqC, DqRef, DqPER, DqC }, // DqPER + { Done, DqC, DqRef, DqPER, DqC }, // DqRef + { SqC, Done, SqRef, SqPER, SqC }, // Sq + { SqC, Done, SqRef, SqPER, SqC }, // SqC + { SqC, Done, SqRef, SqPER, SqC }, // SqPER + { SqC, Done, SqRef, SqPER, SqC } // SqRef + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseEntityValue (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityValue, state); + return false; + } + if (c == QLatin1Char('"')) { + input = InpDq; + } else if (c == QLatin1Char('\'')) { + input = InpSq; + } else if (c == QLatin1Char('&')) { + input = InpAmp; + } else if (c == QLatin1Char('%')) { + input = InpPer; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case DqPER: + case SqPER: + parsePEReference_context = InEntityValue; + if (!parsePEReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state); + return false; + } + break; + case DqRef: + case SqRef: + parseReference_context = InEntityValue; + if (!parseReference()) { + parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state); + return false; + } + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse a comment [15]. + + Precondition: the beginning '<!' of the comment is already read and the head + stands on the first '-' of '<!--'. + + If this funktion was successful, the head-position is on the first + character after the comment. +*/ +bool QXmlSimpleReaderPrivate::parseComment() +{ + const signed char Init = 0; + const signed char Dash1 = 1; // the first dash was read + const signed char Dash2 = 2; // the second dash was read + const signed char Com = 3; // read comment + const signed char Com2 = 4; // read comment (help state) + const signed char ComE = 5; // finished reading comment + const signed char Done = 6; + + const signed char InpDash = 0; // - + const signed char InpGt = 1; // > + const signed char InpUnknown = 2; + + static const signed char table[6][3] = { + /* InpDash InpGt InpUnknown */ + { Dash1, -1, -1 }, // Init + { Dash2, -1, -1 }, // Dash1 + { Com2, Com, Com }, // Dash2 + { Com2, Com, Com }, // Com + { ComE, Com, Com }, // Com2 + { -1, Done, -1 } // ComE + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseComment (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseComment, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Dash2: + stringClear(); + break; + case Com2: + // if next character is not a dash than don't skip it + if (!atEnd() && c != QLatin1Char('-')) + stringAddC(QLatin1Char('-')); + break; + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_ERRORPARSINGCOMMENT)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseComment, state); + return false; + } + if (c == QLatin1Char('-')) { + input = InpDash; + } else if (c == QLatin1Char('>')) { + input = InpGt; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case Dash1: + next(); + break; + case Dash2: + next(); + break; + case Com: + stringAddC(); + next(); + break; + case Com2: + next(); + break; + case ComE: + next(); + break; + case Done: + next(); + break; + } + } + return false; +} + +/* + Parse an Attribute [41]. + + Precondition: the head stands on the first character of the name + of the attribute (i.e. all whitespaces are already parsed). + + The head stand on the next character after the end quotes. The + variable name contains the name of the attribute and the variable + string contains the value of the attribute. +*/ +bool QXmlSimpleReaderPrivate::parseAttribute() +{ + const int Init = 0; + const int PName = 1; // parse name + const int Ws = 2; // eat ws + const int Eq = 3; // the '=' was read + const int Quotes = 4; // " or ' were read + + const int InpNameBe = 0; + const int InpEq = 1; // = + const int InpDq = 2; // " + const int InpSq = 3; // ' + const int InpUnknown = 4; + + static const int table[4][5] = { + /* InpNameBe InpEq InpDq InpSq InpUnknown */ + { PName, -1, -1, -1, -1 }, // Init + { -1, Eq, -1, -1, Ws }, // PName + { -1, Eq, -1, -1, -1 }, // Ws + { -1, -1, Quotes, Quotes, -1 } // Eq + }; + int state; + int input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseAttribute (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Quotes: + // Done + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + if (determineNameChar(c) == NameBeginning) { + input = InpNameBe; + } else if (c == QLatin1Char('=')) { + input = InpEq; + } else if (c == QLatin1Char('"')) { + input = InpDq; + } else if (c == QLatin1Char('\'')) { + input = InpSq; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case PName: + parseName_useRef = false; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + break; + case Ws: + if (!eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + break; + case Eq: + if (!next_eat_ws()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + break; + case Quotes: + if (!parseAttValue()) { + parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state); + return false; + } + break; + } + } + return false; +} + +/* + Parse a Name [5] and store the name in name or ref (if useRef is true). +*/ +bool QXmlSimpleReaderPrivate::parseName() +{ + const int Init = 0; + const int Name1 = 1; // parse first character of the name + const int Name = 2; // parse name + const int Done = 3; + + static const int table[3][3] = { + /* InpNameBe InpNameCh InpUnknown */ + { Name1, -1, -1 }, // Init + { Name, Name, Done }, // Name1 + { Name, Name, Done } // Name + }; + int state; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseName (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseName, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseName, state); + return false; + } + + // we can safely do the (int) cast thanks to the Q_ASSERTs earlier in this function + state = table[state][(int)fastDetermineNameChar(c)]; + + switch (state) { + case Name1: + if (parseName_useRef) { + refClear(); + refAddC(); + } else { + nameClear(); + nameAddC(); + } + next(); + break; + case Name: + if (parseName_useRef) { + refAddC(); + } else { + nameAddC(); + } + next(); + break; + } + } + return false; +} + +/* + Parse a Nmtoken [7] and store the name in name. +*/ +bool QXmlSimpleReaderPrivate::parseNmtoken() +{ + const signed char Init = 0; + const signed char NameF = 1; + const signed char Name = 2; + const signed char Done = 3; + + const signed char InpNameCh = 0; // NameChar without InpNameBe + const signed char InpUnknown = 1; + + static const signed char table[3][2] = { + /* InpNameCh InpUnknown */ + { NameF, -1 }, // Init + { Name, Done }, // NameF + { Name, Done } // Name + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseNmtoken (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseNmtoken, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case Done: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_LETTEREXPECTED)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseNmtoken, state); + return false; + } + if (determineNameChar(c) == NotName) { + input = InpUnknown; + } else { + input = InpNameCh; + } + state = table[state][input]; + + switch (state) { + case NameF: + nameClear(); + nameAddC(); + next(); + break; + case Name: + nameAddC(); + next(); + break; + } + } + return false; +} + +/* + Parse a Reference [67]. + + parseReference_charDataRead is set to true if the reference must not be + parsed. The character(s) which the reference mapped to are appended to + string. The head stands on the first character after the reference. + + parseReference_charDataRead is set to false if the reference must be parsed. + The charachter(s) which the reference mapped to are inserted at the reference + position. The head stands on the first character of the replacement). +*/ +bool QXmlSimpleReaderPrivate::parseReference() +{ + // temporary variables (only used in very local context, so they don't + // interfere with incremental parsing) + uint tmp; + bool ok; + + const signed char Init = 0; + const signed char SRef = 1; // start of a reference + const signed char ChRef = 2; // parse CharRef + const signed char ChDec = 3; // parse CharRef decimal + const signed char ChHexS = 4; // start CharRef hexadecimal + const signed char ChHex = 5; // parse CharRef hexadecimal + const signed char Name = 6; // parse name + const signed char DoneD = 7; // done CharRef decimal + const signed char DoneH = 8; // done CharRef hexadecimal + const signed char DoneN = 9; // done EntityRef + + const signed char InpAmp = 0; // & + const signed char InpSemi = 1; // ; + const signed char InpHash = 2; // # + const signed char InpX = 3; // x + const signed char InpNum = 4; // 0-9 + const signed char InpHex = 5; // a-f A-F + const signed char InpUnknown = 6; + + static const signed char table[8][7] = { + /* InpAmp InpSemi InpHash InpX InpNum InpHex InpUnknown */ + { SRef, -1, -1, -1, -1, -1, -1 }, // Init + { -1, -1, ChRef, Name, Name, Name, Name }, // SRef + { -1, -1, -1, ChHexS, ChDec, -1, -1 }, // ChRef + { -1, DoneD, -1, -1, ChDec, -1, -1 }, // ChDec + { -1, -1, -1, -1, ChHex, ChHex, -1 }, // ChHexS + { -1, DoneH, -1, -1, ChHex, ChHex, -1 }, // ChHex + { -1, DoneN, -1, -1, -1, -1, -1 } // Name + }; + signed char state; + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + parseReference_charDataRead = false; + state = Init; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseReference (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseReference, state); + return false; + } + } + } + + for (;;) { + switch (state) { + case DoneD: + return true; + case DoneH: + return true; + case DoneN: + return true; + case -1: + // Error + reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE)); + return false; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseReference, state); + return false; + } + if (c.row()) { + input = InpUnknown; + } else if (c.cell() == '&') { + input = InpAmp; + } else if (c.cell() == ';') { + input = InpSemi; + } else if (c.cell() == '#') { + input = InpHash; + } else if (c.cell() == 'x') { + input = InpX; + } else if ('0' <= c.cell() && c.cell() <= '9') { + input = InpNum; + } else if ('a' <= c.cell() && c.cell() <= 'f') { + input = InpHex; + } else if ('A' <= c.cell() && c.cell() <= 'F') { + input = InpHex; + } else { + input = InpUnknown; + } + state = table[state][input]; + + switch (state) { + case SRef: + refClear(); + next(); + break; + case ChRef: + next(); + break; + case ChDec: + refAddC(); + next(); + break; + case ChHexS: + next(); + break; + case ChHex: + refAddC(); + next(); + break; + case Name: + // read the name into the ref + parseName_useRef = true; + if (!parseName()) { + parseFailed(&QXmlSimpleReaderPrivate::parseReference, state); + return false; + } + break; + case DoneD: + tmp = ref().toUInt(&ok, 10); + if (ok) { + stringAddC(QChar(tmp)); + } else { + reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE)); + return false; + } + parseReference_charDataRead = true; + next(); + break; + case DoneH: + tmp = ref().toUInt(&ok, 16); + if (ok) { + stringAddC(QChar(tmp)); + } else { + reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE)); + return false; + } + parseReference_charDataRead = true; + next(); + break; + case DoneN: + if (!processReference()) + return false; + next(); + break; + } + } + return false; +} + +/* + Helper function for parseReference() +*/ +bool QXmlSimpleReaderPrivate::processReference() +{ + QString reference = ref(); + if (reference == QLatin1String("amp")) { + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('m')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char(';')); + } else { + // Included or Included in literal + stringAddC(QLatin1Char('&')); + } + parseReference_charDataRead = true; + } else if (reference == QLatin1String("lt")) { + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('l')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';')); + } else { + // Included or Included in literal + stringAddC(QLatin1Char('<')); + } + parseReference_charDataRead = true; + } else if (reference == QLatin1String("gt")) { + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('g')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';')); + } else { + // Included or Included in literal + stringAddC(QLatin1Char('>')); + } + parseReference_charDataRead = true; + } else if (reference == QLatin1String("apos")) { + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('s')); stringAddC(QLatin1Char(';')); + } else { + // Included or Included in literal + stringAddC(QLatin1Char('\'')); + } + parseReference_charDataRead = true; + } else if (reference == QLatin1String("quot")) { + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('q')); stringAddC(QLatin1Char('u')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';')); + } else { + // Included or Included in literal + stringAddC(QLatin1Char('"')); + } + parseReference_charDataRead = true; + } else { + QMap<QString,QString>::Iterator it; + it = entities.find(reference); + if (it != entities.end()) { + // "Internal General" + switch (parseReference_context) { + case InContent: + // Included + if (!insertXmlRef(*it, reference, false)) + return false; + parseReference_charDataRead = false; + break; + case InAttributeValue: + // Included in literal + if (!insertXmlRef(*it, reference, true)) + return false; + parseReference_charDataRead = false; + break; + case InEntityValue: + { + // Bypassed + stringAddC(QLatin1Char('&')); + for (int i=0; i<(int)reference.length(); i++) { + stringAddC(reference[i]); + } + stringAddC(QLatin1Char(';')); + parseReference_charDataRead = true; + } + break; + case InDTD: + // Forbidden + parseReference_charDataRead = false; + reportParseError(QLatin1String(XMLERR_INTERNALGENERALENTITYINDTD)); + return false; + } + } else { + QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern; + itExtern = externEntities.find(reference); + if (itExtern == externEntities.end()) { + // entity not declared + // ### check this case for conformance + if (parseReference_context == InEntityValue) { + // Bypassed + stringAddC(QLatin1Char('&')); + for (int i=0; i<(int)reference.length(); i++) { + stringAddC(reference[i]); + } + stringAddC(QLatin1Char(';')); + parseReference_charDataRead = true; + } else { + // if we have some char data read, report it now + if (parseReference_context == InContent) { + if (contentCharDataRead) { + if (reportWhitespaceCharData || !string().simplified().isEmpty()) { + if (contentHnd != 0 && !contentHnd->characters(string())) { + reportParseError(contentHnd->errorString()); + return false; + } + } + stringClear(); + contentCharDataRead = false; + } + } + + if (contentHnd) { + qt_xml_skipped_entity_in_content = parseReference_context == InContent; + if (!contentHnd->skippedEntity(reference)) { + qt_xml_skipped_entity_in_content = false; + reportParseError(contentHnd->errorString()); + return false; // error + } + qt_xml_skipped_entity_in_content = false; + } + } + } else if ((*itExtern).notation.isNull()) { + // "External Parsed General" + switch (parseReference_context) { + case InContent: + { + // Included if validating + bool skipIt = true; + if (entityRes) { + QXmlInputSource *ret = 0; + if (!entityRes->resolveEntity((*itExtern).publicId, (*itExtern).systemId, ret)) { + delete ret; + reportParseError(entityRes->errorString()); + return false; + } + if (ret) { + QString xmlRefString = ret->data(); + delete ret; + if (!stripTextDecl(xmlRefString)) { + reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL)); + return false; + } + if (!insertXmlRef(xmlRefString, reference, false)) + return false; + skipIt = false; + } + } + if (skipIt && contentHnd) { + qt_xml_skipped_entity_in_content = true; + if (!contentHnd->skippedEntity(reference)) { + qt_xml_skipped_entity_in_content = false; + reportParseError(contentHnd->errorString()); + return false; // error + } + qt_xml_skipped_entity_in_content = false; + } + parseReference_charDataRead = false; + } break; + case InAttributeValue: + // Forbidden + parseReference_charDataRead = false; + reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINAV)); + return false; + case InEntityValue: + { + // Bypassed + stringAddC(QLatin1Char('&')); + for (int i=0; i<(int)reference.length(); i++) { + stringAddC(reference[i]); + } + stringAddC(QLatin1Char(';')); + parseReference_charDataRead = true; + } + break; + case InDTD: + // Forbidden + parseReference_charDataRead = false; + reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINDTD)); + return false; + } + } else { + // "Unparsed" + // ### notify for "Occurs as Attribute Value" missing (but this is no refence, anyway) + // Forbidden + parseReference_charDataRead = false; + reportParseError(QLatin1String(XMLERR_UNPARSEDENTITYREFERENCE)); + return false; // error + } + } + } + return true; // no error +} + + +/* + Parses over a simple string. + + After the string was successfully parsed, the head is on the first + character after the string. +*/ +bool QXmlSimpleReaderPrivate::parseString() +{ + const signed char InpCharExpected = 0; // the character that was expected + const signed char InpUnknown = 1; + + signed char state; // state in this function is the position in the string s + signed char input; + + if (parseStack==0 || parseStack->isEmpty()) { + Done = parseString_s.length(); + state = 0; + } else { + state = parseStack->pop().state; +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: parseString (cont) in state %d", state); +#endif + if (!parseStack->isEmpty()) { + ParseFunction function = parseStack->top().function; + if (function == &QXmlSimpleReaderPrivate::eat_ws) { + parseStack->pop(); +#if defined(QT_QXML_DEBUG) + qDebug("QXmlSimpleReader: eat_ws (cont)"); +#endif + } + if (!(this->*function)()) { + parseFailed(&QXmlSimpleReaderPrivate::parseString, state); + return false; + } + } + } + + for (;;) { + if (state == Done) { + return true; + } + + if (atEnd()) { + unexpectedEof(&QXmlSimpleReaderPrivate::parseString, state); + return false; + } + if (c == parseString_s[(int)state]) { + input = InpCharExpected; + } else { + input = InpUnknown; + } + if (input == InpCharExpected) { + state++; + } else { + // Error + reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER)); + return false; + } + + next(); + } + return false; +} + +/* + This private function inserts and reports an entity substitution. The + substituted string is \a data and the name of the entity reference is \a + name. If \a inLiteral is true, the entity is IncludedInLiteral (i.e., " and ' + must be quoted. Otherwise they are not quoted. + + This function returns false on error. +*/ +bool QXmlSimpleReaderPrivate::insertXmlRef(const QString &data, const QString &name, bool inLiteral) +{ + if (inLiteral) { + QString tmp = data; + xmlRefStack.push(XmlRef(name, tmp.replace(QLatin1String("\""), + QLatin1String(""")).replace(QLatin1String("'"), QLatin1String("'")))); + } else { + xmlRefStack.push(XmlRef(name, data)); + } + int n = qMax(parameterEntities.count(), entities.count()); + if (xmlRefStack.count() > n+1) { + // recursive entities + reportParseError(QLatin1String(XMLERR_RECURSIVEENTITIES)); + return false; + } + if (reportEntities && lexicalHnd) { + if (!lexicalHnd->startEntity(name)) { + reportParseError(lexicalHnd->errorString()); + return false; + } + } + return true; +} + +/* + This private function moves the cursor to the next character. +*/ +void QXmlSimpleReaderPrivate::next() +{ + int count = xmlRefStack.size(); + while (count != 0) { + if (xmlRefStack.top().isEmpty()) { + xmlRefStack.pop_back(); + count--; + } else { + c = xmlRefStack.top().next(); + return; + } + } + + // the following could be written nicer, but since it is a time-critical + // function, rather optimize for speed + ushort uc = c.unicode(); + c = inputSource->next(); + // If we are not incremental parsing, we just skip over EndOfData chars to give the + // parser an uninterrupted stream of document chars. + if (c == QXmlInputSource::EndOfData && parseStack == 0) + c = inputSource->next(); + if (uc == '\n') { + lineNr++; + columnNr = -1; + } else if (uc == '\r') { + if (c != QLatin1Char('\n')) { + lineNr++; + columnNr = -1; + } + } + ++columnNr; +} + +/* + This private function moves the cursor to the next non-whitespace character. + This function does not move the cursor if the actual cursor position is a + non-whitespace charcter. + + Returns false when you use incremental parsing and this function reaches EOF + with reading only whitespace characters. In this case it also poplulates the + parseStack with useful information. In all other cases, this function returns + true. +*/ +bool QXmlSimpleReaderPrivate::eat_ws() +{ + while (!atEnd()) { + if (!is_S(c)) { + return true; + } + next(); + } + if (parseStack != 0) { + unexpectedEof(&QXmlSimpleReaderPrivate::eat_ws, 0); + return false; + } + return true; +} + +bool QXmlSimpleReaderPrivate::next_eat_ws() +{ + next(); + return eat_ws(); +} + + +/* + This private function initializes the reader. \a i is the input source to + read the data from. +*/ +void QXmlSimpleReaderPrivate::init(const QXmlInputSource *i) +{ + lineNr = 0; + columnNr = -1; + inputSource = const_cast<QXmlInputSource *>(i); + initData(); + + externParameterEntities.clear(); + parameterEntities.clear(); + externEntities.clear(); + entities.clear(); + + tags.clear(); + + doctype.clear(); + xmlVersion.clear(); + encoding.clear(); + standalone = QXmlSimpleReaderPrivate::Unknown; + error.clear(); +} + +/* + This private function initializes the XML data related variables. Especially, + it reads the data from the input source. +*/ +void QXmlSimpleReaderPrivate::initData() +{ + c = QXmlInputSource::EndOfData; + xmlRefStack.clear(); + next(); +} + +/* + Returns true if a entity with the name \a e exists, + otherwise returns false. +*/ +bool QXmlSimpleReaderPrivate::entityExist(const QString& e) const +{ + if ( parameterEntities.find(e) == parameterEntities.end() && + externParameterEntities.find(e) == externParameterEntities.end() && + externEntities.find(e) == externEntities.end() && + entities.find(e) == entities.end()) { + return false; + } else { + return true; + } +} + +void QXmlSimpleReaderPrivate::reportParseError(const QString& error) +{ + this->error = error; + if (errorHnd) { + if (this->error.isNull()) { + const QXmlParseException ex(QLatin1String(XMLERR_OK), columnNr+1, lineNr+1, + thisPublicId, thisSystemId); + errorHnd->fatalError(ex); + } else { + const QXmlParseException ex(this->error, columnNr+1, lineNr+1, + thisPublicId, thisSystemId); + errorHnd->fatalError(ex); + } + } +} + +/* + This private function is called when a parsing function encounters an + unexpected EOF. It decides what to do (depending on incremental parsing or + not). \a where is a pointer to the function where the error occurred and \a + state is the parsing state in this function. +*/ +void QXmlSimpleReaderPrivate::unexpectedEof(ParseFunction where, int state) +{ + if (parseStack == 0) { + reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF)); + } else { + if (c == QXmlInputSource::EndOfDocument) { + reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF)); + } else { + pushParseState(where, state); + } + } +} + +/* + This private function is called when a parse...() function returned false. It + determines if there was an error or if incremental parsing simply went out of + data and does the right thing for the case. \a where is a pointer to the + function where the error occurred and \a state is the parsing state in this + function. +*/ +void QXmlSimpleReaderPrivate::parseFailed(ParseFunction where, int state) +{ + if (parseStack!=0 && error.isNull()) { + pushParseState(where, state); + } +} + +/* + This private function pushes the function pointer \a function and state \a + state to the parse stack. This is used when you are doing an incremental + parsing and reach the end of file too early. + + Only call this function when d->parseStack!=0. +*/ +void QXmlSimpleReaderPrivate::pushParseState(ParseFunction function, int state) +{ + QXmlSimpleReaderPrivate::ParseState ps; + ps.function = function; + ps.state = state; + parseStack->push(ps); +} + +inline static void updateValue(QString &value, const QChar *array, int &arrayPos, int &valueLen) +{ + value.resize(valueLen + arrayPos); + memcpy(value.data() + valueLen, array, arrayPos * sizeof(QChar)); + valueLen += arrayPos; + arrayPos = 0; +} + +// use buffers instead of QString::operator+= when single characters are read +const QString& QXmlSimpleReaderPrivate::string() +{ + updateValue(stringValue, stringArray, stringArrayPos, stringValueLen); + return stringValue; +} +const QString& QXmlSimpleReaderPrivate::name() +{ + updateValue(nameValue, nameArray, nameArrayPos, nameValueLen); + return nameValue; +} +const QString& QXmlSimpleReaderPrivate::ref() +{ + updateValue(refValue, refArray, refArrayPos, refValueLen); + return refValue; +} + +void QXmlSimpleReaderPrivate::stringAddC(QChar ch) +{ + if (stringArrayPos == 256) + updateValue(stringValue, stringArray, stringArrayPos, stringValueLen); + stringArray[stringArrayPos++] = ch; +} +void QXmlSimpleReaderPrivate::nameAddC(QChar ch) +{ + if (nameArrayPos == 256) + updateValue(nameValue, nameArray, nameArrayPos, nameValueLen); + nameArray[nameArrayPos++] = ch; +} +void QXmlSimpleReaderPrivate::refAddC(QChar ch) +{ + if (refArrayPos == 256) + updateValue(refValue, refArray, refArrayPos, refValueLen); + refArray[refArrayPos++] = ch; +} +QT_END_NAMESPACE diff --git a/src/xml/sax/qxml.h b/src/xml/sax/qxml.h new file mode 100644 index 0000000..e0165d3 --- /dev/null +++ b/src/xml/sax/qxml.h @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXml 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 QXML_H +#define QXML_H + +#include <QtCore/qtextstream.h> +#include <QtCore/qfile.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qlist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Xml) + +class QXmlNamespaceSupport; +class QXmlAttributes; +class QXmlContentHandler; +class QXmlDefaultHandler; +class QXmlDTDHandler; +class QXmlEntityResolver; +class QXmlErrorHandler; +class QXmlLexicalHandler; +class QXmlDeclHandler; +class QXmlInputSource; +class QXmlLocator; +class QXmlNamespaceSupport; +class QXmlParseException; + +class QXmlReader; +class QXmlSimpleReader; + +class QXmlSimpleReaderPrivate; +class QXmlNamespaceSupportPrivate; +class QXmlAttributesPrivate; +class QXmlInputSourcePrivate; +class QXmlParseExceptionPrivate; +class QXmlLocatorPrivate; +class QXmlDefaultHandlerPrivate; + + +// +// SAX Namespace Support +// + +class Q_XML_EXPORT QXmlNamespaceSupport +{ +public: + QXmlNamespaceSupport(); + ~QXmlNamespaceSupport(); + + void setPrefix(const QString&, const QString&); + + QString prefix(const QString&) const; + QString uri(const QString&) const; + void splitName(const QString&, QString&, QString&) const; + void processName(const QString&, bool, QString&, QString&) const; + QStringList prefixes() const; + QStringList prefixes(const QString&) const; + + void pushContext(); + void popContext(); + void reset(); + +private: + QXmlNamespaceSupportPrivate *d; + + friend class QXmlSimpleReaderPrivate; + Q_DISABLE_COPY(QXmlNamespaceSupport) +}; + + +// +// SAX Attributes +// + +class Q_XML_EXPORT QXmlAttributes +{ +public: + QXmlAttributes() {} + virtual ~QXmlAttributes() {} + + int index(const QString& qName) const; + int index(const QLatin1String& qName) const; + int index(const QString& uri, const QString& localPart) const; + int length() const; + int count() const; + QString localName(int index) const; + QString qName(int index) const; + QString uri(int index) const; + QString type(int index) const; + QString type(const QString& qName) const; + QString type(const QString& uri, const QString& localName) const; + QString value(int index) const; + QString value(const QString& qName) const; + QString value(const QLatin1String& qName) const; + QString value(const QString& uri, const QString& localName) const; + + void clear(); + void append(const QString &qName, const QString &uri, const QString &localPart, const QString &value); + +private: + struct Attribute { + QString qname, uri, localname, value; + }; + typedef QList<Attribute> AttributeList; + AttributeList attList; + + QXmlAttributesPrivate *d; +}; + +// +// SAX Input Source +// + +class Q_XML_EXPORT QXmlInputSource +{ +public: + QXmlInputSource(); + QXmlInputSource(QIODevice *dev); + virtual ~QXmlInputSource(); + + virtual void setData(const QString& dat); + virtual void setData(const QByteArray& dat); + virtual void fetchData(); + virtual QString data() const; + virtual QChar next(); + virtual void reset(); + + static const ushort EndOfData; + static const ushort EndOfDocument; + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QXmlInputSource(QFile& file); + QT3_SUPPORT_CONSTRUCTOR QXmlInputSource(QTextStream& stream); +#endif + +protected: + virtual QString fromRawData(const QByteArray &data, bool beginning = false); + +private: + void init(); + QXmlInputSourcePrivate *d; +}; + +// +// SAX Exception Classes +// + +class Q_XML_EXPORT QXmlParseException +{ +public: + explicit QXmlParseException(const QString &name = QString(), int c = -1, int l = -1, + const QString &p = QString(), const QString &s = QString()); + ~QXmlParseException(); + + int columnNumber() const; + int lineNumber() const; + QString publicId() const; + QString systemId() const; + QString message() const; + +private: + QXmlParseExceptionPrivate *d; +}; + + +// +// XML Reader +// + +class Q_XML_EXPORT QXmlReader +{ +public: + virtual ~QXmlReader() {} + virtual bool feature(const QString& name, bool *ok = 0) const = 0; + virtual void setFeature(const QString& name, bool value) = 0; + virtual bool hasFeature(const QString& name) const = 0; + virtual void* property(const QString& name, bool *ok = 0) const = 0; + virtual void setProperty(const QString& name, void* value) = 0; + virtual bool hasProperty(const QString& name) const = 0; + virtual void setEntityResolver(QXmlEntityResolver* handler) = 0; + virtual QXmlEntityResolver* entityResolver() const = 0; + virtual void setDTDHandler(QXmlDTDHandler* handler) = 0; + virtual QXmlDTDHandler* DTDHandler() const = 0; + virtual void setContentHandler(QXmlContentHandler* handler) = 0; + virtual QXmlContentHandler* contentHandler() const = 0; + virtual void setErrorHandler(QXmlErrorHandler* handler) = 0; + virtual QXmlErrorHandler* errorHandler() const = 0; + virtual void setLexicalHandler(QXmlLexicalHandler* handler) = 0; + virtual QXmlLexicalHandler* lexicalHandler() const = 0; + virtual void setDeclHandler(QXmlDeclHandler* handler) = 0; + virtual QXmlDeclHandler* declHandler() const = 0; + virtual bool parse(const QXmlInputSource& input) = 0; + virtual bool parse(const QXmlInputSource* input) = 0; +}; + +class Q_XML_EXPORT QXmlSimpleReader : public QXmlReader +{ +public: + QXmlSimpleReader(); + virtual ~QXmlSimpleReader(); + + bool feature(const QString& name, bool *ok = 0) const; + void setFeature(const QString& name, bool value); + bool hasFeature(const QString& name) const; + + void* property(const QString& name, bool *ok = 0) const; + void setProperty(const QString& name, void* value); + bool hasProperty(const QString& name) const; + + void setEntityResolver(QXmlEntityResolver* handler); + QXmlEntityResolver* entityResolver() const; + void setDTDHandler(QXmlDTDHandler* handler); + QXmlDTDHandler* DTDHandler() const; + void setContentHandler(QXmlContentHandler* handler); + QXmlContentHandler* contentHandler() const; + void setErrorHandler(QXmlErrorHandler* handler); + QXmlErrorHandler* errorHandler() const; + void setLexicalHandler(QXmlLexicalHandler* handler); + QXmlLexicalHandler* lexicalHandler() const; + void setDeclHandler(QXmlDeclHandler* handler); + QXmlDeclHandler* declHandler() const; + + bool parse(const QXmlInputSource& input); + bool parse(const QXmlInputSource* input); + virtual bool parse(const QXmlInputSource* input, bool incremental); + virtual bool parseContinue(); + +private: + Q_DISABLE_COPY(QXmlSimpleReader) + Q_DECLARE_PRIVATE(QXmlSimpleReader) + QXmlSimpleReaderPrivate* d_ptr; + + friend class QXmlSimpleReaderLocator; +}; + +// +// SAX Locator +// + +class Q_XML_EXPORT QXmlLocator +{ +public: + QXmlLocator(); + virtual ~QXmlLocator(); + + virtual int columnNumber() const = 0; + virtual int lineNumber() const = 0; +// QString getPublicId() const +// QString getSystemId() const +}; + +// +// SAX handler classes +// + +class Q_XML_EXPORT QXmlContentHandler +{ +public: + virtual ~QXmlContentHandler() {} + virtual void setDocumentLocator(QXmlLocator* locator) = 0; + virtual bool startDocument() = 0; + virtual bool endDocument() = 0; + virtual bool startPrefixMapping(const QString& prefix, const QString& uri) = 0; + virtual bool endPrefixMapping(const QString& prefix) = 0; + virtual bool startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts) = 0; + virtual bool endElement(const QString& namespaceURI, const QString& localName, const QString& qName) = 0; + virtual bool characters(const QString& ch) = 0; + virtual bool ignorableWhitespace(const QString& ch) = 0; + virtual bool processingInstruction(const QString& target, const QString& data) = 0; + virtual bool skippedEntity(const QString& name) = 0; + virtual QString errorString() const = 0; +}; + +class Q_XML_EXPORT QXmlErrorHandler +{ +public: + virtual ~QXmlErrorHandler() {} + virtual bool warning(const QXmlParseException& exception) = 0; + virtual bool error(const QXmlParseException& exception) = 0; + virtual bool fatalError(const QXmlParseException& exception) = 0; + virtual QString errorString() const = 0; +}; + +class Q_XML_EXPORT QXmlDTDHandler +{ +public: + virtual ~QXmlDTDHandler() {} + virtual bool notationDecl(const QString& name, const QString& publicId, const QString& systemId) = 0; + virtual bool unparsedEntityDecl(const QString& name, const QString& publicId, const QString& systemId, const QString& notationName) = 0; + virtual QString errorString() const = 0; +}; + +class Q_XML_EXPORT QXmlEntityResolver +{ +public: + virtual ~QXmlEntityResolver() {} + virtual bool resolveEntity(const QString& publicId, const QString& systemId, QXmlInputSource*& ret) = 0; + virtual QString errorString() const = 0; +}; + +class Q_XML_EXPORT QXmlLexicalHandler +{ +public: + virtual ~QXmlLexicalHandler() {} + virtual bool startDTD(const QString& name, const QString& publicId, const QString& systemId) = 0; + virtual bool endDTD() = 0; + virtual bool startEntity(const QString& name) = 0; + virtual bool endEntity(const QString& name) = 0; + virtual bool startCDATA() = 0; + virtual bool endCDATA() = 0; + virtual bool comment(const QString& ch) = 0; + virtual QString errorString() const = 0; +}; + +class Q_XML_EXPORT QXmlDeclHandler +{ +public: + virtual ~QXmlDeclHandler() {} + virtual bool attributeDecl(const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value) = 0; + virtual bool internalEntityDecl(const QString& name, const QString& value) = 0; + virtual bool externalEntityDecl(const QString& name, const QString& publicId, const QString& systemId) = 0; + virtual QString errorString() const = 0; + // ### Qt 5: Conform to SAX by adding elementDecl +}; + + +class Q_XML_EXPORT QXmlDefaultHandler : public QXmlContentHandler, public QXmlErrorHandler, public QXmlDTDHandler, public QXmlEntityResolver, public QXmlLexicalHandler, public QXmlDeclHandler +{ +public: + QXmlDefaultHandler() { } + virtual ~QXmlDefaultHandler() { } + + void setDocumentLocator(QXmlLocator* locator); + bool startDocument(); + bool endDocument(); + bool startPrefixMapping(const QString& prefix, const QString& uri); + bool endPrefixMapping(const QString& prefix); + bool startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts); + bool endElement(const QString& namespaceURI, const QString& localName, const QString& qName); + bool characters(const QString& ch); + bool ignorableWhitespace(const QString& ch); + bool processingInstruction(const QString& target, const QString& data); + bool skippedEntity(const QString& name); + + bool warning(const QXmlParseException& exception); + bool error(const QXmlParseException& exception); + bool fatalError(const QXmlParseException& exception); + + bool notationDecl(const QString& name, const QString& publicId, const QString& systemId); + bool unparsedEntityDecl(const QString& name, const QString& publicId, const QString& systemId, const QString& notationName); + + bool resolveEntity(const QString& publicId, const QString& systemId, QXmlInputSource*& ret); + + bool startDTD(const QString& name, const QString& publicId, const QString& systemId); + bool endDTD(); + bool startEntity(const QString& name); + bool endEntity(const QString& name); + bool startCDATA(); + bool endCDATA(); + bool comment(const QString& ch); + + bool attributeDecl(const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value); + bool internalEntityDecl(const QString& name, const QString& value); + bool externalEntityDecl(const QString& name, const QString& publicId, const QString& systemId); + + QString errorString() const; + +private: + QXmlDefaultHandlerPrivate *d; + Q_DISABLE_COPY(QXmlDefaultHandler) +}; + +// inlines + +inline int QXmlAttributes::count() const +{ return length(); } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QXML_H diff --git a/src/xml/sax/sax.pri b/src/xml/sax/sax.pri new file mode 100644 index 0000000..6591627 --- /dev/null +++ b/src/xml/sax/sax.pri @@ -0,0 +1,2 @@ +SOURCES += $$PWD/qxml.cpp +HEADERS += $$PWD/qxml.h diff --git a/src/xml/stream/qxmlstream.h b/src/xml/stream/qxmlstream.h new file mode 100644 index 0000000..11fd148 --- /dev/null +++ b/src/xml/stream/qxmlstream.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXml 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 OLD_QXMLSTREAM_H +#define OLD_QXMLSTREAM_H + +#include <QtCore/qxmlstream.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Xml) + +#if 0 +// make syncqt generate forwarding headers for this file too +#pragma qt_class(QXmlStreamAttribute) +#pragma qt_class(QXmlStreamAttributes) +#pragma qt_class(QXmlStreamEntityDeclaration) +#pragma qt_class(QXmlStreamEntityDeclarations) +#pragma qt_class(QXmlStreamEntityResolver) +#pragma qt_class(QXmlStreamNamespaceDeclaration) +#pragma qt_class(QXmlStreamNamespaceDeclarations) +#pragma qt_class(QXmlStreamNotationDeclaration) +#pragma qt_class(QXmlStreamNotationDeclarations) +#pragma qt_class(QXmlStreamReader) +#pragma qt_class(QXmlStreamStringRef) +#pragma qt_class(QXmlStreamWriter) +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // OLD_QXMLSTREAM_H diff --git a/src/xml/stream/stream.pri b/src/xml/stream/stream.pri new file mode 100644 index 0000000..a5ba3a2 --- /dev/null +++ b/src/xml/stream/stream.pri @@ -0,0 +1,9 @@ +# compatibility header: +HEADERS += stream/qxmlstream.h + +!static { + # The platforms that require the symbol to be present in QtXml: + win32:!wince-*:SOURCES += ../corelib/xml/qxmlstream.cpp + mac:SOURCES += ../corelib/xml/qxmlstream.cpp + aix-*:SOURCES += ../corelib/xml/qxmlstream.cpp +} diff --git a/src/xml/xml.pro b/src/xml/xml.pro new file mode 100644 index 0000000..0c7133c --- /dev/null +++ b/src/xml/xml.pro @@ -0,0 +1,20 @@ +TARGET = QtXml +QPRO_PWD = $$PWD +QT = core +DEFINES += QT_BUILD_XML_LIB QT_NO_USING_NAMESPACE +win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x61000000 + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore + +include(../qbase.pri) + +PRECOMPILED_HEADER = ../corelib/global/qt_pch.h + +win32-borland { + QMAKE_CFLAGS_WARN_ON += -w-use + QMAKE_CXXFLAGS_WARN_ON += -w-use +} + +include(dom/dom.pri) +include(sax/sax.pri) +include(stream/stream.pri) |