| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * $Id: DocumentImpl.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| // |
| // file DocumentImpl.cpp |
| // |
| |
| #include "DocumentImpl.hpp" |
| #include "DOM_DOMException.hpp" |
| #include "DOM_Node.hpp" |
| |
| #include "DocumentTypeImpl.hpp" |
| #include "ElementImpl.hpp" |
| #include "ElementNSImpl.hpp" |
| #include "AttrImpl.hpp" |
| #include "AttrNSImpl.hpp" |
| #include "CDATASectionImpl.hpp" |
| #include "CommentImpl.hpp" |
| #include "DocumentFragmentImpl.hpp" |
| #include "EntityImpl.hpp" |
| #include "EntityReferenceImpl.hpp" |
| #include "NotationImpl.hpp" |
| #include "ProcessingInstructionImpl.hpp" |
| #include "TextImpl.hpp" |
| #include "DOM_DOMImplementation.hpp" |
| #include "DeepNodeListImpl.hpp" |
| #include "NamedNodeMapImpl.hpp" |
| #include "DStringPool.hpp" |
| #include <xercesc/internal/XMLReader.hpp> |
| #include "TreeWalkerImpl.hpp" |
| #include "NodeIteratorImpl.hpp" |
| #include "NodeIDMap.hpp" |
| #include "DOM_Document.hpp" |
| #include <xercesc/util/HashPtr.hpp> |
| #include "RangeImpl.hpp" |
| #include "DOM_Document.hpp" |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| |
| static DOMString *nam = 0; // will be lazily initialized to "#document" |
| static XMLRegisterCleanup namCleanup; |
| |
| DocumentImpl::DocumentImpl(MemoryManager* const manager) |
| : ParentNode(this) |
| , docType(0) |
| , docElement(0) |
| , namePool(0) |
| , fNodeIDMap(0) |
| , iterators(0) |
| , treeWalkers(0) |
| , userData(0) |
| , ranges(0) |
| , fChanges(0) |
| , errorChecking(true) |
| , fMemoryManager(manager) |
| { |
| namePool = new (fMemoryManager) DStringPool(257, fMemoryManager); |
| }; |
| |
| |
| //DOM Level 2 |
| DocumentImpl::DocumentImpl(const DOMString &fNamespaceURI, |
| const DOMString &qualifiedName, |
| DocumentTypeImpl *doctype, |
| MemoryManager* const manager) |
| : ParentNode(this) |
| , docType(0) |
| , docElement(0) |
| , namePool(0) |
| , fNodeIDMap(0) |
| , iterators(0) |
| , treeWalkers(0) |
| , userData(0) |
| , ranges(0) |
| , fChanges(0) |
| , errorChecking(true) |
| , fMemoryManager(manager) |
| { |
| setDocumentType(doctype); |
| namePool = new (fMemoryManager) DStringPool(257, fMemoryManager); |
| appendChild(createElementNS(fNamespaceURI, qualifiedName)); //root element |
| } |
| |
| void DocumentImpl::setDocumentType(DocumentTypeImpl *doctype) |
| { |
| if (!doctype) |
| return; |
| |
| if (doctype->getOwnerDocument() != null) |
| throw DOM_DOMException( //one doctype can belong to only one DocumentImpl |
| DOM_DOMException::WRONG_DOCUMENT_ERR, null); |
| |
| doctype->setOwnerDocument(this); |
| doctype->getEntities()->ownerNode->setOwnerDocument(this); |
| doctype->getNotations()->ownerNode->setOwnerDocument(this); |
| doctype -> referenced(); // Warning, tricky! An external (DOM_Node) reference |
| // to a node normally bumps the reference count to its |
| // document also. But this could not happen when the |
| // user created the DOM_DocumentType because there was |
| // no document yet. Now we have the document, and |
| // the docs ref count must be got back in sync. |
| |
| |
| appendChild(doctype); |
| |
| } |
| |
| DocumentImpl::~DocumentImpl() |
| { |
| if (iterators != 0L) { |
| // The data in the vector is pointers owned by smart pointers, and will be cleaned up when they go away. |
| delete iterators; |
| } |
| |
| if (treeWalkers != 0L) { |
| // The data in the vector is pointers owned by smart pointers, and will be cleaned up when they go away. |
| delete treeWalkers; |
| } |
| |
| if (ranges != 0L) { |
| delete ranges; |
| ranges = 0; |
| } |
| |
| if (userData) { |
| // make sure we won't access userData any further |
| hasUserData(false); |
| delete userData; |
| } |
| |
| delete namePool; |
| // Do not delete docType and docElement pointers here. |
| // These are also normal child nodes of the document, |
| // and refcounting will take them out in the usual way. |
| |
| delete fNodeIDMap; |
| }; |
| |
| |
| NodeImpl *DocumentImpl::cloneNode(bool deep) { |
| |
| // clone the node itself |
| DocumentImpl *newdoc = new (fMemoryManager) DocumentImpl(fMemoryManager); |
| |
| // then the children by _importing_ them |
| if (deep) { |
| for (ChildNode *n = firstChild; n != null; n = n->nextSibling) { |
| newdoc->appendChild(newdoc->importNode(n, true)); |
| } |
| } |
| newdoc->setErrorChecking(errorChecking); |
| return newdoc; |
| }; |
| |
| |
| DOMString DocumentImpl::getNodeName() { |
| return DStringPool::getStaticString("#document" |
| , &nam |
| , reinitDocumentImpl |
| , namCleanup); |
| } |
| |
| |
| short DocumentImpl::getNodeType() { |
| return DOM_Node::DOCUMENT_NODE; |
| }; |
| |
| |
| // even though ownerDocument refers to this in this implementation |
| // the DOM Level 2 spec says it must be null, so make it appear so |
| DocumentImpl * DocumentImpl::getOwnerDocument() { |
| return null; |
| } |
| |
| |
| bool DocumentImpl::isDocumentImpl() { |
| return true; |
| }; |
| |
| |
| AttrImpl *DocumentImpl::createAttribute(const DOMString &nam) |
| { |
| if (errorChecking && !isXMLName(nam)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR,null); |
| } |
| return new (fMemoryManager) AttrImpl(this,nam); |
| }; |
| |
| |
| |
| CDATASectionImpl *DocumentImpl::createCDATASection(const DOMString &data) { |
| return new (fMemoryManager) CDATASectionImpl(this,data); |
| }; |
| |
| |
| |
| CommentImpl *DocumentImpl::createComment(const DOMString &data) |
| { |
| return new (fMemoryManager) CommentImpl(this,data); |
| }; |
| |
| |
| |
| DocumentFragmentImpl *DocumentImpl::createDocumentFragment() |
| { |
| return new (fMemoryManager) DocumentFragmentImpl(this); |
| }; |
| |
| |
| |
| DocumentTypeImpl *DocumentImpl::createDocumentType(const DOMString &nam) |
| { |
| if (errorChecking && !isXMLName(nam)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR, null); |
| } |
| return new (fMemoryManager) DocumentTypeImpl(this, nam); |
| }; |
| |
| |
| |
| DocumentTypeImpl * |
| DocumentImpl::createDocumentType(const DOMString &qualifiedName, |
| const DOMString &publicId, |
| const DOMString &systemId) |
| { |
| if (errorChecking && !isXMLName(qualifiedName)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR, null); |
| } |
| return new (fMemoryManager) DocumentTypeImpl(this, qualifiedName, publicId, systemId); |
| }; |
| |
| |
| |
| ElementImpl *DocumentImpl::createElement(const DOMString &tagName) |
| { |
| if (errorChecking && !isXMLName(tagName)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR,null); |
| } |
| DOMString pooledTagName = this->namePool->getPooledString(tagName); |
| return new (fMemoryManager) ElementImpl(this,pooledTagName); |
| }; |
| |
| |
| ElementImpl *DocumentImpl::createElement(const XMLCh *tagName) |
| { |
| DOMString pooledTagName = this->namePool->getPooledString(tagName); |
| return new (fMemoryManager) ElementImpl(this,pooledTagName); |
| }; |
| |
| |
| |
| |
| EntityImpl *DocumentImpl::createEntity(const DOMString &nam) |
| { |
| if (errorChecking && !isXMLName(nam)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR, null); |
| } |
| return new (fMemoryManager) EntityImpl(this, nam); |
| }; |
| |
| |
| |
| EntityReferenceImpl *DocumentImpl::createEntityReference(const DOMString &nam) |
| { |
| if (errorChecking && !isXMLName(nam)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR, null); |
| } |
| return new (fMemoryManager) EntityReferenceImpl(this, nam); |
| }; |
| |
| |
| |
| NotationImpl *DocumentImpl::createNotation(const DOMString &nam) |
| { |
| if (errorChecking && !isXMLName(nam)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR, null); |
| } |
| return new (fMemoryManager) NotationImpl(this, nam); |
| }; |
| |
| |
| |
| ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction( |
| const DOMString &target, const DOMString &data) |
| { |
| if (errorChecking && !isXMLName(target)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR,null); |
| } |
| return new (fMemoryManager) ProcessingInstructionImpl(this,target,data); |
| }; |
| |
| |
| |
| |
| TextImpl *DocumentImpl::createTextNode(const DOMString &data) |
| { |
| return new (fMemoryManager) TextImpl(this,data); |
| }; |
| |
| |
| NodeIteratorImpl* DocumentImpl::createNodeIterator (DOM_Node root, |
| unsigned long whatToShow, |
| DOM_NodeFilter* filter, |
| bool entityReferenceExpansion, |
| MemoryManager* const manager) |
| { |
| // Create the node iterator implementation object. |
| // Add it to the vector of iterators that must be synchronized when a node is deleted. |
| // The vector of iterators is kept in the "owner document" if there is one. If there isn't one, I assume that root is the |
| // owner document. |
| |
| NodeIteratorImpl* iter = new (manager) NodeIteratorImpl(root, whatToShow, filter, entityReferenceExpansion); |
| DOM_Document doc = root.getOwnerDocument(); |
| DocumentImpl* impl; |
| |
| if (! doc.isNull()) { |
| impl = (DocumentImpl *) doc.fImpl; |
| } |
| else |
| impl = (DocumentImpl *) root.fImpl; |
| |
| if (impl->iterators == 0L) { |
| impl->iterators = new (manager) NodeIterators(1, false, manager); |
| impl->iterators->addElement(iter); |
| } |
| |
| return iter; |
| } |
| |
| |
| TreeWalkerImpl* DocumentImpl::createTreeWalker (DOM_Node root, unsigned long whatToShow, |
| DOM_NodeFilter* filter, |
| bool entityReferenceExpansion, |
| MemoryManager* const manager) |
| { |
| // See notes for createNodeIterator... |
| |
| TreeWalkerImpl* twi = new (manager) TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion); |
| DOM_Document doc = root.getOwnerDocument(); |
| DocumentImpl* impl; |
| |
| if (! doc.isNull()) { |
| impl = (DocumentImpl *) doc.fImpl; |
| } |
| else |
| impl = (DocumentImpl *) root.fImpl; |
| |
| if (impl->treeWalkers == 0L) { |
| impl->treeWalkers = new (manager) TreeWalkers(1, false, manager); |
| impl->treeWalkers->addElement(twi); |
| } |
| |
| return twi; |
| } |
| |
| |
| |
| |
| DocumentTypeImpl *DocumentImpl::getDoctype() |
| { |
| return docType; |
| }; |
| |
| |
| |
| ElementImpl *DocumentImpl::getDocumentElement() |
| { |
| return docElement; |
| }; |
| |
| |
| |
| DeepNodeListImpl *DocumentImpl::getElementsByTagName(const DOMString &tagname) |
| { |
| return new (fMemoryManager) DeepNodeListImpl(this,tagname); |
| }; |
| |
| |
| |
| NodeImpl *DocumentImpl::insertBefore(NodeImpl *newChild, NodeImpl *refChild) |
| { |
| // Only one such child permitted |
| if (errorChecking && |
| ((newChild->isElementImpl() && docElement!=null) || |
| (newChild->isDocumentTypeImpl() && docType!=null))) { |
| throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR,null); |
| } |
| ParentNode::insertBefore(newChild,refChild); |
| |
| // If insert succeeded, cache the kid appropriately |
| if(newChild->isElementImpl()) |
| docElement=(ElementImpl *)newChild; |
| else if(newChild->isDocumentTypeImpl()) |
| docType=(DocumentTypeImpl *)newChild; |
| |
| return newChild; |
| }; |
| |
| |
| |
| bool DocumentImpl::isXMLName(const DOMString &s) |
| { |
| return XMLChar1_0::isValidName(s.rawBuffer(),s.length()); |
| }; |
| |
| |
| // referenced(). Override this function here in class DocumentImpl because |
| // we don't want the action taken in NodeImpl, which is |
| // to add a reference to the node's owning document. |
| // |
| void DocumentImpl::referenced() |
| { |
| // Intentionally empty. |
| }; |
| |
| |
| |
| NodeImpl *DocumentImpl::removeChild(NodeImpl *oldChild) |
| { |
| ParentNode::removeChild(oldChild); |
| |
| // If remove succeeded, un-cache the kid appropriately |
| if(oldChild->isElementImpl()) |
| docElement=null; |
| else if(oldChild->isDocumentTypeImpl()) |
| docType=null; |
| |
| return oldChild; |
| }; |
| |
| |
| // |
| // unreferenced() will be called whenever the refernce count on |
| // this document goes from 1 to 0. In all cases, when this |
| // happens to a document node (which is the case here), it |
| // is time to actually delete the document. |
| // |
| // See also NodeImpl::referenced() and unreferenced(), which |
| // update document node ref counts based on references coming |
| // or going to nodes owned by the document. |
| // |
| void DocumentImpl::unreferenced() |
| { |
| deleteIf(this); |
| }; |
| |
| |
| //Introduced in DOM Level 2 |
| |
| NodeImpl *DocumentImpl::importNode(NodeImpl *source, bool deep) |
| { |
| NodeImpl *newnode=null; |
| bool oldErrorCheckingFlag = errorChecking; |
| |
| switch (source->getNodeType()) |
| { |
| case DOM_Node::ELEMENT_NODE : |
| { |
| ElementImpl *newelement; |
| if (source->getLocalName() == null) |
| newelement = createElement(source->getNodeName()); |
| else |
| newelement = createElementNS(source->getNamespaceURI(), |
| source->getNodeName()); |
| NamedNodeMapImpl *srcattr=source->getAttributes(); |
| if (srcattr!=null) |
| for(unsigned int i=0;i<srcattr->getLength();++i) |
| { |
| AttrImpl *attr = (AttrImpl *) srcattr->item(i); |
| AttrImpl * pOldAttr = null; |
| if (attr -> getSpecified()) |
| { // not a default attribute |
| AttrImpl *nattr = (AttrImpl *) importNode(attr, true); |
| if (attr -> getLocalName() == null) |
| pOldAttr = newelement->setAttributeNode(nattr); |
| else |
| pOldAttr = newelement->setAttributeNodeNS(nattr); |
| |
| if (pOldAttr) |
| { |
| if (pOldAttr->nodeRefCount == 0) |
| NodeImpl::deleteIf(pOldAttr); |
| } |
| } |
| } |
| |
| newnode=newelement; |
| } |
| break; |
| case DOM_Node::ATTRIBUTE_NODE : |
| { |
| if (source->getLocalName() == null) |
| newnode = createAttribute(source->getNodeName()); |
| else |
| newnode = createAttributeNS(source->getNamespaceURI(), |
| source->getNodeName()); |
| // if source is an AttrImpl from this very same implementation |
| // avoid creating the child nodes if possible |
| // if (source instanceof AttrImpl) { |
| AttrImpl *attr = (AttrImpl *) source; |
| if (attr->hasStringValue()) { |
| AttrImpl *newattr = (AttrImpl *) newnode; |
| newattr->setValue(attr->getValue()); |
| deep = false; |
| } |
| else { |
| deep = true; |
| } |
| // } |
| // else { |
| // // Kids carry value |
| // deep = true; |
| // } |
| } |
| break; |
| case DOM_Node::TEXT_NODE : |
| newnode = createTextNode(source->getNodeValue()); |
| break; |
| case DOM_Node::CDATA_SECTION_NODE : |
| newnode = createCDATASection(source->getNodeValue()); |
| break; |
| case DOM_Node::ENTITY_REFERENCE_NODE : |
| { |
| EntityReferenceImpl* newentityRef = createEntityReference(source->getNodeName()); |
| newnode=newentityRef; |
| errorChecking = false; |
| newentityRef->setReadOnly(false, true); //allow deep import temporarily |
| } |
| break; |
| case DOM_Node::ENTITY_NODE : |
| { |
| EntityImpl *srcentity=(EntityImpl *)source; |
| EntityImpl *newentity = createEntity(source->getNodeName()); |
| newentity->setPublicId(srcentity->getPublicId()); |
| newentity->setSystemId(srcentity->getSystemId()); |
| newentity->setNotationName(srcentity->getNotationName()); |
| // Kids carry additional value |
| newnode=newentity; |
| newentity->setReadOnly(false, true);// allow deep import temporarily |
| } |
| break; |
| case DOM_Node::PROCESSING_INSTRUCTION_NODE : |
| newnode = createProcessingInstruction(source->getNodeName(), |
| source->getNodeValue()); |
| break; |
| case DOM_Node::COMMENT_NODE : |
| newnode = createComment(source->getNodeValue()); |
| break; |
| case DOM_Node::DOCUMENT_TYPE_NODE : |
| { |
| DocumentTypeImpl *srcdoctype = (DocumentTypeImpl *)source; |
| DocumentTypeImpl *newdoctype = (DocumentTypeImpl *) |
| createDocumentType(srcdoctype->getNodeName(), |
| srcdoctype->getPublicId(), |
| srcdoctype->getSystemId()); |
| // Values are on NamedNodeMaps |
| NamedNodeMapImpl *smap = srcdoctype->getEntities(); |
| NamedNodeMapImpl *tmap = newdoctype->getEntities(); |
| if(smap != null) { |
| for(unsigned int i = 0; i < smap->getLength(); i++) { |
| tmap->setNamedItem(importNode(smap->item(i), true)); |
| } |
| } |
| smap = srcdoctype->getNotations(); |
| tmap = newdoctype->getNotations(); |
| if (smap != null) { |
| for(unsigned int i = 0; i < smap->getLength(); i++) { |
| tmap->setNamedItem(importNode(smap->item(i), true)); |
| } |
| } |
| // NOTE: At this time, the DOM definition of DocumentType |
| // doesn't cover Elements and their Attributes. domimpl's |
| // extentions in that area will not be preserved, even if |
| // copying from domimpl to domimpl. We could special-case |
| // that here. Arguably we should. Consider. ????? |
| newnode = newdoctype; |
| } |
| break; |
| case DOM_Node::DOCUMENT_FRAGMENT_NODE : |
| newnode = createDocumentFragment(); |
| // No name, kids carry value |
| break; |
| case DOM_Node::NOTATION_NODE : |
| { |
| NotationImpl *srcnotation=(NotationImpl *)source; |
| NotationImpl *newnotation = createNotation(source->getNodeName()); |
| newnotation->setPublicId(srcnotation->getPublicId()); |
| newnotation->setSystemId(srcnotation->getSystemId()); |
| // Kids carry additional value |
| newnode=newnotation; |
| // No name, no value |
| break; |
| } |
| |
| case DOM_Node::DOCUMENT_NODE : // Document can't be child of Document |
| default: // Unknown node type |
| throw DOM_DOMException(DOM_DOMException::NOT_SUPPORTED_ERR, null); |
| } |
| |
| // If deep, replicate and attach the kids. |
| if (deep) |
| for (NodeImpl *srckid = source->getFirstChild(); |
| srckid != null; |
| srckid = srckid->getNextSibling()) { |
| newnode->appendChild(importNode(srckid, true)); |
| } |
| if (newnode->getNodeType() == DOM_Node::ENTITY_REFERENCE_NODE |
| || newnode->getNodeType() == DOM_Node::ENTITY_NODE) { |
| ((EntityReferenceImpl*)newnode)->setReadOnly(true, true); |
| errorChecking = oldErrorCheckingFlag; |
| } |
| |
| return newnode; |
| }; |
| |
| |
| ElementImpl *DocumentImpl::createElementNS(const DOMString &fNamespaceURI, |
| const DOMString &qualifiedName) |
| { |
| if (errorChecking && !isXMLName(qualifiedName)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR,null); |
| } |
| //DOMString pooledTagName = this->namePool->getPooledString(qualifiedName); |
| return new (fMemoryManager) ElementNSImpl(this, fNamespaceURI, qualifiedName); |
| } |
| |
| |
| AttrImpl *DocumentImpl::createAttributeNS(const DOMString &fNamespaceURI, |
| const DOMString &qualifiedName) |
| { |
| if (!isXMLName(qualifiedName)) { |
| throw DOM_DOMException(DOM_DOMException::INVALID_CHARACTER_ERR,null); |
| } |
| return new (fMemoryManager) AttrNSImpl(this, fNamespaceURI, qualifiedName); |
| } |
| |
| |
| DeepNodeListImpl *DocumentImpl::getElementsByTagNameNS(const DOMString &fNamespaceURI, |
| const DOMString &fLocalName) |
| { |
| return new (fMemoryManager) DeepNodeListImpl(this, fNamespaceURI, fLocalName); |
| } |
| |
| |
| ElementImpl *DocumentImpl::getElementById(const DOMString &elementId) |
| { |
| if (fNodeIDMap == 0) |
| return null; |
| |
| AttrImpl *theAttr = fNodeIDMap->find(elementId); |
| if (theAttr == null) |
| return null; |
| |
| return theAttr->getOwnerElement(); |
| } |
| |
| |
| //Return the index > 0 of ':' in the given qualified name qName="prefix:localName". |
| //Return 0 if there is no ':', or -1 if qName is malformed such as ":abcd". |
| int DocumentImpl::indexofQualifiedName(const DOMString & qName) |
| { |
| //Check if s = prefix:localName, name or malformed |
| const XMLCh *qNameP = qName.rawBuffer(); |
| int qNameLen = qName.length(); //note: qName[qNameLen] may not be 0 |
| int index = -1, count = 0; |
| for (int i = 0; i < qNameLen; ++i) |
| if (*qNameP++ == chColon) { |
| index = i; |
| ++count; //number of ':' found |
| } |
| if (qNameLen == 0 || count > 1 || index == 0 || index == qNameLen-1) |
| return -1; |
| return count == 0 ? 0 : index; |
| } |
| |
| |
| XMLDeclImpl* DocumentImpl::createXMLDecl(const DOMString& version, const DOMString& encoding, const DOMString& standalone) |
| { |
| return new (fMemoryManager) XMLDeclImpl(this, version, encoding, standalone); |
| } |
| |
| RangeImpl* DocumentImpl::createRange() |
| { |
| |
| RangeImpl* range = new (fMemoryManager) RangeImpl(DOM_Document(this)); |
| |
| if (ranges == 0L) { |
| ranges = new (fMemoryManager) RangeImpls(1, false, fMemoryManager); |
| } |
| ranges->addElement(range); |
| return range; |
| } |
| |
| RangeImpls* DocumentImpl::getRanges() |
| { |
| return ranges; |
| } |
| |
| void DocumentImpl::removeRange(RangeImpl* range) |
| { |
| if (ranges != null) { |
| unsigned int sz = ranges->size(); |
| if (sz !=0) { |
| for (unsigned int i =0; i<sz; i++) { |
| if (ranges->elementAt(i) == range) { |
| ranges->removeElementAt(i); |
| delete range; |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /** Uses the kidOK lookup table to check whether the proposed |
| tree structure is legal. |
| |
| ????? It feels like there must be a more efficient solution, |
| but for the life of me I can't think what it would be. |
| */ |
| bool DocumentImpl::isKidOK(NodeImpl *parent, NodeImpl *child) |
| { |
| static int kidOK[14]; |
| |
| if (kidOK[DOM_Node::DOCUMENT_NODE] == 0) |
| { |
| kidOK[DOM_Node::DOCUMENT_NODE] = |
| 1 << DOM_Node::ELEMENT_NODE | |
| 1 << DOM_Node::PROCESSING_INSTRUCTION_NODE | |
| 1 << DOM_Node::COMMENT_NODE | |
| 1 << DOM_Node::DOCUMENT_TYPE_NODE | |
| 1 << DOM_Node::XML_DECL_NODE; |
| |
| kidOK[DOM_Node::DOCUMENT_FRAGMENT_NODE] = |
| kidOK[DOM_Node::ENTITY_NODE] = |
| kidOK[DOM_Node::ENTITY_REFERENCE_NODE] = |
| kidOK[DOM_Node::ELEMENT_NODE] = |
| 1 << DOM_Node::ELEMENT_NODE | |
| 1 << DOM_Node::PROCESSING_INSTRUCTION_NODE | |
| 1 << DOM_Node::COMMENT_NODE | |
| 1 << DOM_Node::TEXT_NODE | |
| 1 << DOM_Node::CDATA_SECTION_NODE | |
| 1 << DOM_Node::ENTITY_REFERENCE_NODE | |
| 1 << DOM_Node::XML_DECL_NODE; |
| |
| kidOK[DOM_Node::ATTRIBUTE_NODE] = |
| 1 << DOM_Node::TEXT_NODE | |
| 1 << DOM_Node::ENTITY_REFERENCE_NODE; |
| |
| kidOK[DOM_Node::PROCESSING_INSTRUCTION_NODE] = |
| kidOK[DOM_Node::COMMENT_NODE] = |
| kidOK[DOM_Node::TEXT_NODE] = |
| kidOK[DOM_Node::CDATA_SECTION_NODE] = |
| kidOK[DOM_Node::NOTATION_NODE] = |
| 0; |
| }; |
| int p=parent->getNodeType(); |
| int ch = child->getNodeType(); |
| return (kidOK[p] & 1<<ch) != 0; |
| } |
| |
| void DocumentImpl::setUserData(NodeImpl* n, void* data) |
| { |
| if (!userData && data) |
| userData = new (fMemoryManager) RefHashTableOf<void> |
| ( |
| 29 |
| , false |
| , new (fMemoryManager) HashPtr() |
| , fMemoryManager |
| ); |
| if (userData) |
| { |
| if (!data) |
| userData->removeKey((void*)n); |
| else |
| userData->put((void*)n,data); |
| } |
| } |
| |
| void* DocumentImpl::getUserData(NodeImpl* n) |
| { |
| if (userData) |
| return userData->get((void*)n); |
| else |
| return null; |
| } |
| |
| void* DocumentImpl::getUserData() |
| { |
| return (hasUserData()) ? getUserData(this) : null; |
| } |
| |
| void DocumentImpl::setUserData(void* val) |
| { |
| setUserData(this, val); |
| if (val) |
| hasUserData(true); |
| else |
| hasUserData(false); |
| }; |
| |
| /** |
| * Denotes that this node has changed. |
| */ |
| void DocumentImpl::changed() { |
| fChanges++; |
| } |
| |
| /** |
| * Returns the number of changes to this node. |
| */ |
| int DocumentImpl::changes() { |
| return fChanges; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Notification that lazy data has been deleted |
| // ----------------------------------------------------------------------- |
| void DocumentImpl::reinitDocumentImpl() { |
| delete nam; |
| nam = 0; |
| } |
| |
| XERCES_CPP_NAMESPACE_END |
| |