GME  13
DOMRangeImpl.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  * 
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  * 
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: DOMRangeImpl.cpp 676911 2008-07-15 13:27:32Z amassari $
00020  */
00021 
00022 #include "DOMRangeImpl.hpp"
00023 #include "DOMDocumentImpl.hpp"
00024 #include "DOMDocumentFragmentImpl.hpp"
00025 #include "DOMCommentImpl.hpp"
00026 #include "DOMProcessingInstructionImpl.hpp"
00027 #include "DOMCasts.hpp"
00028 
00029 #include <xercesc/dom/DOMException.hpp>
00030 #include <xercesc/dom/DOMDocument.hpp>
00031 #include <xercesc/dom/DOMRangeException.hpp>
00032 #include <xercesc/dom/DOMText.hpp>
00033 #include <xercesc/dom/DOMProcessingInstruction.hpp>
00034 
00035 #include <xercesc/framework/XMLBuffer.hpp>
00036 #include <xercesc/util/Janitor.hpp>
00037 
00038 XERCES_CPP_NAMESPACE_BEGIN
00039 
00040 
00041 //---------------------
00042 // C'tor and D'tor
00043 //---------------------
00044 
00045 DOMRangeImpl::DOMRangeImpl(DOMDocument* doc, MemoryManager* const manager)
00046 
00047     :   fStartContainer(doc),     
00048         fStartOffset(0),
00049         fEndContainer(doc),
00050         fEndOffset(0),        
00051         fCollapsed(true),
00052         fDocument(doc),   
00053         fDetached(false),
00054         fRemoveChild(0),
00055         fMemoryManager(manager)
00056 {
00057 }
00058 
00059 DOMRangeImpl::DOMRangeImpl(const DOMRangeImpl& other)
00060 :   DOMRange(other),
00061     fStartContainer(other.fStartContainer),
00062     fStartOffset(other.fStartOffset),
00063     fEndContainer(other.fEndContainer),
00064     fEndOffset(other.fEndOffset),
00065     fCollapsed(other.fCollapsed),
00066     fDocument(other.fDocument),
00067     fDetached(other.fDetached),
00068     fRemoveChild(other.fRemoveChild),
00069     fMemoryManager(other.fMemoryManager)
00070 {
00071 }
00072 
00073 DOMRangeImpl::~DOMRangeImpl()
00074 {
00075 }
00076 
00077 
00078 //-------------------------------
00079 // Public getter functions
00080 //-------------------------------
00081 
00082 
00083 DOMNode* DOMRangeImpl::getStartContainer() const
00084 {
00085     if (fDetached)
00086     {
00087         throw DOMException(
00088             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00089     }
00090 
00091     return fStartContainer;
00092 }
00093 
00094 XMLSize_t DOMRangeImpl::getStartOffset() const
00095 {
00096     if (fDetached)
00097     {
00098         throw DOMException(
00099             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00100     }
00101 
00102     return fStartOffset;
00103 }
00104 
00105 DOMNode* DOMRangeImpl::getEndContainer() const
00106 {
00107     if (fDetached)
00108     {
00109         throw DOMException(
00110             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00111     }
00112 
00113     return fEndContainer;
00114 }
00115 
00116 XMLSize_t DOMRangeImpl::getEndOffset() const
00117 {
00118     if (fDetached)
00119     {
00120         throw DOMException(
00121             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00122     }
00123 
00124     return fEndOffset;
00125 }
00126 
00127 
00128 
00129 bool DOMRangeImpl::getCollapsed() const
00130 {
00131     if (fDetached)
00132     {
00133         throw DOMException(
00134             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00135     }
00136 
00137     return ((fStartContainer == fEndContainer)
00138              && (fStartOffset == fEndOffset));
00139 }
00140 
00141 //-------------------------------
00142 // Public setter functions
00143 //-------------------------------
00144 
00145 void DOMRangeImpl::setStartContainer(const DOMNode* node)
00146 {
00147     if (fDetached)
00148     {
00149         throw DOMException(
00150             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00151     }
00152 
00153     fStartContainer = (DOMNode*) node;
00154 }
00155 
00156 void DOMRangeImpl::setStartOffset(XMLSize_t offset)
00157 {
00158     if (fDetached)
00159     {
00160         throw DOMException(
00161             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00162     }
00163 
00164     fStartOffset = offset;
00165 }
00166 
00167 void DOMRangeImpl::setEndContainer(const DOMNode* node)
00168 {
00169     if (fDetached)
00170     {
00171         throw DOMException(
00172             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00173     }
00174 
00175     fEndContainer = (DOMNode*) node;
00176 
00177 }
00178 
00179 void DOMRangeImpl::setEndOffset(XMLSize_t offset)
00180 {
00181     if (fDetached)
00182     {
00183         throw DOMException(
00184             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00185     }
00186 
00187     fEndOffset = offset;
00188 }
00189 
00190 void DOMRangeImpl::setStart(const DOMNode* refNode, XMLSize_t offset)
00191 {
00192     validateNode(refNode);
00193     checkIndex(refNode, offset);
00194 
00195     // error if not the same owner document
00196     if (fDocument != refNode->getOwnerDocument()) {
00197         if ( refNode != fDocument ) {
00198             collapse(true); //collapse the range positions to start
00199             fCollapsed = true;
00200             throw DOMException(
00201                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00202         }
00203     }
00204 
00205     fStartContainer = (DOMNode*) refNode;
00206     fStartOffset    = offset;
00207 
00208     // they may be of same document, but not same root container
00209     // collapse if not the same root container
00210     if (!commonAncestorOf(refNode, fEndContainer))
00211         collapse(true);
00212 
00213     //compare the start and end boundary point
00214     //collapse if start point is after the end point
00215     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00216         collapse(true); //collapse the range positions to start
00217     else
00218         fCollapsed = false;
00219 }
00220 
00221 void DOMRangeImpl::setEnd(const DOMNode* refNode, XMLSize_t offset)
00222 {
00223     validateNode(refNode);
00224     checkIndex(refNode, offset);
00225 
00226     // error if not the same owner document
00227     if (fDocument != refNode->getOwnerDocument()) {
00228         if ( refNode != fDocument ) {
00229             collapse(false); //collapse the range positions to end
00230             fCollapsed = true;
00231             throw DOMException(
00232                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00233         }
00234     }
00235 
00236     fEndContainer   = (DOMNode*) refNode;
00237     fEndOffset      = offset;
00238 
00239     // they may be of same document, but not same root container
00240     // collapse if not the same root container
00241     if (!commonAncestorOf(refNode, fStartContainer))
00242         collapse(false);
00243 
00244     //compare the start and end boundary point
00245     //collapse if start point is after the end point
00246     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00247         collapse(false); //collapse the range positions to end
00248     else
00249         fCollapsed = false;
00250 }
00251 
00252 void DOMRangeImpl::setStartBefore(const DOMNode* refNode)
00253 {
00254     if( fDetached) {
00255         throw DOMException(
00256             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00257     }
00258     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
00259         throw DOMRangeException(
00260             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00261     }
00262 
00263     // error if not the same owner document
00264     if (fDocument != refNode->getOwnerDocument()) {
00265         if ( refNode != fDocument ) {
00266             collapse(true); //collapse the range positions to start
00267             fCollapsed = true;
00268             throw DOMException(
00269                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00270         }
00271     }
00272 
00273     fStartContainer = refNode->getParentNode();
00274    XMLSize_t i = 0;
00275     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) {
00276         i++;
00277     }
00278     if (i == 0)
00279         fStartOffset = 0;
00280     else
00281         fStartOffset = i-1;
00282 
00283     // they may be of same document, but not same root container
00284     // collapse if not the same root container
00285     if (!commonAncestorOf(refNode, fEndContainer))
00286         collapse(true);
00287 
00288     //compare the start and end boundary point
00289     //collapse if start point is after the end point
00290     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00291         collapse(true); //collapse the range positions to start
00292     else
00293         fCollapsed = false;
00294 }
00295 
00296 void DOMRangeImpl::setStartAfter(const DOMNode* refNode)
00297 {
00298     if( fDetached) {
00299         throw DOMException(
00300             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00301     }
00302     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
00303         throw DOMRangeException(
00304             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00305     }
00306 
00307     // error if not the same owner document
00308     if (fDocument != refNode->getOwnerDocument()) {
00309         if ( refNode != fDocument ) {
00310             collapse(true); //collapse the range positions to start
00311             fCollapsed = true;
00312             throw DOMException(
00313                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00314         }
00315     }
00316 
00317     fStartContainer = refNode->getParentNode();
00318     XMLSize_t i = 0;
00319     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) {
00320         i++;
00321     }
00322 
00323     fStartOffset = i;
00324 
00325     // they may be of same document, but not same root container
00326     // collapse if not the same root container
00327     if (!commonAncestorOf(refNode, fEndContainer))
00328         collapse(true);
00329 
00330     //compare the start and end boundary point
00331     //collapse if start point is after the end point
00332     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00333         collapse(true); //collapse the range positions to start
00334     else
00335         fCollapsed = false;
00336 }
00337 
00338 void DOMRangeImpl::setEndBefore(const DOMNode* refNode)
00339 {
00340     if( fDetached) {
00341         throw DOMException(
00342             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00343     }
00344     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
00345         throw DOMRangeException(
00346             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00347     }
00348 
00349     // error if not the same owner document
00350     if (fDocument != refNode->getOwnerDocument()) {
00351         if ( refNode != fDocument ) {
00352             collapse(false); //collapse the range positions to end
00353             fCollapsed = true;
00354             throw DOMException(
00355                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00356         }
00357     }
00358 
00359     fEndContainer = refNode->getParentNode();
00360     XMLSize_t i = 0;
00361     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
00362 
00363     if (i< 1)
00364         fEndOffset = 0;
00365     else
00366         fEndOffset = i-1;
00367 
00368     // they may be of same document, but not same root container
00369     // collapse if not the same root container
00370     if (!commonAncestorOf(refNode, fStartContainer))
00371         collapse(false);
00372 
00373     //compare the start and end boundary point
00374     //collapse if start point is after the end point
00375     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00376         collapse(false); //collapse the range positions to end
00377     else
00378         fCollapsed = false;
00379 }
00380 
00381 void DOMRangeImpl::setEndAfter(const DOMNode* refNode)
00382 {
00383     if( fDetached) {
00384         throw DOMException(
00385             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00386     }
00387     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
00388         throw DOMRangeException(
00389             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00390     }
00391 
00392     // error if not the same owner document
00393     if (fDocument != refNode->getOwnerDocument()) {
00394         if ( refNode != fDocument ) {
00395             collapse(false); //collapse the range positions to end
00396             fCollapsed = true;
00397             throw DOMException(
00398                 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00399         }
00400     }
00401 
00402     fEndContainer = refNode->getParentNode();
00403     XMLSize_t i = 0;
00404     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
00405 
00406     if (i ==0)
00407         fEndOffset = 0;
00408     else
00409         fEndOffset = i;
00410 
00411     // they may be of same document, but not same root container
00412     // collapse if not the same root container
00413     if (!commonAncestorOf(refNode, fStartContainer))
00414         collapse(false);
00415 
00416     //compare the start and end boundary point
00417     //collapse if start point is after the end point
00418     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
00419         collapse(false); //collapse the range positions to end
00420     else
00421         fCollapsed = false;
00422 }
00423 //-------------------------------
00424 // Public Misc. functions
00425 //-------------------------------
00426 void DOMRangeImpl::detach()
00427 {
00428     if( fDetached) {
00429         throw DOMException(
00430             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00431     }
00432 
00433     ((DOMDocumentImpl *)fDocument)->removeRange(this);
00434 
00435     fDetached = true;
00436 
00437     //0ify nodes
00438     fStartContainer = 0;
00439     fStartOffset    = 0;
00440     fEndContainer   = 0;
00441     fEndOffset      = 0;
00442     fCollapsed      = true;
00443 
00444     fRemoveChild    = 0;
00445 }
00446 
00447 void DOMRangeImpl::collapse(bool toStart)
00448 {
00449     if( fDetached) {
00450         throw DOMException(
00451             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00452     }
00453 
00454     if (toStart) {
00455         fEndContainer = fStartContainer;
00456         fEndOffset = fStartOffset;
00457     } else {
00458         fStartContainer = fEndContainer;
00459         fStartOffset = fEndOffset;
00460     }
00461     fCollapsed = true;
00462 }
00463 
00464 void DOMRangeImpl::selectNode(const DOMNode* refNode)
00465 {
00466     validateNode(refNode);
00467     if ( !isLegalContainedNode(refNode)) {
00468         throw DOMRangeException(
00469             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00470     }
00471     //First check for the text type node
00472     short type = refNode->getNodeType();
00473     if((type == DOMNode::TEXT_NODE
00474         || type == DOMNode::CDATA_SECTION_NODE
00475         || type == DOMNode::COMMENT_NODE
00476         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
00477     {
00478         //The node itself is the container.
00479         fStartContainer = (DOMNode*) refNode;
00480         fEndContainer   = (DOMNode*) refNode;
00481 
00482         //Select all the contents of the node
00483         fStartOffset = 0;
00484         if (type == DOMNode::PROCESSING_INSTRUCTION_NODE)
00485             fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)refNode)->getData());
00486         else
00487             fEndOffset = ((DOMText *)refNode)->getLength();
00488         return;
00489     }
00490 
00491     DOMNode* parent = refNode->getParentNode();
00492     if (parent != 0 ) // REVIST: what to do if it IS 0?
00493     {
00494         fStartContainer = parent;
00495         fEndContainer = parent;
00496 
00497         XMLSize_t i = 0;
00498         for (DOMNode* n = parent->getFirstChild(); n!=0 && n!=refNode; n = n->getNextSibling()) {
00499             i++;
00500         }
00501 
00502         fStartOffset = i;
00503         fEndOffset = fStartOffset+1;
00504     }
00505 }
00506 
00507 void DOMRangeImpl::selectNodeContents(const DOMNode* node)
00508 {
00509     validateNode(node);
00510 
00511     fStartContainer = (DOMNode*) node;
00512     fEndContainer = (DOMNode*) node;
00513 
00514     fStartOffset = 0;
00515     short type = node->getNodeType();
00516 
00517     if((type == DOMNode::TEXT_NODE
00518         || type == DOMNode::CDATA_SECTION_NODE
00519         || type == DOMNode::COMMENT_NODE)) {
00520 
00521         fEndOffset = ((DOMText *)node)->getLength();
00522         return;
00523     }
00524     if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) {
00525         fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)node)->getData());
00526         return;
00527     }
00528 
00529     DOMNode* first = node->getFirstChild();
00530     if (first == 0) {
00531         fEndOffset = 0;
00532         return;
00533     }
00534     XMLSize_t i = 0;
00535     for (DOMNode* n = first; n!=0; n = n->getNextSibling()) {
00536         i++;
00537     }
00538     fEndOffset = i;
00539 }
00540 
00541 void DOMRangeImpl::surroundContents(DOMNode* newParent)
00542 {
00543     if (newParent==0) return;
00544 
00545     //check for elimination criteria
00546     if( fDetached) {
00547         throw DOMException(
00548             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00549     }
00550 
00551     if (newParent->getOwnerDocument() !=fDocument) {
00552         throw DOMException(
00553             DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00554     }
00555 
00556     int type = newParent->getNodeType();
00557     if ( !isLegalContainedNode(newParent)
00558         || type == DOMNode::DOCUMENT_TYPE_NODE)
00559     {
00560         throw DOMRangeException(
00561             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00562     }
00563 
00564     DOMNode* realStart = fStartContainer;
00565     DOMNode* realEnd = fEndContainer;
00566 
00567     type = fStartContainer->getNodeType();
00568     if((type == DOMNode::TEXT_NODE
00569         || type == DOMNode::CDATA_SECTION_NODE
00570         || type == DOMNode::COMMENT_NODE
00571         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00572         realStart = fStartContainer->getParentNode();
00573     }
00574     type = fEndContainer->getNodeType();
00575     if((type == DOMNode::TEXT_NODE
00576         || type == DOMNode::CDATA_SECTION_NODE
00577         || type == DOMNode::COMMENT_NODE
00578         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00579         realEnd = fEndContainer->getParentNode();
00580     }
00581 
00582     if (realStart != realEnd) {
00583         throw DOMRangeException(
00584             DOMRangeException::BAD_BOUNDARYPOINTS_ERR, 0, fMemoryManager);
00585     }
00586 
00587     DOMDocumentFragment* frag = (DOMDocumentFragment*) extractContents();
00588     insertNode(newParent);
00589     newParent->appendChild(frag);
00590     selectNode(newParent);
00591 }
00592 
00593 
00594 short DOMRangeImpl::compareBoundaryPoints(DOMRange::CompareHow how, const DOMRange* srcRange) const
00595 {
00596     if (fDocument != ((DOMRangeImpl*)srcRange)->fDocument) {
00597         throw DOMException(
00598             DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00599     }
00600     if( fDetached) {
00601         throw DOMException(
00602             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00603     }
00604 
00605     DOMNode* pointA;
00606     DOMNode* pointB;
00607     XMLSize_t offsetA, offsetB;
00608 
00609     switch (how)
00610     {
00611     case (DOMRange::START_TO_START) :
00612         pointB = srcRange->getStartContainer();
00613         pointA = fStartContainer;
00614         offsetB = srcRange->getStartOffset();
00615         offsetA = fStartOffset;
00616         break;
00617     case (DOMRange::START_TO_END) :
00618         pointB = srcRange->getStartContainer();
00619         pointA = fEndContainer;
00620         offsetB = srcRange->getStartOffset();
00621         offsetA = fEndOffset;
00622         break;
00623     case (DOMRange::END_TO_START) :
00624         pointB = srcRange->getEndContainer();
00625         pointA = fStartContainer;
00626         offsetB = srcRange->getEndOffset();
00627         offsetA = fStartOffset;
00628         break;
00629     case (DOMRange::END_TO_END) :
00630         pointB = srcRange->getEndContainer();
00631         pointA = fEndContainer;
00632         offsetB = srcRange->getEndOffset();
00633         offsetA = fEndOffset;
00634         break;
00635     default:
00636         throw DOMException(
00637             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00638     }
00639 
00640     // case 1: same container
00641     if (pointA == pointB) {
00642         if (offsetA < offsetB) return -1; //A before B
00643         if (offsetA == offsetB) return 0; //A equal to B
00644         return 1; // A after B
00645     }
00646     // case 2: Child C of container A is ancestor of B
00647     for (DOMNode* node = pointA->getFirstChild(); node != 0; node=node->getNextSibling()) {
00648         if (isAncestorOf(node, pointB)) {
00649             XMLSize_t index = indexOf(node, pointA);
00650             if (offsetA <=  index) return -1;
00651             return 1;
00652         }
00653     }
00654     // case 3: Child C of container B is ancestor of A
00655     for (DOMNode* nd = pointB->getFirstChild(); nd != 0; nd=nd->getNextSibling()) {
00656         if (isAncestorOf(nd, pointA)) {
00657             XMLSize_t index = indexOf(nd, pointB);
00658             if (index < offsetB ) return -1;
00659             return 1; //B strictly before A
00660         }
00661     }
00662 
00663     // case 4: preorder traversal of context tree.
00664     // Instead of literally walking the context tree in pre-order,
00665     // we use relative node depth walking which is usually faster
00666 
00667     int depthDiff = 0;
00668     DOMNode* n = 0;
00669     for ( n = pointB; n != 0; n = n->getParentNode() )
00670         depthDiff++;
00671     for ( n = pointA; n != 0; n = n->getParentNode() )
00672         depthDiff--;
00673     while (depthDiff > 0) {
00674         pointB = pointB->getParentNode();
00675         depthDiff--;
00676     }
00677     while (depthDiff < 0) {
00678         pointA = pointA->getParentNode();
00679         depthDiff++;
00680     }
00681     for (DOMNode* pB = pointB->getParentNode(),
00682          *pA = pointA->getParentNode();
00683          pB != pA;
00684          pB = pB->getParentNode(), pA = pA->getParentNode() )
00685     {
00686         pointB = pB;
00687         pointA = pA;
00688     }
00689     for ( n = pointB->getNextSibling();
00690          n != 0;
00691          n = n->getNextSibling() )
00692     {
00693         if (n == pointA) {
00694             return 1;
00695         }
00696     }
00697     return -1;
00698 }
00699 
00700 
00701 void DOMRangeImpl:: deleteContents()
00702 {
00703     traverseContents(DELETE_CONTENTS);
00704 }
00705 
00706 DOMDocumentFragment* DOMRangeImpl::extractContents()
00707 {
00708     checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
00709     return traverseContents(EXTRACT_CONTENTS);
00710 }
00711 
00712 DOMDocumentFragment* DOMRangeImpl::cloneContents() const
00713 {
00714     // cast off const.
00715     return ((DOMRangeImpl *)this)->traverseContents(CLONE_CONTENTS);
00716 }
00717 
00718 
00719 void DOMRangeImpl::insertNode(DOMNode* newNode)
00720 {
00721     if (newNode == 0) return; //don't have to do anything
00722 
00723     if( fDetached) {
00724         throw DOMException(
00725             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00726     }
00727 
00728     int type = newNode->getNodeType();
00729     if (type == DOMNode::ATTRIBUTE_NODE
00730         || type == DOMNode::ENTITY_NODE
00731         || type == DOMNode::NOTATION_NODE
00732         || type == DOMNode::DOCUMENT_NODE)
00733     {
00734         throw DOMRangeException(
00735             DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
00736     }
00737 
00738     // Prevent cycles in the tree.
00739     //isKidOK() is not checked here as its taken care by insertBefore() function
00740     if (isAncestorOf( newNode, fStartContainer)) {
00741         throw DOMException(
00742             DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager);
00743     }
00744 
00745     for (DOMNode* aNode = fStartContainer; aNode!=0; aNode = aNode->getParentNode()) {
00746         if (castToNodeImpl(newNode)->isReadOnly()) {
00747         throw DOMException(
00748             DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager);
00749     }
00750     }
00751 
00752     if (fDocument != newNode->getOwnerDocument()) {
00753         throw DOMException(
00754             DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager);
00755     }
00756 
00757 
00758     DOMNode* parent;
00759     DOMNode* next;
00760 
00761     type = fStartContainer->getNodeType();
00762     if((type == DOMNode::TEXT_NODE
00763         || type == DOMNode::CDATA_SECTION_NODE
00764         || type == DOMNode::COMMENT_NODE
00765         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00766 
00767         //set 'parent' and 'next' here
00768         parent = fStartContainer->getParentNode();
00769 
00770         //split the text nodes
00771        if (fStartOffset > 0) {
00772            if (type == DOMNode::COMMENT_NODE)
00773                ((DOMCommentImpl*)fStartContainer)->splitText(fStartOffset);
00774            else if (type == DOMNode::PROCESSING_INSTRUCTION_NODE)
00775                ((DOMProcessingInstructionImpl*)fStartContainer)->splitText(fStartOffset);
00776            else
00777                ((DOMText*)fStartContainer)->splitText(fStartOffset);
00778        }
00779 
00780         //update the new start information later. After inserting the first newNode
00781         if (fStartOffset == 0)
00782             next = fStartContainer;
00783         else
00784             next = fStartContainer->getNextSibling();
00785 
00786     } // end of text handling
00787     else {
00788         parent = fStartContainer;
00789 
00790         next = fStartContainer->getFirstChild();
00791         for(XMLSize_t i = 0; (i < fStartOffset) && (next != 0); i++) {
00792             next=next->getNextSibling();
00793         }
00794     }
00795 
00796     if (parent != 0) {
00797         if (next != 0)
00798             parent->insertBefore(newNode, next);
00799         else
00800             parent->appendChild(newNode);
00801     }
00802 }
00803 
00804 DOMRange* DOMRangeImpl::cloneRange() const
00805 {
00806     if( fDetached) {
00807         throw DOMException(
00808             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00809     }
00810 
00811     DOMRange* range = fDocument->createRange();
00812     range->setStart(fStartContainer, fStartOffset);
00813     range->setEnd(fEndContainer, fEndOffset);
00814 
00815     return range;
00816 }
00817 
00818 const XMLCh* DOMRangeImpl::toString() const
00819 {
00820     if( fDetached) {
00821         throw DOMException(
00822             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
00823     }
00824 
00825     if ((fStartContainer == fEndContainer) && (fEndOffset == fStartOffset))
00826         return XMLUni::fgZeroLenString;
00827 
00828     DOMNode* node = fStartContainer;
00829     DOMNode* stopNode = fEndContainer;
00830 
00831     XMLBuffer retStringBuf(1023, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
00832     short type = fStartContainer->getNodeType();
00833     if((type == DOMNode::TEXT_NODE
00834         || type == DOMNode::CDATA_SECTION_NODE
00835         || type == DOMNode::COMMENT_NODE
00836         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00837         if (fStartContainer == fEndContainer) {
00838             XMLCh* tempString;
00839             XMLCh temp[4000];
00840             if ((fEndOffset-fStartOffset) >= 3999)
00841                 tempString = (XMLCh*) fMemoryManager->allocate
00842                 (
00843                     (fEndOffset - fStartOffset + 1) * sizeof(XMLCh)
00844                 );//new XMLCh[fEndOffset-fStartOffset+1];
00845             else
00846                 tempString = temp;
00847 
00848             XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
00849             const XMLCh* retString = ((DOMDocumentImpl *)fDocument)->getPooledString(tempString);
00850 
00851             if ((fEndOffset-fStartOffset) >= 3999)
00852                 fMemoryManager->deallocate(tempString);//delete[] tempString;
00853 
00854             return retString;
00855         } else {
00856             XMLSize_t length = XMLString::stringLen(fStartContainer->getNodeValue());
00857             if (length != fStartOffset) {
00858 
00859                 XMLCh* tempString;
00860                 XMLCh temp[4000];
00861                 if ((length - fStartOffset) >= 3999)
00862                     tempString = (XMLCh*) fMemoryManager->allocate
00863                     (
00864                         (length - fStartOffset + 1) * sizeof(XMLCh)
00865                     );//new XMLCh[length - fStartOffset+1];
00866                 else
00867                     tempString = temp;
00868 
00869                 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, length, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
00870                 retStringBuf.append(tempString);
00871 
00872                 if ((length - fStartOffset) >= 3999)
00873                     fMemoryManager->deallocate(tempString);//delete[] tempString;
00874             }
00875 
00876             node = nextNode(node, true);
00877         }
00878     }else { //fStartContainer is not a TextNode
00879         node=node->getFirstChild();
00880         if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset
00881             XMLSize_t counter = 0;
00882             while (counter<fStartOffset && node!=0) {
00883                 node=node->getNextSibling();
00884                 counter++;
00885             }
00886         }
00887         if (node == 0) {
00888             node = nextNode(fStartContainer,false);
00889         }
00890     }
00891 
00892     type = fEndContainer->getNodeType();
00893     if((type != DOMNode::TEXT_NODE
00894         && type != DOMNode::CDATA_SECTION_NODE
00895         && type != DOMNode::COMMENT_NODE
00896         && type != DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00897         int i=(int)fEndOffset;
00898         stopNode = fEndContainer->getFirstChild();
00899         while( i>0 && stopNode!=0 ){
00900             --i;
00901             stopNode = stopNode->getNextSibling();
00902         }
00903         if ( stopNode == 0 )
00904             stopNode = nextNode( fEndContainer, false );
00905     }
00906 
00907     while (node != stopNode) {  //look into all kids of the Range
00908         if (node == 0) break;
00909         type = node->getNodeType();
00910 
00911         if((type == DOMNode::TEXT_NODE
00912             || type == DOMNode::CDATA_SECTION_NODE
00913             || type == DOMNode::COMMENT_NODE
00914             || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00915             retStringBuf.append(node->getNodeValue());
00916         }
00917         node = nextNode(node, true);
00918     }
00919 
00920     type = fEndContainer->getNodeType();
00921     if((type == DOMNode::TEXT_NODE
00922         || type == DOMNode::CDATA_SECTION_NODE
00923         || type == DOMNode::COMMENT_NODE
00924         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
00925 
00926         if (fEndOffset != 0) {
00927 
00928             XMLCh* tempString;
00929             XMLCh temp[4000];
00930             if (fEndOffset >= 3999)
00931                 tempString = (XMLCh*) fMemoryManager->allocate
00932                 (
00933                     (fEndOffset+1) * sizeof(XMLCh)
00934                 );//new XMLCh[fEndOffset+1];
00935             else
00936                 tempString = temp;
00937 
00938             XMLString::subString(tempString, fEndContainer->getNodeValue(), 0, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
00939             retStringBuf.append(tempString);
00940 
00941             if (fEndOffset >= 3999)
00942                 fMemoryManager->deallocate(tempString);//delete[] tempString;
00943         }
00944     }
00945     return ((DOMDocumentImpl *)fDocument)->getPooledString(retStringBuf.getRawBuffer());
00946 }
00947 
00948 DOMDocument* DOMRangeImpl::getDocument()
00949 {
00950     return fDocument;
00951 }
00952 
00953 const DOMNode* DOMRangeImpl::getCommonAncestorContainer() const
00954 {
00955      return commonAncestorOf(fStartContainer, fEndContainer);
00956 
00957 }
00958 
00959 void DOMRangeImpl::release()
00960 {
00961     detach();
00962     // for performance reason, do not recycle pointer
00963     // chance that this is allocated again and again is not usual
00964 }
00965 
00966 //---------------------
00967 //private functions
00968 //---------------------
00969 
00970 bool DOMRangeImpl::isValidAncestorType(const DOMNode* node) const
00971 {
00972     for (DOMNode* aNode = (DOMNode*) node; aNode!=0; aNode = aNode->getParentNode()) {
00973         short type = aNode->getNodeType();
00974         if ( type == DOMNode::ENTITY_NODE
00975             || type == DOMNode::NOTATION_NODE
00976             || type == DOMNode::DOCUMENT_TYPE_NODE)
00977             return false;
00978     }
00979     return true;
00980 }
00981 
00982 bool DOMRangeImpl::isAncestorOf(const DOMNode* a, const DOMNode* b) {
00983     for (DOMNode* node = (DOMNode*) b; node != 0; node=node->getParentNode()) {
00984         if  (node == a) return true;
00985     }
00986     return false;
00987 }
00988 
00989 bool DOMRangeImpl::hasLegalRootContainer(const DOMNode* node) const {
00990     if ( node==0 )
00991         return false;
00992 
00993     DOMNode* rootContainer = (DOMNode*)node;
00994     for (; rootContainer->getParentNode()!=0; rootContainer = rootContainer->getParentNode())
00995         ;
00996 
00997     switch( rootContainer->getNodeType() ) {
00998         case DOMNode::ATTRIBUTE_NODE:
00999         case DOMNode::DOCUMENT_NODE:
01000         case DOMNode::DOCUMENT_FRAGMENT_NODE:
01001             return true;
01002         default:
01003             return false;
01004     }
01005 }
01006 
01007 bool DOMRangeImpl::isLegalContainedNode(const DOMNode* node ) const {
01008    if ( node==0 )
01009        return false;
01010    switch( node->getNodeType() )
01011    {
01012        case DOMNode::DOCUMENT_NODE:
01013        case DOMNode::DOCUMENT_FRAGMENT_NODE:
01014        case DOMNode::ATTRIBUTE_NODE:
01015        case DOMNode::ENTITY_NODE:
01016        case DOMNode::NOTATION_NODE:
01017             return false;
01018        default:
01019             return true;
01020    }   
01021 }
01022 
01023 XMLSize_t DOMRangeImpl::indexOf(const DOMNode* child, const DOMNode* parent) const
01024 {
01025     XMLSize_t i = 0;
01026     if (child->getParentNode() != parent) return (XMLSize_t)-1;
01027     for(DOMNode* node = child->getPreviousSibling(); node!= 0; node=node->getPreviousSibling()) {
01028         i++;
01029     }
01030     return i;
01031 }
01032 
01033 void DOMRangeImpl::validateNode(const DOMNode* node) const
01034 {
01035     if( fDetached) {
01036         throw DOMException(
01037             DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
01038     }
01039 
01040     if ( !isValidAncestorType(node)) {
01041         throw DOMRangeException(DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager);
01042     }
01043 }
01044 
01045 
01046 const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNode* pointB) const
01047 {
01048     if (fDetached)
01049         throw DOMException(DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
01050 
01051     //if the containers are same then it itself is its common ancestor.
01052     if (pointA == pointB)
01053         return pointA;
01054 
01055     typedef RefVectorOf<DOMNode> VectorNodes;
01056     VectorNodes startV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01057     DOMNode* node;
01058 
01059     for (node=(DOMNode*)pointA; node != 0; node=node->getParentNode())
01060     {
01061         startV.addElement(node);
01062     }
01063     VectorNodes endV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01064     for (node=(DOMNode*)pointB; node != 0; node=node->getParentNode())
01065     {
01066         endV.addElement(node);
01067     }
01068 
01069     XMLSize_t s = startV.size();
01070     XMLSize_t e = endV.size();
01071 
01072     DOMNode* commonAncestor = 0;
01073 
01074     while (s>0 && e>0) {
01075         if (startV.elementAt(s-1) == endV.elementAt(e-1)) {
01076             commonAncestor = startV.elementAt(s-1);
01077         }
01078         else  break;
01079         --s;
01080         --e;
01081     }
01082 
01083     return commonAncestor;
01084 }
01085 
01086 void DOMRangeImpl::checkIndex(const DOMNode* node, XMLSize_t offset) const
01087 {
01088     short type = node->getNodeType();
01089 
01090     if((type == DOMNode::TEXT_NODE
01091         || type == DOMNode::CDATA_SECTION_NODE
01092         || type == DOMNode::COMMENT_NODE
01093         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
01094         if (offset > XMLString::stringLen(node->getNodeValue()))
01095             throw DOMException( DOMException::INDEX_SIZE_ERR, 0, fMemoryManager );
01096         else  return;
01097     }
01098 
01099     DOMNode* child = node->getFirstChild();
01100     XMLSize_t i = 0;
01101     for (; child != 0; i++) {
01102         child = child->getNextSibling();
01103     }
01104     if (i < offset) {
01105         throw DOMException( DOMException::INDEX_SIZE_ERR, 0, fMemoryManager );
01106     }
01107 
01108 }
01109 
01110 DOMNode* DOMRangeImpl::nextNode(const DOMNode* node, bool visitChildren) const
01111 {
01112 
01113     if (node == 0) return 0;
01114 
01115     DOMNode* result;
01116     if (visitChildren) {
01117         result = node->getFirstChild();
01118         if (result != 0) {
01119             return result;
01120         }
01121     }
01122 
01123     // if hasSibling, return sibling
01124     result = node->getNextSibling();
01125     if (result != 0) {
01126         return result;
01127     }
01128 
01129 
01130     // return parent's 1st sibling.
01131     DOMNode* parent = node->getParentNode();
01132 
01133 
01134     while ( (parent != 0) && (parent != fDocument) )
01135     {
01136         result = parent->getNextSibling();
01137         if (result != 0) {
01138             return result;
01139         } else {
01140             parent = parent->getParentNode();
01141         }
01142 
01143     }
01144     // end of list, return 0
01145     return 0;
01146 }
01147 
01148 
01153 DOMDocumentFragment* DOMRangeImpl::traverseContents(TraversalType how)
01154 {
01155     if (fDetached)
01156             throw DOMException(DOMException::INVALID_STATE_ERR, 0, fMemoryManager);
01157 
01158     if (fStartContainer == 0 || fEndContainer == 0) {
01159         return 0; // REVIST: Throw exception?
01160     }
01161 
01162     /* Traversal is accomplished by first determining the
01163        relationship between the endpoints of the range.
01164        For each of four significant relationships, we will
01165        delegate the traversal call to a method that
01166        can make appropriate assumptions.
01167     */
01168 
01169     // case 1: same container
01170     if ( fStartContainer == fEndContainer )
01171         return traverseSameContainer( how );
01172 
01173     // case 2: Child C of start container is ancestor of end container
01174     // This can be quickly tested by walking the parent chain of
01175     // end container
01176     int endContainerDepth = 0;
01177     for ( DOMNode* c = fEndContainer, *p = c->getParentNode();
01178              p != 0;
01179              c = p, p = p->getParentNode())
01180         {
01181             if (p == fStartContainer)
01182                 return traverseCommonStartContainer( c, how );
01183             ++endContainerDepth;
01184         }
01185 
01186     // case 3: Child C of end container  is ancestor of start container
01187     // This can be quickly tested by walking the parent chain of A
01188     int startContainerDepth = 0;
01189     for ( DOMNode* c2 = fStartContainer, *p2 = c2->getParentNode();
01190          p2 != 0;
01191          c2 = p2, p2 = p2->getParentNode())
01192     {
01193         if (p2 == fEndContainer)
01194             return traverseCommonEndContainer( c2, how );
01195         ++startContainerDepth;
01196     }
01197 
01198     // case 4: There is a common ancestor container.  Find the
01199     // ancestor siblings that are children of that container.
01200     int depthDiff = startContainerDepth - endContainerDepth;
01201 
01202     DOMNode* startNode = fStartContainer;
01203     while (depthDiff > 0) {
01204         startNode = startNode->getParentNode();
01205         depthDiff--;
01206     }
01207 
01208     DOMNode* endNode = fEndContainer;
01209     while (depthDiff < 0) {
01210         endNode = endNode->getParentNode();
01211         depthDiff++;
01212     }
01213 
01214     // ascend the ancestor hierarchy until we have a common parent.
01215     for( DOMNode* sp = startNode->getParentNode(), *ep = endNode->getParentNode();
01216          sp!=ep;
01217          sp = sp->getParentNode(), ep = ep->getParentNode() )
01218     {
01219         startNode = sp;
01220         endNode = ep;
01221     }
01222     return traverseCommonAncestors( startNode, endNode, how );
01223     }
01224 
01230 DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how )
01231 {
01232     DOMDocumentFragment* frag = 0;
01233     if ( how!=DELETE_CONTENTS)
01234         frag = fDocument->createDocumentFragment();
01235 
01236     // If selection is empty, just return the fragment
01237     if ( fStartOffset==fEndOffset )
01238             return frag;
01239 
01240     DOMNode* cloneCurrent = 0;
01241 
01242     // Text node needs special case handling
01243     short type = fStartContainer->getNodeType();
01244     if((type == DOMNode::TEXT_NODE
01245         || type == DOMNode::CDATA_SECTION_NODE
01246         || type == DOMNode::COMMENT_NODE
01247         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01248     {
01249         cloneCurrent = fStartContainer->cloneNode(false);
01250         if (fEndOffset == fStartOffset) {
01251             cloneCurrent->setNodeValue(XMLUni::fgZeroLenString);
01252         }
01253         else {
01254             XMLCh* tempString;
01255             XMLCh temp[4000];
01256             if (fEndOffset >= 3999)
01257                 tempString = (XMLCh*) fMemoryManager->allocate
01258                 (
01259                     (fEndOffset+1) * sizeof(XMLCh)
01260                 );//new XMLCh[fEndOffset+1];
01261             else
01262                 tempString = temp;
01263 
01264             XMLString::subString(tempString, cloneCurrent->getNodeValue(), fStartOffset, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01265             cloneCurrent->setNodeValue(((DOMDocumentImpl *)fDocument)->getPooledString(tempString));
01266 
01267             if (fEndOffset >= 3999)
01268                 fMemoryManager->deallocate(tempString);//delete[] tempString;
01269         }
01270 
01271         // set the original text node to its new value
01272         if ( how != CLONE_CONTENTS ) {
01273             if(type == DOMNode::PROCESSING_INSTRUCTION_NODE) {
01274                 ((DOMProcessingInstructionImpl*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset);
01275             }
01276             else
01277                 ((DOMCharacterData*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset);
01278         }
01279         if ( how != DELETE_CONTENTS)
01280             frag->appendChild(cloneCurrent);
01281     }
01282     else {
01283         // Copy nodes between the start/end offsets.
01284         DOMNode* n = getSelectedNode( fStartContainer, (int)fStartOffset );
01285         int cnt = (int)fEndOffset - (int)fStartOffset;
01286         while( cnt > 0 && n)
01287         {
01288             DOMNode* sibling = n->getNextSibling();
01289             DOMNode* xferNode = traverseFullySelected( n, how );
01290             if ( frag!=0 )
01291                 frag->appendChild( xferNode );
01292             --cnt;
01293             n = sibling;
01294         }
01295     }
01296 
01297     // Nothing is partially selected, so collapse to start point
01298     if ( how != CLONE_CONTENTS )
01299             collapse(true);
01300     return frag;
01301 }
01302 
01309 DOMDocumentFragment* DOMRangeImpl::traverseCommonStartContainer( DOMNode*endAncestor, int how )
01310 {
01311     DOMDocumentFragment* frag = 0;
01312     if ( how!=DELETE_CONTENTS)
01313         frag = fDocument->createDocumentFragment();
01314     DOMNode*n = traverseRightBoundary( endAncestor, how );
01315     if ( frag!=0 )
01316         frag->appendChild( n );
01317 
01318     XMLSize_t endIdx = indexOf( endAncestor, fStartContainer );
01319     if ( endIdx <= fStartOffset )
01320     {
01321         // Collapse to just before the endAncestor, which
01322         // is partially selected.
01323         if ( how != CLONE_CONTENTS )
01324         {
01325             setEndBefore( endAncestor );
01326             collapse( false );
01327         }
01328         return frag;
01329     }
01330 
01331     n = endAncestor->getPreviousSibling();
01332     int cnt = (int)endIdx - (int)fStartOffset;
01333     while( cnt > 0 )
01334     {
01335         DOMNode* sibling = n->getPreviousSibling();
01336         DOMNode* xferNode = traverseFullySelected( n, how );
01337         if ( frag!=0 )
01338             frag->insertBefore( xferNode, frag->getFirstChild() );
01339         --cnt;
01340         n = sibling;
01341     }
01342     // Collapse to just before the endAncestor, which
01343     // is partially selected.
01344     if ( how != CLONE_CONTENTS )
01345     {
01346         setEndBefore( endAncestor );
01347         collapse( false );
01348     }
01349     return frag;
01350 }
01351 
01358 DOMDocumentFragment* DOMRangeImpl::traverseCommonEndContainer( DOMNode*startAncestor, int how )
01359 {
01360     DOMDocumentFragment* frag = 0;
01361     if ( how!=DELETE_CONTENTS)
01362         frag = fDocument->createDocumentFragment();
01363     DOMNode* n = traverseLeftBoundary( startAncestor, how );
01364     if ( frag!=0 )
01365         frag->appendChild( n );
01366     XMLSize_t startIdx = indexOf( startAncestor, fEndContainer );
01367     ++startIdx;  // Because we already traversed it....
01368 
01369     int cnt = (int)fEndOffset - (int)startIdx;
01370     n = startAncestor->getNextSibling();
01371     while( cnt > 0 )
01372     {
01373         DOMNode* sibling = n->getNextSibling();
01374         DOMNode* xferNode = traverseFullySelected( n, how );
01375         if ( frag!=0 )
01376             frag->appendChild( xferNode );
01377         --cnt;
01378         n = sibling;
01379     }
01380 
01381     if ( how != CLONE_CONTENTS )
01382     {
01383         setStartAfter( startAncestor );
01384         collapse( true );
01385     }
01386 
01387     return frag;
01388 }
01389 
01396 DOMDocumentFragment* DOMRangeImpl::traverseCommonAncestors( DOMNode*startAncestor, DOMNode*endAncestor, int how )
01397 {
01398     DOMDocumentFragment* frag = 0;
01399     if ( how!=DELETE_CONTENTS)
01400         frag = fDocument->createDocumentFragment();
01401 
01402     DOMNode*n = traverseLeftBoundary( startAncestor, how );
01403     if ( frag!=0 )
01404         frag->appendChild( n );
01405 
01406     DOMNode*commonParent = startAncestor->getParentNode();
01407     XMLSize_t startOffset = indexOf( startAncestor, commonParent );
01408     XMLSize_t endOffset = indexOf( endAncestor, commonParent );
01409     ++startOffset;
01410 
01411     int cnt = (int)endOffset - (int)startOffset;
01412     DOMNode* sibling = startAncestor->getNextSibling();
01413 
01414     while( cnt > 0 )
01415     {
01416         DOMNode* nextSibling = sibling->getNextSibling();
01417         n = traverseFullySelected( sibling, how );
01418         if ( frag!=0 )
01419             frag->appendChild( n );
01420         sibling = nextSibling;
01421         --cnt;
01422     }
01423 
01424     n = traverseRightBoundary( endAncestor, how );
01425     if ( frag!=0 )
01426         frag->appendChild( n );
01427 
01428     if ( how != CLONE_CONTENTS )
01429     {
01430         setStartAfter( startAncestor );
01431         collapse( true );
01432     }
01433     return frag;
01434 }
01435 
01470 DOMNode* DOMRangeImpl::traverseRightBoundary( DOMNode*root, int how )
01471 {
01472     DOMNode*next = getSelectedNode( fEndContainer, (int)fEndOffset-1 );
01473     bool isFullySelected = ( next!=fEndContainer );
01474 
01475     if ( next==root )
01476         return traverseNode( next, isFullySelected, false, how );
01477 
01478     DOMNode*parent = next->getParentNode();
01479     DOMNode*clonedParent = traverseNode( parent, false, false, how );
01480 
01481     while( parent!=0 )
01482     {
01483         while( next!=0 )
01484         {
01485             DOMNode* prevSibling = next->getPreviousSibling();
01486             DOMNode* clonedChild =
01487                 traverseNode( next, isFullySelected, false, how );
01488             if ( how!=DELETE_CONTENTS )
01489             {
01490                 clonedParent->insertBefore(
01491                     clonedChild,
01492                     clonedParent->getFirstChild()
01493                 );
01494             }
01495             isFullySelected = true;
01496             next = prevSibling;
01497         }
01498         if ( parent==root )
01499             return clonedParent;
01500 
01501         next = parent->getPreviousSibling();
01502         parent = parent->getParentNode();
01503         DOMNode* clonedGrandParent = traverseNode( parent, false, false, how );
01504         if ( how!=DELETE_CONTENTS )
01505             clonedGrandParent->appendChild( clonedParent );
01506         clonedParent = clonedGrandParent;
01507 
01508     }
01509 
01510     // should never occur
01511     return 0;
01512 }
01513 
01549 DOMNode* DOMRangeImpl::traverseLeftBoundary( DOMNode*root, int how )
01550 {
01551     DOMNode*next = getSelectedNode( getStartContainer(), (int)getStartOffset() );
01552     bool isFullySelected = ( next!=getStartContainer() );
01553 
01554     if ( next==root )
01555         return traverseNode( next, isFullySelected, true, how );
01556 
01557     DOMNode* parent = next->getParentNode();
01558     DOMNode* clonedParent = traverseNode( parent, false, true, how );
01559 
01560     while( parent!=0 )
01561     {
01562         while( next!=0 )
01563         {
01564             DOMNode* nextSibling = next->getNextSibling();
01565             DOMNode* clonedChild =
01566                 traverseNode( next, isFullySelected, true, how );
01567             if ( how!=DELETE_CONTENTS )
01568                 clonedParent->appendChild(clonedChild);
01569             isFullySelected = true;
01570             next = nextSibling;
01571         }
01572         if ( parent==root )
01573             return clonedParent;
01574 
01575         next = parent->getNextSibling();
01576         parent = parent->getParentNode();
01577         DOMNode* clonedGrandParent = traverseNode( parent, false, true, how );
01578         if ( how!=DELETE_CONTENTS )
01579             clonedGrandParent->appendChild( clonedParent );
01580         clonedParent = clonedGrandParent;
01581 
01582     }
01583 
01584     // should never occur
01585     return 0;
01586 
01587 }
01588 
01596 DOMNode* DOMRangeImpl::traverseNode( DOMNode* n, bool isFullySelected, bool isLeft, int how )
01597 {
01598     if ( isFullySelected )
01599         return traverseFullySelected( n, how );
01600 
01601     short type = n->getNodeType();
01602 
01603     if((type == DOMNode::TEXT_NODE
01604         || type == DOMNode::CDATA_SECTION_NODE
01605         || type == DOMNode::COMMENT_NODE
01606         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01607         return traverseTextNode( n, isLeft, how );
01608 
01609     return traversePartiallySelected( n, how );
01610 }
01611 
01618 DOMNode* DOMRangeImpl::traverseFullySelected( DOMNode* n, int how )
01619 {
01620     switch( how )
01621     {
01622     case CLONE_CONTENTS:
01623         return n->cloneNode( true );
01624     case EXTRACT_CONTENTS:
01625         return n;
01626     case DELETE_CONTENTS:
01627         // revisit:
01628         //   should I release the removed node?
01629         //   not released in case user still referencing it externally
01630         n->getParentNode()->removeChild(n);
01631         return 0;
01632     }
01633     return 0;
01634 }
01635 
01642 DOMNode* DOMRangeImpl::traversePartiallySelected( DOMNode*n, int how )
01643 {
01644     switch( how )
01645     {
01646     case DELETE_CONTENTS:
01647         return 0;
01648     case CLONE_CONTENTS:
01649     case EXTRACT_CONTENTS:
01650         return n->cloneNode( false );
01651     }
01652     return 0;
01653 }
01654 
01662 DOMNode* DOMRangeImpl::traverseTextNode( DOMNode*n, bool isLeft, int how )
01663 {
01664     XMLCh* txtValue = XMLString::replicate(n->getNodeValue(), fMemoryManager);
01665     ArrayJanitor<XMLCh> janValue(txtValue, fMemoryManager);
01666 
01667     if ( isLeft )
01668     {
01669         XMLSize_t startLen = XMLString::stringLen(fStartContainer->getNodeValue());
01670         XMLSize_t offset = getStartOffset();
01671 
01672         if (offset == 0) {
01673             if ( how != CLONE_CONTENTS )
01674                 n->setNodeValue(XMLUni::fgZeroLenString);
01675         }
01676         else {
01677             XMLCh* oldNodeValue;
01678             XMLCh oldTemp[4000];
01679 
01680             if (offset >= 3999)  {
01681                 oldNodeValue = (XMLCh*) fMemoryManager->allocate
01682                 (
01683                     (offset+1) * sizeof(XMLCh)
01684                 );//new XMLCh[offset+1];
01685             }
01686             else {
01687                 oldNodeValue = oldTemp;
01688             }
01689             XMLString::subString(oldNodeValue, txtValue, 0, offset, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01690 
01691             if ( how != CLONE_CONTENTS )
01692                 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
01693 
01694             if (offset>= 3999)
01695                 fMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue;
01696         }
01697 
01698         if ( how==DELETE_CONTENTS )
01699             return 0;
01700 
01701         DOMNode* newNode = n->cloneNode( false );
01702 
01703         if (startLen == offset) {
01704             newNode->setNodeValue(XMLUni::fgZeroLenString);
01705         }
01706         else {
01707             XMLCh* newNodeValue;
01708             XMLCh newTemp[4000];
01709 
01710             if (offset >= 3999)  {
01711                 newNodeValue = (XMLCh*) fMemoryManager->allocate
01712                 (
01713                     (offset+1) * sizeof(XMLCh)
01714                 );//new XMLCh[offset+1];
01715             }
01716             else {
01717                 newNodeValue = newTemp;
01718             }
01719             XMLString::subString(newNodeValue, txtValue, offset, startLen, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01720             newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
01721 
01722             if (offset>= 3999)
01723                 fMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue;
01724 
01725         }
01726         return newNode;
01727     }
01728     else
01729     {
01730         XMLSize_t endLen = XMLString::stringLen(fEndContainer->getNodeValue());
01731         XMLSize_t offset = getEndOffset();
01732 
01733         if (endLen == offset) {
01734             if ( how != CLONE_CONTENTS )
01735                 n->setNodeValue(XMLUni::fgZeroLenString);
01736         }
01737         else {
01738             XMLCh* oldNodeValue;
01739             XMLCh oldTemp[4000];
01740 
01741             if (offset >= 3999)  {
01742                 oldNodeValue = (XMLCh*) fMemoryManager->allocate
01743                 (
01744                     (offset+1) * sizeof(XMLCh)
01745                 );//new XMLCh[offset+1];
01746             }
01747             else {
01748                 oldNodeValue = oldTemp;
01749             }
01750             XMLString::subString(oldNodeValue, txtValue, offset, endLen, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01751 
01752             if ( how != CLONE_CONTENTS )
01753                 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
01754 
01755             if (offset>= 3999)
01756                 fMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue;
01757         }
01758 
01759         if ( how==DELETE_CONTENTS )
01760             return 0;
01761 
01762         DOMNode* newNode = n->cloneNode( false );
01763 
01764         if (offset == 0) {
01765             newNode->setNodeValue(XMLUni::fgZeroLenString);
01766         }
01767         else {
01768             XMLCh* newNodeValue;
01769             XMLCh newTemp[4000];
01770 
01771             if (offset >= 3999)  {
01772                 newNodeValue = (XMLCh*) fMemoryManager->allocate
01773                 (
01774                     (offset+1) * sizeof(XMLCh)
01775                 );//new XMLCh[offset+1];
01776             }
01777             else {
01778                 newNodeValue = newTemp;
01779             }
01780             XMLString::subString(newNodeValue, txtValue, 0, offset, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
01781             newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
01782 
01783             if (offset>= 3999)
01784                 fMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue;
01785 
01786         }
01787         return newNode;
01788     }
01789 }
01790 
01799 DOMNode* DOMRangeImpl::getSelectedNode( DOMNode*container, int offset )
01800 {
01801     short type = container->getNodeType();
01802     if((type == DOMNode::TEXT_NODE
01803         || type == DOMNode::CDATA_SECTION_NODE
01804         || type == DOMNode::COMMENT_NODE
01805         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01806         return container;
01807 
01808     // This case is an important convenience for
01809     // traverseRightBoundary()
01810     if ( offset<0 )
01811         return container;
01812 
01813     DOMNode*child = container->getFirstChild();
01814     while( child!=0 && offset > 0 )
01815     {
01816         --offset;
01817         child = child->getNextSibling();
01818     }
01819     if ( child!=0 )
01820         return child;
01821     return container;
01822 }
01823 
01824 void DOMRangeImpl::checkReadOnly(DOMNode* start, DOMNode* end,
01825                               XMLSize_t startOffset, XMLSize_t endOffset)
01826 {
01827     if ((start == 0) || (end == 0) ) return;
01828     DOMNode*sNode = 0;
01829 
01830     short type = start->getNodeType();
01831     if ( type == DOMNode::DOCUMENT_TYPE_NODE )
01832     {
01833         throw DOMException(
01834             DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager);
01835     }
01836 
01837     if((type == DOMNode::TEXT_NODE
01838         || type == DOMNode::CDATA_SECTION_NODE
01839         || type == DOMNode::COMMENT_NODE
01840         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01841     {
01842         if (castToNodeImpl(start)->isReadOnly()) {
01843             throw DOMException(
01844                 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager);
01845         }
01846         //if both start and end are text check and return
01847         if (start == end)
01848             return;
01849 
01850         sNode = start;
01851     } else {
01852         //set the start and end nodes to check
01853         sNode = start->getFirstChild();
01854         for(XMLSize_t i = 0; i<startOffset; i++)
01855             sNode = sNode->getNextSibling();
01856     }
01857 
01858     DOMNode* eNode;
01859     type = end->getNodeType();
01860     if ( type == DOMNode::DOCUMENT_TYPE_NODE )
01861     {
01862         throw DOMException(
01863             DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager);
01864     }
01865 
01866     if((type == DOMNode::TEXT_NODE
01867         || type == DOMNode::CDATA_SECTION_NODE
01868         || type == DOMNode::COMMENT_NODE
01869         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01870     {
01871         eNode = end; //need to check only till this node
01872     }
01873     else { //need to check all the kids that fall before the end offset value
01874         eNode = end->getFirstChild();
01875         if (endOffset > 0)  {
01876             for (XMLSize_t i = 0; i<endOffset-1; i++)
01877                 eNode = eNode->getNextSibling();
01878         }
01879     }
01880     //recursivly search if any node is readonly
01881     recurseTreeAndCheck(sNode, eNode);
01882 }
01883 
01884 void DOMRangeImpl::recurseTreeAndCheck(DOMNode* start, DOMNode* end)
01885 {
01886     for(DOMNode* node=start; node != 0 && node !=end; node=node->getNextSibling())
01887     {
01888         if ( node->getNodeType()== DOMNode::DOCUMENT_TYPE_NODE )
01889         {
01890             throw DOMException(
01891                 DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager);
01892         }
01893 
01894         if (castToNodeImpl(node)->isReadOnly()) {
01895             throw DOMException(
01896                 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager);
01897         }
01898 
01899         if (node->hasChildNodes()) {
01900             node = node->getFirstChild();
01901             recurseTreeAndCheck(node, end);
01902         }
01903     }
01904 }
01905 
01906 
01907 DOMNode* DOMRangeImpl::removeChild(DOMNode* parent, DOMNode* child)
01908 {
01909     fRemoveChild = child; //only a precaution measure not to update this range data before removal
01910     DOMNode*n = parent->removeChild(child);
01911     fRemoveChild = 0;
01912     return n;
01913 }
01914 
01915 
01916 //
01917 // Mutation functions
01918 //
01919 
01920 
01921 /* This function is called from DOM.
01922 *  The  text has already been replaced.
01923 *  Fix-up any offsets.
01924 */
01925 void DOMRangeImpl::receiveReplacedText(DOMNode* node)
01926 {
01927     if (node == 0) return;
01928 
01929     short type = fStartContainer->getNodeType();
01930     if (node == fStartContainer
01931         && (type == DOMNode::TEXT_NODE
01932         || type == DOMNode::CDATA_SECTION_NODE
01933         || type == DOMNode::COMMENT_NODE
01934         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01935     {
01936         fStartOffset = 0;
01937     }
01938     type = fEndContainer->getNodeType();
01939     if (node == fEndContainer
01940         && (type == DOMNode::TEXT_NODE
01941         || type == DOMNode::CDATA_SECTION_NODE
01942         || type == DOMNode::COMMENT_NODE
01943         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01944     {
01945         fEndOffset = 0;
01946     }
01947 }
01948 
01949 
01954 void DOMRangeImpl::updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, XMLSize_t count)
01955 {
01956     if (node == 0) return;
01957 
01958     short type = fStartContainer->getNodeType();
01959     if (node == fStartContainer
01960         && (type == DOMNode::TEXT_NODE
01961         || type == DOMNode::CDATA_SECTION_NODE
01962         || type == DOMNode::COMMENT_NODE
01963         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01964     {
01965         if (fStartOffset > offset+count) {
01966             fStartOffset = fStartOffset-count;
01967         } else if (fStartOffset > offset) {
01968             fStartOffset = offset;
01969         }
01970     }
01971     type = fEndContainer->getNodeType();
01972     if (node == fEndContainer
01973         && (type == DOMNode::TEXT_NODE
01974         || type == DOMNode::CDATA_SECTION_NODE
01975         || type == DOMNode::COMMENT_NODE
01976         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
01977     {
01978         if (fEndOffset > offset+count) {
01979             fEndOffset = fEndOffset-count;
01980         } else if (fEndOffset > offset) {
01981             fEndOffset = offset;
01982         }
01983     }
01984 }
01985 
01986 
01987 
01992 void DOMRangeImpl::updateRangeForInsertedText(DOMNode* node, XMLSize_t offset, XMLSize_t count)
01993 {
01994     if (node == 0) return;
01995 
01996     short type = fStartContainer->getNodeType();
01997     if (node == fStartContainer
01998         && (type == DOMNode::TEXT_NODE
01999         || type == DOMNode::CDATA_SECTION_NODE
02000         || type == DOMNode::COMMENT_NODE
02001         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
02002     {
02003         if (fStartOffset > offset) {
02004             fStartOffset = offset;
02005         }
02006     }
02007     type = fEndContainer->getNodeType();
02008     if (node == fEndContainer
02009         && (type == DOMNode::TEXT_NODE
02010         || type == DOMNode::CDATA_SECTION_NODE
02011         || type == DOMNode::COMMENT_NODE
02012         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
02013     {
02014         if (fEndOffset > offset) {
02015             fEndOffset = fEndOffset+count;
02016         }
02017     }
02018 }
02019 
02020 
02021 
02026 void DOMRangeImpl::updateRangeForDeletedNode(DOMNode* node)
02027 {
02028 
02029     if (node == 0) return;
02030     if (fRemoveChild == node) return;
02031 
02032     if (node->getParentNode() == fStartContainer) {
02033         XMLSize_t index = indexOf(node, fStartContainer);
02034         if ( fStartOffset > index) {
02035             fStartOffset--;
02036         }
02037     }
02038 
02039     if (node->getParentNode() == fEndContainer) {
02040         XMLSize_t index = indexOf(node, fEndContainer);
02041         if ( fEndOffset > index) {
02042             fEndOffset--;
02043         }
02044     }
02045 
02046     if (node->getParentNode() != fStartContainer
02047         ||  node->getParentNode() != fEndContainer) {
02048         if (isAncestorOf(node, fStartContainer)) {
02049             DOMNode* tpNode = node->getParentNode();
02050             setStartContainer( tpNode );
02051             fStartOffset = indexOf( node, tpNode);
02052         }
02053         if (isAncestorOf(node, fEndContainer)) {
02054             DOMNode* tpNode = node->getParentNode();
02055             setEndContainer( tpNode );
02056             fEndOffset = indexOf( node, tpNode);
02057         }
02058     }
02059 
02060 }
02061 
02062 void DOMRangeImpl::updateRangeForInsertedNode(DOMNode* node) {
02063     if (node == 0) return;
02064 
02065     if (node->getParentNode() == fStartContainer) {
02066         XMLSize_t index = indexOf(node, fStartContainer);
02067         if (index < fStartOffset) {
02068             fStartOffset++;
02069         }
02070     }
02071 
02072     if (node->getParentNode() == fEndContainer) {
02073         XMLSize_t index = indexOf(node, fEndContainer);
02074         if (index < fEndOffset) {
02075             fEndOffset++;
02076         }
02077     }
02078 }
02079 
02080 
02081 void DOMRangeImpl::updateSplitInfo(DOMNode* oldNode, DOMNode* startNode, XMLSize_t offset)
02082 {
02083     if (startNode == 0) return;
02084 
02085     short type = fStartContainer->getNodeType();
02086     if (oldNode == fStartContainer
02087         && (type == DOMNode::TEXT_NODE
02088         || type == DOMNode::CDATA_SECTION_NODE
02089         || type == DOMNode::COMMENT_NODE
02090         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
02091     {
02092         if (fStartOffset > offset) {
02093             fStartOffset = fStartOffset - offset;
02094             fStartContainer = startNode;
02095         }
02096     }
02097 
02098     type = fEndContainer->getNodeType();
02099     if (oldNode == fEndContainer
02100         && (type == DOMNode::TEXT_NODE
02101         || type == DOMNode::CDATA_SECTION_NODE
02102         || type == DOMNode::COMMENT_NODE
02103         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
02104     {
02105         if (fEndOffset > offset) {
02106             fEndContainer = startNode;
02107            fEndOffset = fEndOffset - offset;
02108         }
02109     }
02110 }
02111 
02112 
02113 
02114 XERCES_CPP_NAMESPACE_END
02115