diff --git a/src/xercesc/dom/impl/DOMCharacterDataImpl.cpp b/src/xercesc/dom/impl/DOMCharacterDataImpl.cpp index bbd1e94bfb6ea57c741e8710d20ba43b594d1fce..7f609e3eab13706fb7dd5ee70afd820a7e40b44c 100644 --- a/src/xercesc/dom/impl/DOMCharacterDataImpl.cpp +++ b/src/xercesc/dom/impl/DOMCharacterDataImpl.cpp @@ -251,6 +251,18 @@ void DOMCharacterDataImpl::insertData(const DOMNode *node, XMLSize_t offset, con if (newLen >= 3999) delete[] newString; + + if (node->getOwnerDocument() != 0) { + Ranges* ranges = ((DOMDocumentImpl *)node->getOwnerDocument())->getRanges(); + if (ranges != 0) { + XMLSize_t sz = ranges->size(); + if (sz != 0) { + for (XMLSize_t i =0; i<sz; i++) { + ranges->elementAt(i)->updateRangeForInsertedText( (DOMNode*)node, offset, datLen); + } + } + } + } } @@ -271,9 +283,7 @@ void DOMCharacterDataImpl::replaceData(const DOMNode *node, XMLSize_t offset, XM void DOMCharacterDataImpl::setData(const DOMNode *node, const XMLCh *arg) { - if (castToNodeImpl(node)->isReadOnly()) - throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); - fDataBuf->set(arg); + setNodeValue(node, arg); }; diff --git a/src/xercesc/dom/impl/DOMCommentImpl.cpp b/src/xercesc/dom/impl/DOMCommentImpl.cpp index 3b38171a9283f23579f87ca80899739a9a050d2f..9aa3c455e4e27da01a27c11338030beec6582341 100644 --- a/src/xercesc/dom/impl/DOMCommentImpl.cpp +++ b/src/xercesc/dom/impl/DOMCommentImpl.cpp @@ -60,8 +60,10 @@ #include "DOMCommentImpl.hpp" #include "DOMCharacterDataImpl.hpp" +#include "DOMStringPool.hpp" #include "DOMCasts.hpp" #include "DOMDocumentImpl.hpp" +#include "DOMRangeImpl.hpp" #include <xercesc/dom/DOMNode.hpp> #include <xercesc/dom/DOMException.hpp> #include <xercesc/util/XMLUniDefs.hpp> @@ -127,6 +129,44 @@ void DOMCommentImpl::release() } +// Non standard extension for the range to work +DOMComment *DOMCommentImpl::splitText(XMLSize_t offset) +{ + if (fNode.isReadOnly()) + { + throw DOMException( + DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); + } + XMLSize_t len = fCharacterData.fDataBuf->getLen(); + if (offset > len || offset < 0) + throw DOMException(DOMException::INDEX_SIZE_ERR, 0); + + DOMComment *newText = + getOwnerDocument()->createComment( + this->substringData(offset, len - offset)); + + DOMNode *parent = getParentNode(); + if (parent != 0) + parent->insertBefore(newText, getNextSibling()); + + fCharacterData.fDataBuf->chop(offset); + + if (this->getOwnerDocument() != 0) { + Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges(); + if (ranges != 0) { + XMLSize_t sz = ranges->size(); + if (sz != 0) { + for (XMLSize_t i =0; i<sz; i++) { + ranges->elementAt(i)->updateSplitInfo( this, newText, offset); + } + } + } + } + + return newText; +}; + + DOMNode* DOMCommentImpl::appendChild(DOMNode *newChild) {return fNode.appendChild (newChild); }; DOMNamedNodeMap* DOMCommentImpl::getAttributes() const {return fNode.getAttributes (); }; DOMNodeList* DOMCommentImpl::getChildNodes() const {return fNode.getChildNodes (); }; diff --git a/src/xercesc/dom/impl/DOMCommentImpl.hpp b/src/xercesc/dom/impl/DOMCommentImpl.hpp index bb34d19cc65a2b90471e331ce1a55c5d4b6ab49b..f75a19339e8d6c24715336814ef74fa64ac7e414 100644 --- a/src/xercesc/dom/impl/DOMCommentImpl.hpp +++ b/src/xercesc/dom/impl/DOMCommentImpl.hpp @@ -107,6 +107,9 @@ public: virtual void setData(const XMLCh * arg); virtual const XMLCh * substringData(XMLSize_t offset, XMLSize_t count) const; + // Non standard extension for the range to work + DOMComment* splitText(XMLSize_t offset); + }; XERCES_CPP_NAMESPACE_END diff --git a/src/xercesc/dom/impl/DOMProcessingInstructionImpl.cpp b/src/xercesc/dom/impl/DOMProcessingInstructionImpl.cpp index 180ffbd4a2472610e275d67ce315dbc158c3a5ed..5eb371c5f9cc9e3e8df0b005dc058e736856e13a 100644 --- a/src/xercesc/dom/impl/DOMProcessingInstructionImpl.cpp +++ b/src/xercesc/dom/impl/DOMProcessingInstructionImpl.cpp @@ -61,6 +61,8 @@ #include "DOMProcessingInstructionImpl.hpp" #include "DOMDocumentImpl.hpp" #include "DOMNodeImpl.hpp" +#include "DOMStringPool.hpp" +#include "DOMRangeImpl.hpp" #include <xercesc/dom/DOMException.hpp> #include <xercesc/dom/DOMNode.hpp> @@ -71,22 +73,20 @@ XERCES_CPP_NAMESPACE_BEGIN DOMProcessingInstructionImpl::DOMProcessingInstructionImpl(DOMDocument *ownerDoc, const XMLCh *targt, const XMLCh *dat) - : fNode(ownerDoc), fBaseURI(0) + : fNode(ownerDoc), fBaseURI(0), fCharacterData(ownerDoc, dat) { fNode.setIsLeafNode(true); this->fTarget = ((DOMDocumentImpl *)ownerDoc)->cloneString(targt); - this->fData = ((DOMDocumentImpl *)ownerDoc)->cloneString(dat); }; DOMProcessingInstructionImpl::DOMProcessingInstructionImpl( const DOMProcessingInstructionImpl &other, bool deep) - : fNode(other.fNode), fChild(other.fChild) + : fNode(other.fNode), fChild(other.fChild), fCharacterData(other.fCharacterData) { fNode.setIsLeafNode(true); fTarget = other.fTarget; - fData = other.fData; fBaseURI = other.fBaseURI; }; @@ -115,26 +115,6 @@ short DOMProcessingInstructionImpl::getNodeType() const { }; -const XMLCh * DOMProcessingInstructionImpl::getNodeValue() const -{ - return fData; -}; - - -void DOMProcessingInstructionImpl::setNodeValue(const XMLCh *value) -{ - if (fNode.isReadOnly()) - throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); - fData = ((DOMDocumentImpl *)getOwnerDocument())->cloneString(value); -}; - - -const XMLCh * DOMProcessingInstructionImpl::getData() const -{ - return fData; -}; - - /** A PI's "target" states what processor channel the PI's data should be directed to. It is defined differently in HTML and XML. @@ -151,20 +131,6 @@ const XMLCh * DOMProcessingInstructionImpl::getTarget() const }; -/** -* Change the data content of this PI. -* Note that setNodeValue is aliased to setData -* @see getData(). -* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is read-only. -*/ -void DOMProcessingInstructionImpl::setData(const XMLCh *arg) -{ - if (fNode.isReadOnly()) - throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, - 0); - fData = ((DOMDocumentImpl *)getOwnerDocument())->cloneString(arg); -}; - void DOMProcessingInstructionImpl::release() { if (fNode.isOwned() && !fNode.isToBeReleased()) @@ -173,6 +139,7 @@ void DOMProcessingInstructionImpl::release() DOMDocumentImpl* doc = (DOMDocumentImpl*) getOwnerDocument(); if (doc) { fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0); + fCharacterData.releaseBuffer(); doc->release(this, DOMDocumentImpl::PROCESSING_INSTRUCTION_OBJECT); } else { @@ -190,6 +157,43 @@ const XMLCh* DOMProcessingInstructionImpl::getBaseURI() const return fBaseURI? fBaseURI : fNode.fOwnerNode->getBaseURI(); } +// Non standard extension for the range to work +DOMProcessingInstruction *DOMProcessingInstructionImpl::splitText(XMLSize_t offset) +{ + if (fNode.isReadOnly()) + { + throw DOMException( + DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); + } + XMLSize_t len = fCharacterData.fDataBuf->getLen(); + if (offset > len || offset < 0) + throw DOMException(DOMException::INDEX_SIZE_ERR, 0); + + DOMProcessingInstruction *newText = + getOwnerDocument()->createProcessingInstruction(fTarget, + this->substringData(offset, len - offset)); + + DOMNode *parent = getParentNode(); + if (parent != 0) + parent->insertBefore(newText, getNextSibling()); + + fCharacterData.fDataBuf->chop(offset); + + if (this->getOwnerDocument() != 0) { + Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges(); + if (ranges != 0) { + XMLSize_t sz = ranges->size(); + if (sz != 0) { + for (XMLSize_t i =0; i<sz; i++) { + ranges->elementAt(i)->updateSplitInfo( this, newText, offset); + } + } + } + } + + return newText; +}; + // // Delegation stubs for inherited functions // @@ -201,6 +205,7 @@ const XMLCh* DOMProcessingInstructionImpl::getBaseURI() const const XMLCh* DOMProcessingInstructionImpl::getLocalName() const {return fNode.getLocalName (); }; const XMLCh* DOMProcessingInstructionImpl::getNamespaceURI() const {return fNode.getNamespaceURI (); }; DOMNode* DOMProcessingInstructionImpl::getNextSibling() const {return fChild.getNextSibling (); }; + const XMLCh* DOMProcessingInstructionImpl::getNodeValue() const {return fCharacterData.getNodeValue (); }; DOMDocument* DOMProcessingInstructionImpl::getOwnerDocument() const {return fNode.getOwnerDocument (); }; const XMLCh* DOMProcessingInstructionImpl::getPrefix() const {return fNode.getPrefix (); }; DOMNode* DOMProcessingInstructionImpl::getParentNode() const {return fChild.getParentNode (this); }; @@ -229,5 +234,19 @@ const XMLCh* DOMProcessingInstructionImpl::getBaseURI() const const XMLCh* DOMProcessingInstructionImpl::lookupNamespaceURI(const XMLCh* prefix) const {return fNode.lookupNamespaceURI(prefix); }; DOMNode* DOMProcessingInstructionImpl::getInterface(const XMLCh* feature) {return fNode.getInterface(feature); }; +// +// Delegation of CharacerData functions. +// + + + const XMLCh* DOMProcessingInstructionImpl::getData() const {return fCharacterData.getData();}; + void DOMProcessingInstructionImpl::deleteData(XMLSize_t offset, XMLSize_t count) + {fCharacterData.deleteData(this, offset, count);}; + const XMLCh* DOMProcessingInstructionImpl::substringData(XMLSize_t offset, XMLSize_t count) const + {return fCharacterData.substringData(this, offset, count);}; + void DOMProcessingInstructionImpl::setData(const XMLCh *data) {fCharacterData.setData(this, data);}; + void DOMProcessingInstructionImpl::setNodeValue(const XMLCh *nodeValue) {fCharacterData.setNodeValue (this, nodeValue); }; + + XERCES_CPP_NAMESPACE_END diff --git a/src/xercesc/dom/impl/DOMProcessingInstructionImpl.hpp b/src/xercesc/dom/impl/DOMProcessingInstructionImpl.hpp index 7d746523f72418fd4d8680733efe030d47557ba5..61809d9be3fd726a50cd03d695e67b8edfb30cfb 100644 --- a/src/xercesc/dom/impl/DOMProcessingInstructionImpl.hpp +++ b/src/xercesc/dom/impl/DOMProcessingInstructionImpl.hpp @@ -72,6 +72,7 @@ #include <xercesc/util/XercesDefs.hpp> #include <xercesc/dom/DOMProcessingInstruction.hpp> +#include "DOMCharacterDataImpl.hpp" #include "DOMNodeImpl.hpp" #include "DOMChildNode.hpp" @@ -85,9 +86,10 @@ class CDOM_EXPORT DOMProcessingInstructionImpl: public DOMProcessingInstruction private: DOMNodeImpl fNode; DOMChildNode fChild; + // use fCharacterData to store its data so that those character utitlites can be used + DOMCharacterDataImpl fCharacterData; XMLCh *fTarget; - XMLCh *fData; const XMLCh *fBaseURI; public: @@ -107,6 +109,11 @@ public: // NON-DOM: set base uri virtual void setBaseURI(const XMLCh* baseURI); + + // Non standard extension for the range to work + void deleteData(XMLSize_t offset, XMLSize_t count); + const XMLCh* substringData(XMLSize_t offset, XMLSize_t count) const; + DOMProcessingInstruction* splitText(XMLSize_t offset); }; XERCES_CPP_NAMESPACE_END diff --git a/src/xercesc/dom/impl/DOMRangeImpl.cpp b/src/xercesc/dom/impl/DOMRangeImpl.cpp index 252d1dcdd64ceb0b48609251156cde9d3c6471b3..ef8b6d68db51a4c0355c1b7986f53cd77236e391 100644 --- a/src/xercesc/dom/impl/DOMRangeImpl.cpp +++ b/src/xercesc/dom/impl/DOMRangeImpl.cpp @@ -61,14 +61,18 @@ #include "DOMRangeImpl.hpp" #include "DOMDocumentImpl.hpp" #include "DOMDocumentFragmentImpl.hpp" +#include "DOMCommentImpl.hpp" +#include "DOMProcessingInstructionImpl.hpp" #include "DOMCasts.hpp" #include <xercesc/dom/DOMException.hpp> #include <xercesc/dom/DOMDocument.hpp> #include <xercesc/dom/DOMRangeException.hpp> #include <xercesc/dom/DOMText.hpp> +#include <xercesc/dom/DOMProcessingInstruction.hpp> #include <xercesc/framework/XMLBuffer.hpp> +#include <xercesc/util/Janitor.hpp> XERCES_CPP_NAMESPACE_BEGIN @@ -114,21 +118,45 @@ DOMRangeImpl::~DOMRangeImpl() DOMNode* DOMRangeImpl::getStartContainer() const { + if (fDetached) + { + throw DOMException( + DOMException::INVALID_STATE_ERR, 0); + } + return fStartContainer; } XMLSize_t DOMRangeImpl::getStartOffset() const { + if (fDetached) + { + throw DOMException( + DOMException::INVALID_STATE_ERR, 0); + } + return fStartOffset; } DOMNode* DOMRangeImpl::getEndContainer() const { + if (fDetached) + { + throw DOMException( + DOMException::INVALID_STATE_ERR, 0); + } + return fEndContainer; } XMLSize_t DOMRangeImpl::getEndOffset() const { + if (fDetached) + { + throw DOMException( + DOMException::INVALID_STATE_ERR, 0); + } + return fEndOffset; } @@ -147,7 +175,7 @@ bool DOMRangeImpl::getCollapsed() const } //------------------------------- -// Public getter functions +// Public setter functions //------------------------------- void DOMRangeImpl::setStartContainer(const DOMNode* node) @@ -203,13 +231,18 @@ void DOMRangeImpl::setStart(const DOMNode* refNode, XMLSize_t offset) fStartContainer = (DOMNode*) refNode; fStartOffset = offset; - if ((fDocument != refNode->getOwnerDocument() ) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(true); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fEndContainer)) + collapse(true); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -226,13 +259,18 @@ void DOMRangeImpl::setEnd(const DOMNode* refNode, XMLSize_t offset) fEndContainer = (DOMNode*) refNode; fEndOffset = offset; - if ((fDocument != refNode->getOwnerDocument() ) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(false); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fStartContainer)) + collapse(false); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -262,13 +300,18 @@ void DOMRangeImpl::setStartBefore(const DOMNode* refNode) else fStartOffset = i-1; - if ((fDocument != refNode->getOwnerDocument()) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(true); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fEndContainer)) + collapse(true); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -296,13 +339,18 @@ void DOMRangeImpl::setStartAfter(const DOMNode* refNode) fStartOffset = i; - if ((fDocument != refNode->getOwnerDocument() ) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(true); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fEndContainer)) + collapse(true); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -331,13 +379,18 @@ void DOMRangeImpl::setEndBefore(const DOMNode* refNode) else fEndOffset = i-1; - if ((fDocument != refNode->getOwnerDocument() ) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(true); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fStartContainer)) + collapse(false); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -366,13 +419,18 @@ void DOMRangeImpl::setEndAfter(const DOMNode* refNode) else fEndOffset = i; - if ((fDocument != refNode->getOwnerDocument() ) - && (refNode->getOwnerDocument() != 0) ) - { - fDocument = refNode->getOwnerDocument(); - collapse(true); + // error if not the same owner document + if (fDocument != refNode->getOwnerDocument()) { + if ( refNode != fDocument ) + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } + // they may be of same document, but not same root container + // collapse if not the same root container + if (!commonAncestorOf(refNode, fStartContainer)) + collapse(false); + //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) @@ -429,7 +487,11 @@ void DOMRangeImpl::selectNode(const DOMNode* refNode) DOMRangeException::INVALID_NODE_TYPE_ERR, 0); } //First check for the text type node - if (refNode->getNodeType() == DOMNode::TEXT_NODE) + short type = refNode->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { //The node itself is the container. fStartContainer = (DOMNode*) refNode; @@ -437,7 +499,10 @@ void DOMRangeImpl::selectNode(const DOMNode* refNode) //Select all the contents of the node fStartOffset = 0; - fEndOffset = ((DOMText *)refNode)->getLength(); + if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) + fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)refNode)->getData()); + else + fEndOffset = ((DOMText *)refNode)->getLength(); return; } @@ -465,10 +530,19 @@ void DOMRangeImpl::selectNodeContents(const DOMNode* node) fEndContainer = (DOMNode*) node; fStartOffset = 0; - if (node->getNodeType() == DOMNode::TEXT_NODE ) { + short type = node->getNodeType(); + + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE)) { + fEndOffset = ((DOMText *)node)->getLength(); return; } + if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) { + fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)node)->getData()); + return; + } DOMNode* first = node->getFirstChild(); if (first == 0) { @@ -510,10 +584,18 @@ void DOMRangeImpl::surroundContents(DOMNode* newParent) DOMNode* realStart = fStartContainer; DOMNode* realEnd = fEndContainer; - if (fStartContainer->getNodeType() == DOMNode::TEXT_NODE) { + type = fStartContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { realStart = fStartContainer->getParentNode(); } - if (fEndContainer->getNodeType() == DOMNode::TEXT_NODE) { + type = fEndContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { realEnd = fEndContainer->getParentNode(); } @@ -595,16 +677,25 @@ short DOMRangeImpl::compareBoundaryPoints(DOMRange::CompareHow how, const DOMRan } } - // case 4: preorder traversal of context tree. DOMNode* ancestor = (DOMNode*) commonAncestorOf(pointA, pointB); - DOMNode* current = ancestor; - do { - if (current == pointA) return -1; - if (current == pointB) return 1; - current = nextNode(current, true); + // case 4: preorder traversal of context tree. + if (ancestor) { + DOMNode* current = ancestor; + + do { + if (current == pointA) return -1; + if (current == pointB) return 1; + current = nextNode(current, true); + } + while (current!=0 && current!=ancestor); + } + else { + // case 5: there is no common ancestor of these two points + // it means the two Ranges are not in the same "root container" + throw DOMException( + DOMException::WRONG_DOCUMENT_ERR, 0); } - while (current!=0 && current!=ancestor); return -2; // this should never happen } @@ -670,14 +761,24 @@ void DOMRangeImpl::insertNode(DOMNode* newNode) DOMNode* parent; DOMNode* next; - if (fStartContainer->getNodeType() == DOMNode::TEXT_NODE) { + type = fStartContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { //set 'parent' and 'next' here parent = fStartContainer->getParentNode(); //split the text nodes - if (fStartOffset > 0) - ((DOMText*)fStartContainer)->splitText(fStartOffset); + if (fStartOffset > 0) { + if (type == DOMNode::COMMENT_NODE) + ((DOMCommentImpl*)fStartContainer)->splitText(fStartOffset); + else if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) + ((DOMProcessingInstructionImpl*)fStartContainer)->splitText(fStartOffset); + else + ((DOMText*)fStartContainer)->splitText(fStartOffset); + } //update the new start information later. After inserting the first newNode if (fStartOffset == 0) @@ -724,34 +825,33 @@ const XMLCh* DOMRangeImpl::toString() const DOMException::INVALID_STATE_ERR, 0); } + if ((fStartContainer == fEndContainer) && (fEndOffset == fStartOffset)) + return XMLUni::fgZeroLenString; + DOMNode* node = fStartContainer; DOMNode* stopNode = fEndContainer; XMLBuffer retStringBuf; - if ( (fStartContainer->getNodeType() == DOMNode::TEXT_NODE) - || (fStartContainer->getNodeType() == DOMNode::CDATA_SECTION_NODE) ) { + short type = fStartContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { if (fStartContainer == fEndContainer) { - if (fEndOffset == fStartOffset) { - return XMLUni::fgZeroLenString; - } - else { - - XMLCh* tempString; - XMLCh temp[4000]; - if ((fEndOffset-fStartOffset) >= 3999) - tempString = new XMLCh[fEndOffset-fStartOffset+1]; - else - tempString = temp; - - XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset); - const XMLCh* retString = ((DOMDocumentImpl *)fDocument)->getPooledString(tempString); + XMLCh* tempString; + XMLCh temp[4000]; + if ((fEndOffset-fStartOffset) >= 3999) + tempString = new XMLCh[fEndOffset-fStartOffset+1]; + else + tempString = temp; - if ((fEndOffset-fStartOffset) >= 3999) - delete[] tempString; + XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset); + const XMLCh* retString = ((DOMDocumentImpl *)fDocument)->getPooledString(tempString); - return retString; - } + if ((fEndOffset-fStartOffset) >= 3999) + delete[] tempString; + return retString; } else { XMLSize_t length = XMLString::stringLen(fStartContainer->getNodeValue()); if (length != fStartOffset) { @@ -786,8 +886,11 @@ const XMLCh* DOMRangeImpl::toString() const } } - if ( fEndContainer->getNodeType()!= DOMNode::TEXT_NODE && - fEndContainer->getNodeType()!= DOMNode::CDATA_SECTION_NODE ){ + type = fEndContainer->getNodeType(); + if((type != DOMNode::TEXT_NODE + && type != DOMNode::CDATA_SECTION_NODE + && type != DOMNode::COMMENT_NODE + && type != DOMNode::PROCESSING_INSTRUCTION_NODE)) { int i=fEndOffset; stopNode = fEndContainer->getFirstChild(); while( i>0 && stopNode!=0 ){ @@ -800,15 +903,22 @@ const XMLCh* DOMRangeImpl::toString() const while (node != stopNode) { //look into all kids of the Range if (node == 0) break; - if (node->getNodeType() == DOMNode::TEXT_NODE - || node->getNodeType() == DOMNode::CDATA_SECTION_NODE) { + type = node->getNodeType(); + + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { retStringBuf.append(node->getNodeValue()); } node = nextNode(node, true); } - if (fEndContainer->getNodeType() == DOMNode::TEXT_NODE - || fEndContainer->getNodeType() == DOMNode::CDATA_SECTION_NODE) { + type = fEndContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { if (fEndOffset != 0) { @@ -931,9 +1041,6 @@ const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNo if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0); - if (pointA->getOwnerDocument() != pointB->getOwnerDocument()) - throw DOMException( DOMException::WRONG_DOCUMENT_ERR, 0 ); - //if the containers are same then it itself is its common ancestor. if (pointA == pointB) return pointA; @@ -942,12 +1049,12 @@ const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNo VectorNodes startV(1, false); DOMNode* node; - for (node=fStartContainer; node != 0; node=node->getParentNode()) + for (node=(DOMNode*)pointA; node != 0; node=node->getParentNode()) { startV.addElement(node); } VectorNodes endV(1, false); - for (node=fEndContainer; node != 0; node=node->getParentNode()) + for (node=(DOMNode*)pointB; node != 0; node=node->getParentNode()) { endV.addElement(node); } @@ -955,7 +1062,7 @@ const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNo int s = startV.size()-1; int e = endV.size()-1; - DOMNode* commonAncestor; + DOMNode* commonAncestor = 0; while (s>=0 && e>=0) { if (startV.elementAt(s) == endV.elementAt(e)) { @@ -1061,22 +1168,55 @@ DOMDocumentFragment* DOMRangeImpl::traverseContents(TraversalType how) return traverseSameContainer( how ); // case 2: Child C of start container is ancestor of end container - for (DOMNode* node = fStartContainer->getFirstChild(); node != 0; node=node->getNextSibling()) { - if (isAncestorOf(node, fEndContainer)) - return traverseCommonStartContainer( node, how ); - } + // This can be quickly tested by walking the parent chain of + // end container + int endContainerDepth = 0; + for ( DOMNode* c = fEndContainer, *p = c->getParentNode(); + p != 0; + c = p, p = p->getParentNode()) + { + if (p == fStartContainer) + return traverseCommonStartContainer( c, how ); + ++endContainerDepth; + } // case 3: Child C of end container is ancestor of start container - for (DOMNode* nd = fEndContainer->getFirstChild(); nd != 0; nd=nd->getNextSibling()) { - if (isAncestorOf(nd, fStartContainer)) - return traverseCommonEndContainer( nd, how ); - } + // This can be quickly tested by walking the parent chain of A + int startContainerDepth = 0; + for ( DOMNode* c2 = fStartContainer, *p2 = c2->getParentNode(); + p2 != 0; + c2 = p2, p2 = p2->getParentNode()) + { + if (p2 == fEndContainer) + return traverseCommonEndContainer( c2, how ); + ++startContainerDepth; + } - // case 4: preorder traversal of context tree. - // There is a common ancestor container. Find the + // case 4: There is a common ancestor container. Find the // ancestor siblings that are children of that container. - DOMNode* ancestor = (DOMNode*)commonAncestorOf(fStartContainer, fEndContainer); - return traverseCommonAncestors( ancestor, ancestor, how ); + int depthDiff = startContainerDepth - endContainerDepth; + + DOMNode* startNode = fStartContainer; + while (depthDiff > 0) { + startNode = startNode->getParentNode(); + depthDiff--; + } + + DOMNode* endNode = fEndContainer; + while (depthDiff < 0) { + endNode = endNode->getParentNode(); + depthDiff++; + } + + // ascend the ancestor hierarchy until we have a common parent. + for( DOMNode* sp = startNode->getParentNode(), *ep = endNode->getParentNode(); + sp!=ep; + sp = sp->getParentNode(), ep = ep->getParentNode() ) + { + startNode = sp; + endNode = ep; + } + return traverseCommonAncestors( startNode, endNode, how ); } /** @@ -1098,7 +1238,11 @@ DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how ) DOMNode* cloneCurrent = 0; // Text node needs special case handling - if ( fStartContainer->getNodeType()== DOMNode::TEXT_NODE ) + short type = fStartContainer->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { cloneCurrent = fStartContainer->cloneNode(false); if (fEndOffset == fStartOffset) { @@ -1120,8 +1264,13 @@ DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how ) } // set the original text node to its new value - if ( how != CLONE_CONTENTS ) - ((DOMText*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset); + if ( how != CLONE_CONTENTS ) { + if(type == DOMNode::PROCESSING_INSTRUCTION_NODE) { + ((DOMProcessingInstructionImpl*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset); + } + else + ((DOMCharacterData*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset); + } if ( how != DELETE_CONTENTS) frag->appendChild(cloneCurrent); } @@ -1129,7 +1278,7 @@ DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how ) // Copy nodes between the start/end offsets. DOMNode* n = getSelectedNode( fStartContainer, fStartOffset ); int cnt = fEndOffset - fStartOffset; - while( cnt > 0 ) + while( cnt > 0 && n) { DOMNode* sibling = n->getNextSibling(); DOMNode* xferNode = traverseFullySelected( n, how ); @@ -1137,7 +1286,7 @@ DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how ) frag->appendChild( xferNode ); --cnt; n = sibling; - } + } } // Nothing is partially selected, so collapse to start point @@ -1443,8 +1592,15 @@ DOMNode* DOMRangeImpl::traverseNode( DOMNode* n, bool isFullySelected, bool isLe { if ( isFullySelected ) return traverseFullySelected( n, how ); - if ( n->getNodeType()== DOMNode::TEXT_NODE ) + + short type = n->getNodeType(); + + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) return traverseTextNode( n, isLeft, how ); + return traversePartiallySelected( n, how ); } @@ -1461,11 +1617,6 @@ DOMNode* DOMRangeImpl::traverseFullySelected( DOMNode* n, int how ) case CLONE_CONTENTS: return n->cloneNode( true ); case EXTRACT_CONTENTS: - if ( n->getNodeType()== DOMNode::DOCUMENT_TYPE_NODE ) - { - throw DOMException( - DOMException::HIERARCHY_REQUEST_ERR, 0); - } return n; case DELETE_CONTENTS: // revisit: @@ -1505,7 +1656,8 @@ DOMNode* DOMRangeImpl::traversePartiallySelected( DOMNode*n, int how ) */ DOMNode* DOMRangeImpl::traverseTextNode( DOMNode*n, bool isLeft, int how ) { - const XMLCh* txtValue = n->getNodeValue(); + XMLCh* txtValue = XMLString::replicate(n->getNodeValue()); + ArrayJanitor<XMLCh> janValue(txtValue); if ( isLeft ) { @@ -1629,7 +1781,11 @@ DOMNode* DOMRangeImpl::traverseTextNode( DOMNode*n, bool isLeft, int how ) */ DOMNode* DOMRangeImpl::getSelectedNode( DOMNode*container, int offset ) { - if ( container->getNodeType() == DOMNode::TEXT_NODE ) + short type = container->getNodeType(); + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) return container; // This case is an important convenience for @@ -1652,22 +1808,49 @@ void DOMRangeImpl::checkReadOnly(DOMNode* start, DOMNode* end, XMLSize_t startOffset, XMLSize_t endOffset) { if ((start == 0) || (end == 0) ) return; - //if both start and end are text check and return - if (start->getNodeType() == DOMNode::TEXT_NODE) { + DOMNode*sNode = 0; + + short type = start->getNodeType(); + if ( type == DOMNode::DOCUMENT_TYPE_NODE ) + { + throw DOMException( + DOMException::HIERARCHY_REQUEST_ERR, 0); + } + + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { if (castToNodeImpl(start)->isReadOnly()) { throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); } + //if both start and end are text check and return if (start == end) return; + + sNode = start; + } else { + //set the start and end nodes to check + sNode = start->getFirstChild(); + for(XMLSize_t i = 0; i<startOffset; i++) + sNode = sNode->getNextSibling(); } - //set the start and end nodes to check - DOMNode*sNode = start->getFirstChild(); - for(XMLSize_t i = 0; i<startOffset; i++) - sNode = sNode->getNextSibling(); DOMNode* eNode; - if (end->getNodeType() == DOMNode::TEXT_NODE) { + type = end->getNodeType(); + if ( type == DOMNode::DOCUMENT_TYPE_NODE ) + { + throw DOMException( + DOMException::HIERARCHY_REQUEST_ERR, 0); + } + + if((type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { eNode = end; //need to check only till this node } else { //need to check all the kids that fall before the end offset value @@ -1685,6 +1868,12 @@ void DOMRangeImpl::recurseTreeAndCheck(DOMNode* start, DOMNode* end) { for(DOMNode* node=start; node != 0 && node !=end; node=node->getNextSibling()) { + if ( node->getNodeType()== DOMNode::DOCUMENT_TYPE_NODE ) + { + throw DOMException( + DOMException::HIERARCHY_REQUEST_ERR, 0); + } + if (castToNodeImpl(node)->isReadOnly()) { throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); @@ -1713,42 +1902,62 @@ DOMNode* DOMRangeImpl::removeChild(DOMNode* parent, DOMNode* child) /* This function is called from DOM. -* The text has already beeen replaced. +* The text has already been replaced. * Fix-up any offsets. */ void DOMRangeImpl::receiveReplacedText(DOMNode* node) { if (node == 0) return; + short type = fStartContainer->getNodeType(); if (node == fStartContainer - && fStartContainer->getNodeType() == DOMNode::TEXT_NODE) { + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { fStartOffset = 0; } + type = fEndContainer->getNodeType(); if (node == fEndContainer - && fEndContainer->getNodeType() == DOMNode::TEXT_NODE) { + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { fEndOffset = 0; } } /** This function is called from DOM. -* The text has already beeen inserted. +* The text has already been deleted. * Fix-up any offsets. */ void DOMRangeImpl::updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, int count) { if (node == 0) return; + short type = fStartContainer->getNodeType(); if (node == fStartContainer - && fStartContainer->getNodeType() == DOMNode::TEXT_NODE) { + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { if (fStartOffset > offset+count) { fStartOffset = fStartOffset-count; } else if (fStartOffset > offset) { fStartOffset = offset; } } + type = fEndContainer->getNodeType(); if (node == fEndContainer - && fEndContainer->getNodeType() == DOMNode::TEXT_NODE) { + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { if (fEndOffset > offset+count) { fEndOffset = fEndOffset-count; } else if (fEndOffset > offset) { @@ -1759,6 +1968,40 @@ void DOMRangeImpl::updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, in +/** This function is called from DOM. +* The text has already beeen inserted. +* Fix-up any offsets. +*/ +void DOMRangeImpl::updateRangeForInsertedText(DOMNode* node, XMLSize_t offset, int count) +{ + if (node == 0) return; + + short type = fStartContainer->getNodeType(); + if (node == fStartContainer + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { + if (fStartOffset > offset) { + fStartOffset = offset; + } + } + type = fEndContainer->getNodeType(); + if (node == fEndContainer + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { + if (fEndOffset > offset) { + fEndOffset = fEndOffset+count; + } + } +} + + + /** This function must be called by the DOM _BEFORE_ * a node is deleted, because at that time it is * connected in the DOM tree, which we depend on. @@ -1818,18 +2061,34 @@ void DOMRangeImpl::updateRangeForInsertedNode(DOMNode* node) { } -void DOMRangeImpl::updateSplitInfo(DOMText* oldNode, DOMText* startNode, XMLSize_t offset) +void DOMRangeImpl::updateSplitInfo(DOMNode* oldNode, DOMNode* startNode, XMLSize_t offset) { if (startNode == 0) return; - if (fStartContainer == oldNode && fStartOffset > offset) { - fStartOffset = fStartOffset - offset; - fStartContainer = startNode; + short type = fStartContainer->getNodeType(); + if (oldNode == fStartContainer + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { + if (fStartOffset > offset) { + fStartOffset = fStartOffset - offset; + fStartContainer = startNode; + } } - if (fEndContainer == oldNode && fEndOffset > offset) { + type = fEndContainer->getNodeType(); + if (oldNode == fEndContainer + && (type == DOMNode::TEXT_NODE + || type == DOMNode::CDATA_SECTION_NODE + || type == DOMNode::COMMENT_NODE + || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) + { + if (fEndOffset > offset) { fEndContainer = startNode; - fEndOffset = fEndOffset - offset; + fEndOffset = fEndOffset - offset; + } } } diff --git a/src/xercesc/dom/impl/DOMRangeImpl.hpp b/src/xercesc/dom/impl/DOMRangeImpl.hpp index fd75a15e9a7df6459b0b0db1bdbbef7d83be2e63..3ac626ec16224e2c8798bb6dfb41af0b66909c50 100644 --- a/src/xercesc/dom/impl/DOMRangeImpl.hpp +++ b/src/xercesc/dom/impl/DOMRangeImpl.hpp @@ -156,10 +156,11 @@ public: DOMDocument* getDocument(); // functions to inform all existing valid ranges about a change - void updateSplitInfo(DOMText* oldNode, DOMText* startNode, XMLSize_t offset); + void updateSplitInfo(DOMNode* oldNode, DOMNode* startNode, XMLSize_t offset); void updateRangeForInsertedNode(DOMNode* node); void receiveReplacedText(DOMNode* node); void updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, int count); + void updateRangeForInsertedText(DOMNode* node, XMLSize_t offset, int count); void updateRangeForDeletedNode(DOMNode* node); private: