IDRangeImpl.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:52k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 2001, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: IDRangeImpl.cpp,v 1.3 2001/06/04 14:55:36 tng Exp $
  58.  */
  59. #include "IDNodeImpl.hpp"
  60. #include "IDRangeImpl.hpp"
  61. #include "IDTextImpl.hpp"
  62. #include "IDDocumentImpl.hpp"
  63. #include "IDOM_DOMException.hpp"
  64. #include "IDOM_Document.hpp"
  65. #include "IDDocumentFragmentImpl.hpp"
  66. #include "IDOM_Document.hpp"
  67. #include "IDOM_RangeException.hpp"
  68. #include "IDOM_DOMException.hpp"
  69. #include "IDOM_Text.hpp"
  70. #include "IDCasts.hpp"
  71. #include <framework/XMLBuffer.hpp>
  72. //---------------------
  73. // C'tor and D'tor
  74. //---------------------
  75. IDRangeImpl::IDRangeImpl(IDOM_Document* doc)
  76.     :   fDocument(doc),
  77.         fStartContainer(doc),
  78.         fStartOffset(0),
  79.         fEndContainer(doc),
  80.         fEndOffset(0),
  81.         fDetached(false),
  82.         fCollapsed(true),
  83.         fRemoveChild(0)
  84. {
  85. }
  86. IDRangeImpl::IDRangeImpl(const IDRangeImpl& other)
  87. {
  88.     fDocument = other.fDocument;
  89.     fStartContainer = other.fStartContainer;
  90.     fStartOffset = other.fStartOffset;
  91.     fEndContainer = other.fEndContainer;
  92.     fEndOffset = other.fEndOffset;
  93.     fDetached = other.fDetached;
  94.     fCollapsed = other.fCollapsed;
  95.     fRemoveChild = other.fRemoveChild;
  96. }
  97. IDRangeImpl::~IDRangeImpl()
  98. {
  99. }
  100. //-------------------------------
  101. // Public getter functions
  102. //-------------------------------
  103. IDOM_Node* IDRangeImpl::getStartContainer() const
  104. {
  105.     return fStartContainer;
  106. }
  107. unsigned int IDRangeImpl::getStartOffset() const
  108. {
  109.     return fStartOffset;
  110. }
  111. IDOM_Node* IDRangeImpl::getEndContainer() const
  112. {
  113.     return fEndContainer;
  114. }
  115. unsigned int IDRangeImpl::getEndOffset() const
  116. {
  117.     return fEndOffset;
  118. }
  119. bool IDRangeImpl::getCollapsed() const
  120. {
  121.     if (fDetached)
  122.     {
  123.         throw IDOM_DOMException(
  124.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  125.     }
  126.     return ((fStartContainer == fEndContainer)
  127.              && (fStartOffset == fEndOffset));
  128. }
  129. //-------------------------------
  130. // Public getter functions
  131. //-------------------------------
  132. void IDRangeImpl::setStartContainer(const IDOM_Node* node)
  133. {
  134.     if (fDetached)
  135.     {
  136.         throw IDOM_DOMException(
  137.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  138.     }
  139.     fStartContainer = (IDOM_Node*) node;
  140. }
  141. void IDRangeImpl::setStartOffset(unsigned int offset)
  142. {
  143.     if (fDetached)
  144.     {
  145.         throw IDOM_DOMException(
  146.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  147.     }
  148.     fStartOffset = offset;
  149. }
  150. void IDRangeImpl::setEndContainer(const IDOM_Node* node)
  151. {
  152.     if (fDetached)
  153.     {
  154.         throw IDOM_DOMException(
  155.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  156.     }
  157.     fEndContainer = (IDOM_Node*) node;
  158. }
  159. void IDRangeImpl::setEndOffset(unsigned int offset)
  160. {
  161.     if (fDetached)
  162.     {
  163.         throw IDOM_DOMException(
  164.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  165.     }
  166.     fEndOffset = offset;
  167. }
  168. void IDRangeImpl::setStart(const IDOM_Node* refNode, unsigned int offset)
  169. {
  170.     validateNode(refNode);
  171.     checkIndex(refNode, offset);
  172.     fStartContainer = (IDOM_Node*) refNode;
  173.     fStartOffset    = offset;
  174.     if ((fDocument != refNode->getOwnerDocument() )
  175.         && (refNode->getOwnerDocument() != 0) )
  176.     {
  177.         fDocument = refNode->getOwnerDocument();
  178.         collapse(true);
  179.     }
  180.     //compare the start and end boundary point
  181.     //collapse if start point is after the end point
  182.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  183.         collapse(true); //collapse the range positions to start
  184.     else
  185.         fCollapsed = false;
  186. }
  187. void IDRangeImpl::setEnd(const IDOM_Node* refNode, unsigned int offset)
  188. {
  189.     validateNode(refNode);
  190.     checkIndex(refNode, offset);
  191.     fEndContainer   = (IDOM_Node*) refNode;
  192.     fEndOffset      = offset;
  193.     if ((fDocument != refNode->getOwnerDocument() )
  194.         && (refNode->getOwnerDocument() != 0) )
  195.     {
  196.         fDocument = refNode->getOwnerDocument();
  197.         collapse(false);
  198.     }
  199.     //compare the start and end boundary point
  200.     //collapse if start point is after the end point
  201.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  202.         collapse(false); //collapse the range positions to end
  203.     else
  204.         fCollapsed = false;
  205. }
  206. void IDRangeImpl::setStartBefore(const IDOM_Node* refNode)
  207. {
  208.     if( fDetached) {
  209.         throw IDOM_DOMException(
  210.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  211.     }
  212.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  213.         throw IDOM_RangeException(
  214.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  215.     }
  216.     fStartContainer = refNode->getParentNode();
  217.    unsigned int i = 0;
  218.     for (IDOM_Node* n = (IDOM_Node*) refNode; n!=0; n = n->getPreviousSibling()) {
  219.         i++;
  220.     }
  221.     if (i == 0)
  222.         fStartOffset = 0;
  223.     else
  224.         fStartOffset = i-1;
  225.     if ((fDocument != refNode->getOwnerDocument())
  226.         && (refNode->getOwnerDocument() != 0) )
  227.     {
  228.         fDocument = refNode->getOwnerDocument();
  229.         collapse(true);
  230.     }
  231.     //compare the start and end boundary point
  232.     //collapse if start point is after the end point
  233.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  234.         collapse(true); //collapse the range positions to start
  235.     else
  236.         fCollapsed = false;
  237. }
  238. void IDRangeImpl::setStartAfter(const IDOM_Node* refNode)
  239. {
  240.     if( fDetached) {
  241.         throw IDOM_DOMException(
  242.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  243.     }
  244.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  245.         throw IDOM_RangeException(
  246.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  247.     }
  248.     fStartContainer = refNode->getParentNode();
  249.     unsigned int i = 0;
  250.     for (IDOM_Node* n = (IDOM_Node*) refNode; n!=0; n = n->getPreviousSibling()) {
  251.         i++;
  252.     }
  253.     fStartOffset = i;
  254.     if ((fDocument != refNode->getOwnerDocument() )
  255.         && (refNode->getOwnerDocument() != 0) )
  256.     {
  257.         fDocument = refNode->getOwnerDocument();
  258.         collapse(true);
  259.     }
  260.     //compare the start and end boundary point
  261.     //collapse if start point is after the end point
  262.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  263.         collapse(true); //collapse the range positions to start
  264.     else
  265.         fCollapsed = false;
  266. }
  267. void IDRangeImpl::setEndBefore(const IDOM_Node* refNode)
  268. {
  269.     if( fDetached) {
  270.         throw IDOM_DOMException(
  271.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  272.     }
  273.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  274.         throw IDOM_RangeException(
  275.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  276.     }
  277.     fEndContainer = refNode->getParentNode();
  278.     unsigned int i = 0;
  279.     for (IDOM_Node* n = (IDOM_Node*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
  280.     if (i< 1)
  281.         fEndOffset = 0;
  282.     else
  283.         fEndOffset = i-1;
  284.     if ((fDocument != refNode->getOwnerDocument() )
  285.         && (refNode->getOwnerDocument() != 0) )
  286.     {
  287.         fDocument = refNode->getOwnerDocument();
  288.         collapse(true);
  289.     }
  290.     //compare the start and end boundary point
  291.     //collapse if start point is after the end point
  292.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  293.         collapse(false); //collapse the range positions to end
  294.     else
  295.         fCollapsed = false;
  296. }
  297. void IDRangeImpl::setEndAfter(const IDOM_Node* refNode)
  298. {
  299.     if( fDetached) {
  300.         throw IDOM_DOMException(
  301.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  302.     }
  303.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  304.         throw IDOM_RangeException(
  305.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  306.     }
  307.     fEndContainer = refNode->getParentNode();
  308.     unsigned int i = 0;
  309.     for (IDOM_Node* n = (IDOM_Node*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
  310.     if (i ==0)
  311.         fEndOffset = 0;
  312.     else
  313.         fEndOffset = i;
  314.     if ((fDocument != refNode->getOwnerDocument() )
  315.         && (refNode->getOwnerDocument() != 0) )
  316.     {
  317.         fDocument = refNode->getOwnerDocument();
  318.         collapse(true);
  319.     }
  320.     //compare the start and end boundary point
  321.     //collapse if start point is after the end point
  322.     if(compareBoundaryPoints(IDOM_Range::END_TO_START, this) == 1)
  323.         collapse(false); //collapse the range positions to end
  324.     else
  325.         fCollapsed = false;
  326. }
  327. //-------------------------------
  328. // Public Misc. functions
  329. //-------------------------------
  330. void IDRangeImpl::detach()
  331. {
  332.     if( fDetached) {
  333.         throw IDOM_DOMException(
  334.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  335.     }
  336.     fDetached = true;
  337.     //0ify nodes
  338.     fStartContainer = 0;
  339.     fStartOffset    = 0;
  340.     fEndContainer   = 0;
  341.     fEndOffset      = 0;
  342.     fCollapsed      = true;
  343.     fRemoveChild    = 0;
  344. }
  345. void IDRangeImpl::collapse(bool toStart)
  346. {
  347.     if( fDetached) {
  348.         throw IDOM_DOMException(
  349.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  350.     }
  351.     if (toStart) {
  352.         fEndContainer = fStartContainer;
  353.         fEndOffset = fStartOffset;
  354.     } else {
  355.         fStartContainer = fEndContainer;
  356.         fStartOffset = fEndOffset;
  357.     }
  358.     fCollapsed = true;
  359. }
  360. void IDRangeImpl::selectNode(const IDOM_Node* refNode)
  361. {
  362.     validateNode(refNode);
  363.     if ( !isLegalContainedNode(refNode)) {
  364.         throw IDOM_RangeException(
  365.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  366.     }
  367.     //First check for the text type node
  368.     if (refNode->getNodeType() ==  IDOM_Node::TEXT_NODE)
  369.     {
  370.         //The node itself is the container.
  371.         fStartContainer = (IDOM_Node*) refNode;
  372.         fEndContainer   = (IDOM_Node*) refNode;
  373.         //Select all the contents of the node
  374.         fStartOffset = 0;
  375.         fEndOffset = ((IDOM_Text *)refNode)->getLength();
  376.         return;
  377.     }
  378.     IDOM_Node* parent = refNode->getParentNode();
  379.     if (parent != 0 ) // REVIST: what to do if it IS 0?
  380.     {
  381.         fStartContainer = parent;
  382.         fEndContainer = parent;
  383.         unsigned int i = 0;
  384.         for (IDOM_Node* n = parent->getFirstChild(); n!=0, n!=refNode; n = n->getNextSibling()) {
  385.             i++;
  386.         }
  387.         fStartOffset = i;
  388.         fEndOffset = fStartOffset+1;
  389.     }
  390. }
  391. void IDRangeImpl::selectNodeContents(const IDOM_Node* node)
  392. {
  393.     validateNode(node);
  394.     fStartContainer = (IDOM_Node*) node;
  395.     fEndContainer = (IDOM_Node*) node;
  396.     fStartOffset = 0;
  397.     if (node->getNodeType() == IDOM_Node::TEXT_NODE ) {
  398.         fEndOffset = ((IDOM_Text *)node)->getLength();
  399.         return;
  400.     }
  401.     IDOM_Node* first = node->getFirstChild();
  402.     if (first == 0) {
  403.         fEndOffset = 0;
  404.         return;
  405.     }
  406.     unsigned int i = 0;
  407.     for (IDOM_Node* n = first; n!=0; n = n->getNextSibling()) {
  408.         i++;
  409.     }
  410.     fEndOffset = i;
  411. }
  412. void IDRangeImpl::surroundContents(IDOM_Node* newParent)
  413. {
  414.     if (newParent==0) return;
  415.     //check for elimination criteria
  416.     if( fDetached) {
  417.         throw IDOM_DOMException(
  418.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  419.     }
  420.     if (newParent->getOwnerDocument() !=fDocument) {
  421.         throw IDOM_DOMException(
  422.             IDOM_DOMException::WRONG_DOCUMENT_ERR, 0);
  423.     }
  424.     int type = newParent->getNodeType();
  425.     if ( !isLegalContainedNode(newParent)
  426.         || type == IDOM_Node::DOCUMENT_TYPE_NODE)
  427.     {
  428.         throw IDOM_RangeException(
  429.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  430.     }
  431.     IDOM_Node* root = (IDOM_Node*) getCommonAncestorContainer();
  432.     IDOM_Node* realStart = fStartContainer;
  433.     IDOM_Node* realEnd = fEndContainer;
  434.     if (fStartContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  435.         realStart = fStartContainer->getParentNode();
  436.     }
  437.     if (fEndContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  438.         realEnd = fEndContainer->getParentNode();
  439.     }
  440.     if (realStart != realEnd) {
  441.         throw IDOM_RangeException(
  442.             IDOM_RangeException::BAD_BOUNDARYPOINTS_ERR, 0);
  443.     }
  444.     IDOM_DocumentFragment* frag = (IDOM_DocumentFragment*) extractContents();
  445.     insertNode(newParent);
  446.     newParent->appendChild(frag);
  447.     selectNode(newParent);
  448. }
  449. short IDRangeImpl::compareBoundaryPoints(IDOM_Range::CompareHow how, const IDOM_Range* srcRange) const
  450. {
  451.     if (fDocument != ((IDRangeImpl*)srcRange)->fDocument) {
  452.         throw IDOM_DOMException(
  453.             IDOM_DOMException::WRONG_DOCUMENT_ERR, 0);
  454.     }
  455.     if( fDetached) {
  456.         throw IDOM_DOMException(
  457.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  458.     }
  459.     IDOM_Node* pointA;
  460.     IDOM_Node* pointB;
  461.     int offsetA, offsetB;
  462.     switch (how)
  463.     {
  464.     case (IDOM_Range::START_TO_START) :
  465.         pointB = srcRange->getStartContainer();
  466.         pointA = fStartContainer;
  467.         offsetB = srcRange->getStartOffset();
  468.         offsetA = fStartOffset;
  469.         break;
  470.     case (IDOM_Range::START_TO_END) :
  471.         pointB = srcRange->getStartContainer();
  472.         pointA = fEndContainer;
  473.         offsetB = srcRange->getStartOffset();
  474.         offsetA = fEndOffset;
  475.         break;
  476.     case (IDOM_Range::END_TO_START) :
  477.         pointB = srcRange->getEndContainer();
  478.         pointA = fStartContainer;
  479.         offsetB = srcRange->getEndOffset();
  480.         offsetA = fStartOffset;
  481.         break;
  482.     case (IDOM_Range::END_TO_END) :
  483.         pointB = srcRange->getEndContainer();
  484.         pointA = fEndContainer;
  485.         offsetB = srcRange->getEndOffset();
  486.         offsetA = fEndOffset;
  487.         break;
  488.     }
  489.     // case 1: same container
  490.     if (pointA == pointB) {
  491.         if (offsetA < offsetB) return -1; //A before B
  492.         if (offsetA == offsetB) return 0; //A equal to B
  493.         return 1; // A after B
  494.     }
  495.     // case 2: Child C of container A is ancestor of B
  496.     for (IDOM_Node* node = pointA->getFirstChild(); node != 0; node=node->getNextSibling()) {
  497.         if (isAncestorOf(node, pointB)) {
  498.             int index = indexOf(node, pointA);
  499.             if (offsetA <=  index) return -1;
  500.             return 1;
  501.         }
  502.     }
  503.     // case 3: Child C of container B is ancestor of A
  504.     for (IDOM_Node* nd = pointB->getFirstChild(); nd != 0; nd=nd->getNextSibling()) {
  505.         if (isAncestorOf(nd, pointA)) {
  506.             int index = indexOf(nd, pointB);
  507.             if (index < offsetB ) return -1;
  508.             return 1; //B strictly before A
  509.         }
  510.     }
  511.     // case 4: preorder traversal of context tree.
  512.     IDOM_Node* ancestor = (IDOM_Node*) commonAncestorOf(pointA, pointB);
  513.     IDOM_Node* current = ancestor;
  514.     do {
  515.         if (current == pointA) return -1;
  516.         if (current == pointB) return 1;
  517.         current = nextNode(current, true);
  518.     }
  519.     while (current!=0 && current!=ancestor);
  520.     return -2; // this should never happen
  521. }
  522. void IDRangeImpl:: deleteContents()
  523. {
  524.     traverseContents(DELETE_CONTENTS);
  525. }
  526. IDOM_DocumentFragment* IDRangeImpl::extractContents()
  527. {
  528.     checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
  529.     return traverseContents(EXTRACT_CONTENTS);
  530. }
  531. IDOM_DocumentFragment* IDRangeImpl::cloneContents() const
  532. {
  533.     // cast off const.
  534.     return ((IDRangeImpl *)this)->traverseContents(CLONE_CONTENTS);
  535. }
  536. void IDRangeImpl::insertNode(IDOM_Node* newNode)
  537. {
  538.     if (newNode == 0) return; //don't have to do anything
  539.     for (IDOM_Node* aNode = fStartContainer; aNode!=0; aNode = aNode->getParentNode()) {
  540.         if (castToNodeImpl(newNode)->isReadOnly()) {
  541.         throw IDOM_DOMException(
  542.             IDOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  543.     }
  544.     }
  545.     if (fDocument != newNode->getOwnerDocument()) {
  546.         throw IDOM_DOMException(
  547.             IDOM_DOMException::WRONG_DOCUMENT_ERR, 0);
  548.     }
  549.     // Prevent cycles in the tree.
  550.     //isKidOK() is not checked here as its taken care by insertBefore() function
  551.     if (isAncestorOf( newNode, fStartContainer)) {
  552.         throw IDOM_DOMException(
  553.             IDOM_DOMException::HIERARCHY_REQUEST_ERR, 0);
  554.     }
  555.     if( fDetached) {
  556.         throw IDOM_DOMException(
  557.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  558.     }
  559.     int type = newNode->getNodeType();
  560.     if (type == IDOM_Node::ATTRIBUTE_NODE
  561.         || type == IDOM_Node::ENTITY_NODE
  562.         || type == IDOM_Node::NOTATION_NODE
  563.         || type == IDOM_Node::DOCUMENT_NODE)
  564.     {
  565.         throw IDOM_RangeException(
  566.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  567.     }
  568.     IDOM_Node* parent;
  569.     IDOM_Node* next;
  570.     if (fStartContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  571.         //set 'parent' and 'next' here
  572.         parent = fStartContainer->getParentNode();
  573.         //split the text nodes
  574.        if (fStartOffset > 0)
  575.             ((IDOM_Text*)fStartContainer)->splitText(fStartOffset);
  576.         //update the new start information later. After inserting the first newNode
  577.         if (fStartOffset == 0)
  578.             next = fStartContainer;
  579.         else
  580.             next = fStartContainer->getNextSibling();
  581.     } // end of text handling
  582.     else {
  583.         parent = fStartContainer;
  584.         next = fStartContainer->getFirstChild();
  585.         for(unsigned int i = 0; (i < fStartOffset) && (next != 0); i++) {
  586.             next=next->getNextSibling();
  587.         }
  588.     }
  589.     if (parent != 0) {
  590.         if (next != 0)
  591.             parent->insertBefore(newNode, next);
  592.         else
  593.             parent->appendChild(newNode);
  594.     }
  595. }
  596. IDOM_Range* IDRangeImpl::cloneRange() const
  597. {
  598.     if( fDetached) {
  599.         throw IDOM_DOMException(
  600.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  601.     }
  602.     IDOM_Range* range = fDocument->createRange();
  603.     range->setStart(fStartContainer, fStartOffset);
  604.     range->setEnd(fEndContainer, fEndOffset);
  605.     return range;
  606. }
  607. const XMLCh* IDRangeImpl::toString() const
  608. {
  609.     if( fDetached) {
  610.         throw IDOM_DOMException(
  611.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  612.     }
  613.     IDOM_Node* node = fStartContainer;
  614.     IDOM_Node* stopNode = fEndContainer;
  615.     XMLBuffer retStringBuf;
  616.     if ( (fStartContainer->getNodeType() == IDOM_Node::TEXT_NODE)
  617.         || (fStartContainer->getNodeType() == IDOM_Node::CDATA_SECTION_NODE) ) {
  618.         if (fStartContainer == fEndContainer) {
  619.             if (fEndOffset == fStartOffset) {
  620.                 return XMLUni::fgZeroLenString;
  621.             }
  622.             else {
  623.                 XMLCh* tempString;
  624.                 XMLCh temp[4000];
  625.                 if ((fEndOffset-fStartOffset) >= 3999)
  626.                     tempString = new XMLCh[fEndOffset-fStartOffset+1];
  627.                 else
  628.                     tempString = temp;
  629.                 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset);
  630.                 const XMLCh* retString = ((IDDocumentImpl *)fDocument)->getPooledString(tempString);
  631.                 if ((fEndOffset-fStartOffset) >= 3999)
  632.                     delete[] tempString;
  633.                 return retString;
  634.             }
  635.         } else {
  636.             unsigned int length = XMLString::stringLen(fStartContainer->getNodeValue());
  637.             if (length != fStartOffset) {
  638.                 XMLCh* tempString;
  639.                 XMLCh temp[4000];
  640.                 if ((length - fStartOffset) >= 3999)
  641.                     tempString = new XMLCh[length - fStartOffset+1];
  642.                 else
  643.                     tempString = temp;
  644.                 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, length);
  645.                 retStringBuf.append(tempString);
  646.                 if ((length - fStartOffset) >= 3999)
  647.                     delete[] tempString;
  648.             }
  649.             node = nextNode(node, true);
  650.         }
  651.     }else { //fStartContainer is not a TextNode
  652.         node=node->getFirstChild();
  653.         if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset
  654.             unsigned int counter = 0;
  655.             while (counter<fStartOffset && node!=0) {
  656.                 node=node->getNextSibling();
  657.                 counter++;
  658.             }
  659.         }
  660.         if (node == 0) {
  661.             node = nextNode(fStartContainer,false);
  662.         }
  663.     }
  664.     if ( fEndContainer->getNodeType()!= IDOM_Node::TEXT_NODE &&
  665.         fEndContainer->getNodeType()!= IDOM_Node::CDATA_SECTION_NODE ){
  666.         int i=fEndOffset;
  667.         stopNode = fEndContainer->getFirstChild();
  668.         while( i>0 && stopNode!=0 ){
  669.             --i;
  670.             stopNode = stopNode->getNextSibling();
  671.         }
  672.         if ( stopNode == 0 )
  673.             stopNode = nextNode( fEndContainer, false );
  674.     }
  675.     while (node != stopNode) {  //look into all kids of the Range
  676.         if (node == 0) break;
  677.         if (node->getNodeType() == IDOM_Node::TEXT_NODE
  678.             ||  node->getNodeType() == IDOM_Node::CDATA_SECTION_NODE) {
  679.             retStringBuf.append(node->getNodeValue());
  680.         }
  681.         node = nextNode(node, true);
  682.     }
  683.     if (fEndContainer->getNodeType() == IDOM_Node::TEXT_NODE
  684.         || fEndContainer->getNodeType() == IDOM_Node::CDATA_SECTION_NODE) {
  685.         if (fEndOffset != 0) {
  686.             XMLCh* tempString;
  687.             XMLCh temp[4000];
  688.             if (fEndOffset >= 3999)
  689.                 tempString = new XMLCh[fEndOffset+1];
  690.             else
  691.                 tempString = temp;
  692.             XMLString::subString(tempString, fEndContainer->getNodeValue(), 0, fEndOffset);
  693.             retStringBuf.append(tempString);
  694.             if (fEndOffset >= 3999)
  695.                 delete[] tempString;
  696.         }
  697.     }
  698.     return ((IDDocumentImpl *)fDocument)->getPooledString(retStringBuf.getRawBuffer());
  699. }
  700. IDOM_Document* IDRangeImpl::getDocument()
  701. {
  702.     return fDocument;
  703. }
  704. const IDOM_Node* IDRangeImpl::getCommonAncestorContainer() const
  705. {
  706.      return commonAncestorOf(fStartContainer, fEndContainer);
  707. }
  708. //---------------------
  709. //private functions
  710. //---------------------
  711. bool IDRangeImpl::isValidAncestorType(const IDOM_Node* node) const
  712. {
  713.     for (IDOM_Node* aNode = (IDOM_Node*) node; aNode!=0; aNode = aNode->getParentNode()) {
  714.         short type = aNode->getNodeType();
  715.         if ( type == IDOM_Node::ENTITY_NODE
  716.             || type == IDOM_Node::NOTATION_NODE
  717.             || type == IDOM_Node::DOCUMENT_TYPE_NODE)
  718.             return false;
  719.     }
  720.     return true;
  721. }
  722. bool IDRangeImpl::isAncestorOf(const IDOM_Node* a, const IDOM_Node* b) {
  723.     for (IDOM_Node* node = (IDOM_Node*) b; node != 0; node=node->getParentNode()) {
  724.         if  (node == a) return true;
  725.     }
  726.     return false;
  727. }
  728. bool IDRangeImpl::hasLegalRootContainer(const IDOM_Node* node) const {
  729.     if ( node==0 )
  730.         return false;
  731.     IDOM_Node* rootContainer = (IDOM_Node*)node;
  732.     for (; rootContainer->getParentNode()!=0; rootContainer = rootContainer->getParentNode())
  733.         ;
  734.     switch( rootContainer->getNodeType() ) {
  735.         case IDOM_Node::ATTRIBUTE_NODE:
  736.         case IDOM_Node::DOCUMENT_NODE:
  737.         case IDOM_Node::DOCUMENT_FRAGMENT_NODE:
  738.         return true;
  739.     }
  740.     return false;
  741. }
  742. bool IDRangeImpl::isLegalContainedNode(const IDOM_Node* node ) const {
  743.    if ( node==0 )
  744.        return false;
  745.    switch( node->getNodeType() )
  746.    {
  747.        case IDOM_Node::DOCUMENT_NODE:
  748.        case IDOM_Node::DOCUMENT_FRAGMENT_NODE:
  749.        case IDOM_Node::ATTRIBUTE_NODE:
  750.        case IDOM_Node::ENTITY_NODE:
  751.        case IDOM_Node::NOTATION_NODE:
  752.        return false;
  753.    }
  754.    return true;
  755. }
  756. unsigned short IDRangeImpl::indexOf(const IDOM_Node* child, const IDOM_Node* parent) const
  757. {
  758.     unsigned short i = 0;
  759.     if (child->getParentNode() != parent) return (unsigned short)-1;
  760.     for(IDOM_Node* node = child->getPreviousSibling(); node!= 0; node=node->getPreviousSibling()) {
  761.         i++;
  762.     }
  763.     return i;
  764. }
  765. void IDRangeImpl::validateNode(const IDOM_Node* node) const
  766. {
  767.     if( fDetached) {
  768.         throw IDOM_DOMException(
  769.             IDOM_DOMException::INVALID_STATE_ERR, 0);
  770.     }
  771.     if ( !isValidAncestorType(node)) {
  772.         throw IDOM_RangeException(
  773.             IDOM_RangeException::INVALID_NODE_TYPE_ERR, 0);
  774.     }
  775. }
  776. const IDOM_Node* IDRangeImpl::commonAncestorOf(const IDOM_Node* pointA, const IDOM_Node* pointB) const
  777. {
  778.     if (fDetached)
  779.             throw IDOM_DOMException(IDOM_DOMException::INVALID_STATE_ERR, 0);
  780.     if (pointA->getOwnerDocument() != pointB->getOwnerDocument())
  781.         throw IDOM_DOMException( IDOM_DOMException::WRONG_DOCUMENT_ERR, 0 );
  782.     //if the containers are same then it itself is its common ancestor.
  783.     if (pointA == pointB)
  784.         return pointA;
  785.     typedef RefVectorOf<IDOM_Node> VectorNodes;
  786.     VectorNodes startV(1, false);
  787.     IDOM_Node* node;
  788.     for (node=fStartContainer; node != 0; node=node->getParentNode())
  789.     {
  790.         startV.addElement(node);
  791.     }
  792.     VectorNodes endV(1, false);
  793.     for (node=fEndContainer; node != 0; node=node->getParentNode())
  794.     {
  795.         endV.addElement(node);
  796.     }
  797.     int s = startV.size()-1;
  798.     int e = endV.size()-1;
  799.     IDOM_Node* commonAncestor;
  800.     while (s>=0 && e>=0) {
  801.         if (startV.elementAt(s) == endV.elementAt(e)) {
  802.             commonAncestor = startV.elementAt(s);
  803.         }
  804.         else  break;
  805.         --s;
  806.         --e;
  807.     }
  808.     return commonAncestor;
  809. }
  810. void IDRangeImpl::checkIndex(const IDOM_Node* node, unsigned int offset) const
  811. {
  812.     if (offset < 0) {
  813.         throw IDOM_DOMException( IDOM_DOMException::INDEX_SIZE_ERR, 0 );
  814.     }
  815.     short type = node->getNodeType();
  816.     if((type == IDOM_Node::TEXT_NODE
  817.         || type == IDOM_Node::CDATA_SECTION_NODE
  818.         || type == IDOM_Node::COMMENT_NODE
  819.         || type == IDOM_Node::PROCESSING_INSTRUCTION_NODE)) {
  820.         if (offset > XMLString::stringLen(node->getNodeValue()))
  821.             throw IDOM_DOMException( IDOM_DOMException::INDEX_SIZE_ERR, 0 );
  822.         else  return;
  823.     }
  824.     IDOM_Node* child = node->getFirstChild();
  825.     unsigned int i = 0;
  826.     for (; child != 0; i++) {
  827.         child = child->getNextSibling();
  828.     }
  829.     if (i < offset) {
  830.         throw IDOM_DOMException( IDOM_DOMException::INDEX_SIZE_ERR, 0 );
  831.     }
  832. }
  833. IDOM_Node* IDRangeImpl::nextNode(const IDOM_Node* node, bool visitChildren) const
  834. {
  835.     if (node == 0) return 0;
  836.     IDOM_Node* result;
  837.     if (visitChildren) {
  838.         result = node->getFirstChild();
  839.         if (result != 0) {
  840.             return result;
  841.         }
  842.     }
  843.     // if hasSibling, return sibling
  844.     result = node->getNextSibling();
  845.     if (result != 0) {
  846.         return result;
  847.     }
  848.     // return parent's 1st sibling.
  849.     IDOM_Node* parent = node->getParentNode();
  850.     while ( (parent != 0) && (parent != fDocument) )
  851.     {
  852.         result = parent->getNextSibling();
  853.         if (result != 0) {
  854.             return result;
  855.         } else {
  856.             parent = parent->getParentNode();
  857.             if (parent == fEndContainer) return parent;
  858.         }
  859.     }
  860.     // end of list, return 0
  861.     return 0;
  862. }
  863. /** This is the master routine invoked to visit the nodes
  864. *   selected by this range.  For each such node, different
  865. *   actions are taken depending on the value of the TraversalType argument.
  866. */
  867. IDOM_DocumentFragment* IDRangeImpl::traverseContents(TraversalType how)
  868. {
  869.     if (fDetached)
  870.             throw IDOM_DOMException(IDOM_DOMException::INVALID_STATE_ERR, 0);
  871.     if (fStartContainer == 0 || fEndContainer == 0) {
  872.         return 0; // REVIST: Throw exception?
  873.     }
  874.     /* Traversal is accomplished by first determining the
  875.        relationship between the endpoints of the range.
  876.        For each of four significant relationships, we will
  877.        delegate the traversal call to a method that
  878.        can make appropriate assumptions.
  879.     */
  880.     // case 1: same container
  881.     if ( fStartContainer == fEndContainer )
  882.         return traverseSameContainer( how );
  883.     // case 2: Child C of start container is ancestor of end container
  884.     for (IDOM_Node* node = fStartContainer->getFirstChild(); node != 0; node=node->getNextSibling()) {
  885.         if (isAncestorOf(node, fEndContainer))
  886.             return traverseCommonStartContainer( node, how );
  887.     }
  888.     // case 3: Child C of end container  is ancestor of start container
  889.     for (IDOM_Node* nd = fEndContainer->getFirstChild(); nd != 0; nd=nd->getNextSibling()) {
  890.         if (isAncestorOf(nd, fStartContainer))
  891.              return traverseCommonEndContainer( nd, how );
  892.         }
  893.     // case 4: preorder traversal of context tree.
  894.     // There is a common ancestor container.  Find the
  895.     // ancestor siblings that are children of that container.
  896.     IDOM_Node* ancestor = (IDOM_Node*)commonAncestorOf(fStartContainer, fEndContainer);
  897.     return traverseCommonAncestors( ancestor, ancestor, how );
  898.     }
  899. /**
  900.  * Visits the nodes selected by this range when we know
  901.  * a-priori that the start and end containers are the same.
  902.  *
  903.  */
  904. IDOM_DocumentFragment* IDRangeImpl::traverseSameContainer( int how )
  905. {
  906.     IDOM_DocumentFragment* frag = 0;
  907.     if ( how!=DELETE_CONTENTS)
  908.         frag = fDocument->createDocumentFragment();
  909.     // If selection is empty, just return the fragment
  910.     if ( fStartOffset==fEndOffset )
  911.             return frag;
  912.     IDOM_Node* current = fStartContainer;
  913.     IDOM_Node* cloneCurrent = 0;
  914.     // Text node needs special case handling
  915.     if ( fStartContainer->getNodeType()== IDOM_Node::TEXT_NODE )
  916.     {
  917.         cloneCurrent = fStartContainer->cloneNode(false);
  918.         if (fEndOffset == fStartOffset) {
  919.             cloneCurrent->setNodeValue(XMLUni::fgZeroLenString);
  920.         }
  921.         else {
  922.             XMLCh* tempString;
  923.             XMLCh temp[4000];
  924.             if (fEndOffset >= 3999)
  925.                 tempString = new XMLCh[fEndOffset+1];
  926.             else
  927.                 tempString = temp;
  928.             XMLString::subString(tempString, cloneCurrent->getNodeValue(), fStartOffset, fEndOffset);
  929.             cloneCurrent->setNodeValue(((IDDocumentImpl *)fDocument)->getPooledString(tempString));
  930.             if (fEndOffset >= 3999)
  931.                 delete[] tempString;
  932.         }
  933.         // set the original text node to its new value
  934.         if ( how != CLONE_CONTENTS )
  935.             ((IDOM_Text*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset);
  936.         if ( how != DELETE_CONTENTS)
  937.             frag->appendChild(cloneCurrent);
  938.     }
  939.     else {
  940.         // Copy nodes between the start/end offsets.
  941.         IDOM_Node* n = getSelectedNode( fStartContainer, fStartOffset );
  942.         int cnt = fEndOffset - fStartOffset;
  943.         while( cnt > 0 )
  944.         {
  945.             IDOM_Node* sibling = n->getNextSibling();
  946.             IDOM_Node* xferNode = traverseFullySelected( n, how );
  947.             if ( frag!=0 )
  948.                 frag->appendChild( xferNode );
  949.             --cnt;
  950.             n = sibling;
  951.             }
  952.     }
  953.     // Nothing is partially selected, so collapse to start point
  954.     if ( how != CLONE_CONTENTS )
  955.             collapse(true);
  956.     return frag;
  957. }
  958. /**
  959.  * Visits the nodes selected by this range when we know
  960.  * a-priori that the start and end containers are not the
  961.  * same, but the start container is an ancestor of the end container
  962.  *
  963.  */
  964. IDOM_DocumentFragment* IDRangeImpl::traverseCommonStartContainer( IDOM_Node*endAncestor, int how )
  965. {
  966.     IDOM_DocumentFragment* frag = 0;
  967.     if ( how!=DELETE_CONTENTS)
  968.         frag = fDocument->createDocumentFragment();
  969.     IDOM_Node*n = traverseRightBoundary( endAncestor, how );
  970.     if ( frag!=0 )
  971.         frag->appendChild( n );
  972.     int endIdx = indexOf( endAncestor, fStartContainer );
  973.     int cnt = endIdx - fStartOffset;
  974.     if ( cnt <=0 )
  975.     {
  976.         // Collapse to just before the endAncestor, which
  977.         // is partially selected.
  978.         if ( how != CLONE_CONTENTS )
  979.         {
  980.             setEndBefore( endAncestor );
  981.             collapse( false );
  982.         }
  983.         return frag;
  984.     }
  985.     n = endAncestor->getPreviousSibling();
  986.     while( cnt > 0 )
  987.     {
  988.         IDOM_Node* sibling = n->getPreviousSibling();
  989.         IDOM_Node* xferNode = traverseFullySelected( n, how );
  990.         if ( frag!=0 )
  991.             frag->insertBefore( xferNode, frag->getFirstChild() );
  992.         --cnt;
  993.         n = sibling;
  994.     }
  995.     // Collapse to just before the endAncestor, which
  996.     // is partially selected.
  997.     if ( how != CLONE_CONTENTS )
  998.     {
  999.         setEndBefore( endAncestor );
  1000.         collapse( false );
  1001.     }
  1002.     return frag;
  1003. }
  1004. /**
  1005.  * Visits the nodes selected by this range when we know
  1006.  * a-priori that the start and end containers are not the
  1007.  * same, but the end container is an ancestor of the start container
  1008.  *
  1009.  */
  1010. IDOM_DocumentFragment* IDRangeImpl::traverseCommonEndContainer( IDOM_Node*startAncestor, int how )
  1011. {
  1012.     IDOM_DocumentFragment* frag = 0;
  1013.     if ( how!=DELETE_CONTENTS)
  1014.         frag = fDocument->createDocumentFragment();
  1015.     IDOM_Node* n = traverseLeftBoundary( startAncestor, how );
  1016.     if ( frag!=0 )
  1017.         frag->appendChild( n );
  1018.     int startIdx = indexOf( startAncestor, fEndContainer );
  1019.     ++startIdx;  // Because we already traversed it....
  1020.     int cnt = fEndOffset - startIdx;
  1021.     n = startAncestor->getNextSibling();
  1022.     while( cnt > 0 )
  1023.     {
  1024.         IDOM_Node* sibling = n->getNextSibling();
  1025.         IDOM_Node* xferNode = traverseFullySelected( n, how );
  1026.         if ( frag!=0 )
  1027.             frag->appendChild( xferNode );
  1028.         --cnt;
  1029.         n = sibling;
  1030.     }
  1031.     if ( how != CLONE_CONTENTS )
  1032.     {
  1033.         setStartAfter( startAncestor );
  1034.         collapse( true );
  1035.     }
  1036.     return frag;
  1037. }
  1038. /**
  1039.  * Visits the nodes selected by this range when we know
  1040.  * a-priori that the start and end containers are not
  1041.  * the same, and we also know that neither the start
  1042.  * nor end container is an ancestor of the other.
  1043.  */
  1044. IDOM_DocumentFragment* IDRangeImpl::traverseCommonAncestors( IDOM_Node*startAncestor, IDOM_Node*endAncestor, int how )
  1045. {
  1046.     IDOM_DocumentFragment* frag = 0;
  1047.     if ( how!=DELETE_CONTENTS)
  1048.         frag = fDocument->createDocumentFragment();
  1049.     IDOM_Node*n = traverseLeftBoundary( startAncestor, how );
  1050.     if ( frag!=0 )
  1051.         frag->appendChild( n );
  1052.     IDOM_Node*commonParent = startAncestor->getParentNode();
  1053.     int startOffset = indexOf( startAncestor, commonParent );
  1054.     int endOffset = indexOf( endAncestor, commonParent );
  1055.     ++startOffset;
  1056.     int cnt = endOffset - startOffset;
  1057.     IDOM_Node* sibling = startAncestor->getNextSibling();
  1058.     while( cnt > 0 )
  1059.     {
  1060.         IDOM_Node* nextSibling = sibling->getNextSibling();
  1061.         n = traverseFullySelected( sibling, how );
  1062.         if ( frag!=0 )
  1063.             frag->appendChild( n );
  1064.         sibling = nextSibling;
  1065.         --cnt;
  1066.     }
  1067.     n = traverseRightBoundary( endAncestor, how );
  1068.     if ( frag!=0 )
  1069.         frag->appendChild( n );
  1070.     if ( how != CLONE_CONTENTS )
  1071.     {
  1072.         setStartAfter( startAncestor );
  1073.         collapse( true );
  1074.     }
  1075.     return frag;
  1076. }
  1077. /**
  1078.  * Traverses the "right boundary" of this range and
  1079.  * operates on each "boundary node" according to the
  1080.  * how parameter.  It is a-priori assumed
  1081.  * by this method that the right boundary does
  1082.  * not contain the range's start container.
  1083.  *
  1084.  * A "right boundary" is best visualized by thinking
  1085.  * of a sample tree:
  1086.  *                 A
  1087.  *                /|
  1088.  *               / | 
  1089.  *              /  |  
  1090.  *             B   C   D
  1091.  *            /|     /|
  1092.  *           E F G   H I J
  1093.  *
  1094.  * Imagine first a range that begins between the
  1095.  * "E" and "F" nodes and ends between the
  1096.  * "I" and "J" nodes.  The start container is
  1097.  * "B" and the end container is "D".  Given this setup,
  1098.  * the following applies:
  1099.  *
  1100.  * Partially Selected Nodes: B, D<br>
  1101.  * Fully Selected Nodes: F, G, C, H, I
  1102.  *
  1103.  * The "right boundary" is the highest subtree node
  1104.  * that contains the ending container.  The root of
  1105.  * this subtree is always partially selected.
  1106.  *
  1107.  * In this example, the nodes that are traversed
  1108.  * as "right boundary" nodes are: H, I, and D.
  1109.  *
  1110.  */
  1111. IDOM_Node*IDRangeImpl::traverseRightBoundary( IDOM_Node*root, int how )
  1112. {
  1113.     IDOM_Node*next = getSelectedNode( fEndContainer, fEndOffset-1 );
  1114.     bool isFullySelected = ( next!=fEndContainer );
  1115.     if ( next==root )
  1116.         return traverseNode( next, isFullySelected, false, how );
  1117.     IDOM_Node*parent = next->getParentNode();
  1118.     IDOM_Node*clonedParent = traverseNode( parent, false, false, how );
  1119.     while( parent!=0 )
  1120.     {
  1121.         while( next!=0 )
  1122.         {
  1123.             IDOM_Node* prevSibling = next->getPreviousSibling();
  1124.             IDOM_Node* clonedChild =
  1125.                 traverseNode( next, isFullySelected, false, how );
  1126.             if ( how!=DELETE_CONTENTS )
  1127.             {
  1128.                 clonedParent->insertBefore(
  1129.                     clonedChild,
  1130.                     clonedParent->getFirstChild()
  1131.                 );
  1132.             }
  1133.             isFullySelected = true;
  1134.             next = prevSibling;
  1135.         }
  1136.         if ( parent==root )
  1137.             return clonedParent;
  1138.         next = parent->getPreviousSibling();
  1139.         parent = parent->getParentNode();
  1140.         IDOM_Node* clonedGrandParent = traverseNode( parent, false, false, how );
  1141.         if ( how!=DELETE_CONTENTS )
  1142.             clonedGrandParent->appendChild( clonedParent );
  1143.         clonedParent = clonedGrandParent;
  1144.     }
  1145.     // should never occur
  1146.     return 0;
  1147. }
  1148. /**
  1149.  * Traverses the "left boundary" of this range and
  1150.  * operates on each "boundary node" according to the
  1151.  * how parameter.  It is a-priori assumed
  1152.  * by this method that the left boundary does
  1153.  * not contain the range's end container.
  1154.  *
  1155.  * A "left boundary" is best visualized by thinking
  1156.  * of a sample tree:
  1157.  *
  1158.  *                 A
  1159.  *                /|
  1160.  *               / | 
  1161.  *              /  |  
  1162.  *             B   C   D
  1163.  *            /|     /|
  1164.  *           E F G   H I J
  1165.  *
  1166.  * Imagine first a range that begins between the
  1167.  * "E" and "F" nodes and ends between the
  1168.  * "I" and "J" nodes.  The start container is
  1169.  * "B" and the end container is "D".  Given this setup,
  1170.  * the following applies:
  1171.  *
  1172.  * Partially Selected Nodes: B, D<br>
  1173.  * Fully Selected Nodes: F, G, C, H, I
  1174.  *
  1175.  * The "left boundary" is the highest subtree node
  1176.  * that contains the starting container.  The root of
  1177.  * this subtree is always partially selected.
  1178.  *
  1179.  * In this example, the nodes that are traversed
  1180.  * as "left boundary" nodes are: F, G, and B.
  1181.  *
  1182.  */
  1183. IDOM_Node*IDRangeImpl::traverseLeftBoundary( IDOM_Node*root, int how )
  1184. {
  1185.     IDOM_Node*next = getSelectedNode( getStartContainer(), getStartOffset() );
  1186.     bool isFullySelected = ( next!=getStartContainer() );
  1187.     if ( next==root )
  1188.         return traverseNode( next, isFullySelected, true, how );
  1189.     IDOM_Node* parent = next->getParentNode();
  1190.     IDOM_Node* clonedParent = traverseNode( parent, false, true, how );
  1191.     while( parent!=0 )
  1192.     {
  1193.         while( next!=0 )
  1194.         {
  1195.             IDOM_Node* nextSibling = next->getNextSibling();
  1196.             IDOM_Node* clonedChild =
  1197.                 traverseNode( next, isFullySelected, true, how );
  1198.             if ( how!=DELETE_CONTENTS )
  1199.                 clonedParent->appendChild(clonedChild);
  1200.             isFullySelected = true;
  1201.             next = nextSibling;
  1202.         }
  1203.         if ( parent==root )
  1204.             return clonedParent;
  1205.         next = parent->getNextSibling();
  1206.         parent = parent->getParentNode();
  1207.         IDOM_Node* clonedGrandParent = traverseNode( parent, false, true, how );
  1208.         if ( how!=DELETE_CONTENTS )
  1209.             clonedGrandParent->appendChild( clonedParent );
  1210.         clonedParent = clonedGrandParent;
  1211.     }
  1212.     // should never occur
  1213.     return 0;
  1214. }
  1215. /**
  1216.  * Utility method for traversing a single node.
  1217.  * Does not properly handle a text node containing both the
  1218.  * start and end offsets.  Such nodes should
  1219.  * have been previously detected and been routed to traverseTextNode.
  1220.  *
  1221.  */
  1222. IDOM_Node*IDRangeImpl::traverseNode( IDOM_Node* n, bool isFullySelected, bool isLeft, int how )
  1223. {
  1224.     if ( isFullySelected )
  1225.         return traverseFullySelected( n, how );
  1226.     if ( n->getNodeType()== IDOM_Node::TEXT_NODE )
  1227.         return traverseTextNode( n, isLeft, how );
  1228.     return traversePartiallySelected( n, how );
  1229. }
  1230. /**
  1231.  * Utility method for traversing a single node when
  1232.  * we know a-priori that the node if fully
  1233.  * selected.
  1234.  *
  1235.  */
  1236. IDOM_Node*IDRangeImpl::traverseFullySelected( IDOM_Node* n, int how )
  1237. {
  1238.     switch( how )
  1239.     {
  1240.     case CLONE_CONTENTS:
  1241.         return n->cloneNode( true );
  1242.     case EXTRACT_CONTENTS:
  1243.         if ( n->getNodeType()== IDOM_Node::DOCUMENT_TYPE_NODE )
  1244.         {
  1245.             throw IDOM_DOMException(
  1246.                 IDOM_DOMException::HIERARCHY_REQUEST_ERR, 0);
  1247.         }
  1248.         return n;
  1249.     case DELETE_CONTENTS:
  1250.         n->getParentNode()->removeChild(n);
  1251.         return 0;
  1252.     }
  1253.     return 0;
  1254. }
  1255. /**
  1256.  * Utility method for traversing a single node when
  1257.  * we know a-priori that the node if partially
  1258.  * selected and is not a text node.
  1259.  *
  1260.  */
  1261. IDOM_Node*IDRangeImpl::traversePartiallySelected( IDOM_Node*n, int how )
  1262. {
  1263.     switch( how )
  1264.     {
  1265.     case DELETE_CONTENTS:
  1266.         return 0;
  1267.     case CLONE_CONTENTS:
  1268.     case EXTRACT_CONTENTS:
  1269.         return n->cloneNode( false );
  1270.     }
  1271.     return 0;
  1272. }
  1273. /**
  1274.  * Utility method for traversing a text node that we know
  1275.  * a-priori to be on a left or right boundary of the range.
  1276.  * This method does not properly handle text nodes that contain
  1277.  * both the start and end points of the range.
  1278.  *
  1279.  */
  1280. IDOM_Node*IDRangeImpl::traverseTextNode( IDOM_Node*n, bool isLeft, int how )
  1281. {
  1282.     const XMLCh* txtValue = n->getNodeValue();
  1283.     if ( isLeft )
  1284.     {
  1285.         int startLen = XMLString::stringLen(fStartContainer->getNodeValue());
  1286.         int offset = getStartOffset();
  1287.         if (offset == 0) {
  1288.             if ( how != CLONE_CONTENTS )
  1289.                 n->setNodeValue(XMLUni::fgZeroLenString);
  1290.         }
  1291.         else {
  1292.             XMLCh* oldNodeValue;
  1293.             XMLCh oldTemp[4000];
  1294.             if (offset >= 3999)  {
  1295.                 oldNodeValue = new XMLCh[offset+1];
  1296.             }
  1297.             else {
  1298.                 oldNodeValue = oldTemp;
  1299.             }
  1300.             XMLString::subString(oldNodeValue, txtValue, 0, offset);
  1301.             if ( how != CLONE_CONTENTS )
  1302.                 n->setNodeValue( ((IDDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
  1303.             if (offset>= 3999)
  1304.                 delete[] oldNodeValue;
  1305.         }
  1306.         if ( how==DELETE_CONTENTS )
  1307.             return 0;
  1308.         IDOM_Node* newNode = n->cloneNode( false );
  1309.         if (startLen == offset) {
  1310.             newNode->setNodeValue(XMLUni::fgZeroLenString);
  1311.         }
  1312.         else {
  1313.             XMLCh* newNodeValue;
  1314.             XMLCh newTemp[4000];
  1315.             if (offset >= 3999)  {
  1316.                 newNodeValue = new XMLCh[offset+1];
  1317.             }
  1318.             else {
  1319.                 newNodeValue = newTemp;
  1320.             }
  1321.             XMLString::subString(newNodeValue, txtValue, offset, startLen);
  1322.             newNode->setNodeValue( ((IDDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
  1323.             if (offset>= 3999)
  1324.                 delete[] newNodeValue;
  1325.         }
  1326.         return newNode;
  1327.     }
  1328.     else
  1329.     {
  1330.         int endLen = XMLString::stringLen(fEndContainer->getNodeValue());
  1331.         int offset = getEndOffset();
  1332.         if (endLen == offset) {
  1333.             if ( how != CLONE_CONTENTS )
  1334.                 n->setNodeValue(XMLUni::fgZeroLenString);
  1335.         }
  1336.         else {
  1337.             XMLCh* oldNodeValue;
  1338.             XMLCh oldTemp[4000];
  1339.             if (offset >= 3999)  {
  1340.                 oldNodeValue = new XMLCh[offset+1];
  1341.             }
  1342.             else {
  1343.                 oldNodeValue = oldTemp;
  1344.             }
  1345.             XMLString::subString(oldNodeValue, txtValue, offset, endLen);
  1346.             if ( how != CLONE_CONTENTS )
  1347.                 n->setNodeValue( ((IDDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
  1348.             if (offset>= 3999)
  1349.                 delete[] oldNodeValue;
  1350.         }
  1351.         if ( how==DELETE_CONTENTS )
  1352.             return 0;
  1353.         IDOM_Node* newNode = n->cloneNode( false );
  1354.         if (offset == 0) {
  1355.             newNode->setNodeValue(XMLUni::fgZeroLenString);
  1356.         }
  1357.         else {
  1358.             XMLCh* newNodeValue;
  1359.             XMLCh newTemp[4000];
  1360.             if (offset >= 3999)  {
  1361.                 newNodeValue = new XMLCh[offset+1];
  1362.             }
  1363.             else {
  1364.                 newNodeValue = newTemp;
  1365.             }
  1366.             XMLString::subString(newNodeValue, txtValue, 0, offset);
  1367.             newNode->setNodeValue( ((IDDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
  1368.             if (offset>= 3999)
  1369.                 delete[] newNodeValue;
  1370.         }
  1371.         return newNode;
  1372.     }
  1373. }
  1374. /**
  1375.  * Utility method to retrieve a child node by index.  This method
  1376.  * assumes the caller is trying to find out which node is
  1377.  * selected by the given index.  Note that if the index is
  1378.  * greater than the number of children, this implies that the
  1379.  * first node selected is the parent node itself.
  1380.  *
  1381.  */
  1382. IDOM_Node*IDRangeImpl::getSelectedNode( IDOM_Node*container, int offset )
  1383. {
  1384.     if ( container->getNodeType() == IDOM_Node::TEXT_NODE )
  1385.         return container;
  1386.     // This case is an important convenience for
  1387.     // traverseRightBoundary()
  1388.     if ( offset<0 )
  1389.         return container;
  1390.     IDOM_Node*child = container->getFirstChild();
  1391.     while( child!=0 && offset > 0 )
  1392.     {
  1393.         --offset;
  1394.         child = child->getNextSibling();
  1395.     }
  1396.     if ( child!=0 )
  1397.         return child;
  1398.     return container;
  1399. }
  1400. void IDRangeImpl::checkReadOnly(IDOM_Node* start, IDOM_Node* end,
  1401.                               unsigned int startOffset, unsigned int endOffset)
  1402. {
  1403.     if ((start == 0) || (end == 0) ) return;
  1404.     //if both start and end are text check and return
  1405.     if (start->getNodeType() == IDOM_Node::TEXT_NODE) {
  1406.         if (castToNodeImpl(start)->isReadOnly()) {
  1407.             throw IDOM_DOMException(
  1408.                 IDOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  1409.         }
  1410.         if (start == end)
  1411.             return;
  1412.     }
  1413.     //set the start and end nodes to check
  1414.     IDOM_Node*sNode = start->getFirstChild();
  1415.     for(unsigned int i = 0; i<startOffset; i++)
  1416.         sNode = sNode->getNextSibling();
  1417.     IDOM_Node* eNode;
  1418.     if (end->getNodeType() == IDOM_Node::TEXT_NODE) {
  1419.         eNode = end; //need to check only till this node
  1420.     }
  1421.     else { //need to check all the kids that fall before the end offset value
  1422.         eNode = end->getFirstChild();
  1423.         for (unsigned int i = 0; i<endOffset-1; i++)
  1424.             eNode = eNode->getNextSibling();
  1425.     }
  1426.     //recursivly search if any node is readonly
  1427.     recurseTreeAndCheck(sNode, eNode);
  1428. }
  1429. void IDRangeImpl::recurseTreeAndCheck(IDOM_Node* start, IDOM_Node* end)
  1430. {
  1431.     for(IDOM_Node* node=start; node != 0 && node !=end; node=node->getNextSibling())
  1432.     {
  1433.         if (castToNodeImpl(node)->isReadOnly()) {
  1434.             throw IDOM_DOMException(
  1435.                 IDOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  1436.         }
  1437.         if (node->hasChildNodes()) {
  1438.             node = node->getFirstChild();
  1439.             recurseTreeAndCheck(node, end);
  1440.         }
  1441.     }
  1442. }
  1443. IDOM_Node*IDRangeImpl::removeChild(IDOM_Node* parent, IDOM_Node* child)
  1444. {
  1445.     fRemoveChild = child; //only a precaution measure not to update this range data before removal
  1446.     IDOM_Node*n = parent->removeChild(child);
  1447.     fRemoveChild = 0;
  1448.     return n;
  1449. }
  1450. //
  1451. // Mutation functions
  1452. //
  1453. /* This function is called from DOM.
  1454. *  The  text has already beeen replaced.
  1455. *  Fix-up any offsets.
  1456. */
  1457. void IDRangeImpl::receiveReplacedText(IDOM_Node* node)
  1458. {
  1459.     if (node == 0) return;
  1460.     if (node == fStartContainer
  1461.         && fStartContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  1462.         fStartOffset = 0;
  1463.     }
  1464.     if (node == fEndContainer
  1465.         && fEndContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  1466.         fEndOffset = 0;
  1467.     }
  1468. }
  1469. /** This function is called from DOM.
  1470. *  The  text has already beeen inserted.
  1471. *  Fix-up any offsets.
  1472. */
  1473. void IDRangeImpl::updateRangeForDeletedText(IDOM_Node* node, unsigned int offset, int count)
  1474. {
  1475.     if (node == 0) return;
  1476.     if (node == fStartContainer
  1477.         && fStartContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  1478.         if (fStartOffset > offset+count) {
  1479.             fStartOffset = fStartOffset-count;
  1480.         } else if (fStartOffset > offset) {
  1481.             fStartOffset = offset;
  1482.         }
  1483.     }
  1484.     if (node == fEndContainer
  1485.         && fEndContainer->getNodeType() == IDOM_Node::TEXT_NODE) {
  1486.         if (fEndOffset > offset+count) {
  1487.             fEndOffset = fEndOffset-count;
  1488.         } else if (fEndOffset > offset) {
  1489.             fEndOffset = offset;
  1490.         }
  1491.     }
  1492. }
  1493. /** This function must be called by the DOM _BEFORE_
  1494. *  a node is deleted, because at that time it is
  1495. *  connected in the DOM tree, which we depend on.
  1496. */
  1497. void IDRangeImpl::updateRangeForDeletedNode(IDOM_Node* node)
  1498. {
  1499.     if (node == 0) return;
  1500.     if (fRemoveChild == node) return;
  1501.     if (node->getParentNode() == fStartContainer) {
  1502.         unsigned short index = indexOf(node, fStartContainer);
  1503.         if ( fStartOffset > index) {
  1504.             fStartOffset--;
  1505.         }
  1506.     }
  1507.     if (node->getParentNode() == fEndContainer) {
  1508.         unsigned short index = indexOf(node, fEndContainer);
  1509.         if ( fEndOffset > index) {
  1510.             fEndOffset--;
  1511.         }
  1512.     }
  1513.     if (node->getParentNode() != fStartContainer
  1514.         ||  node->getParentNode() != fEndContainer) {
  1515.         if (isAncestorOf(node, fStartContainer)) {
  1516.             IDOM_Node* tpNode = node->getParentNode();
  1517.             setStartContainer( tpNode );
  1518.             fStartOffset = indexOf( node, tpNode);
  1519.         }
  1520.         if (isAncestorOf(node, fEndContainer)) {
  1521.             IDOM_Node* tpNode = node->getParentNode();
  1522.             setEndContainer( tpNode );
  1523.             fEndOffset = indexOf( node, tpNode);
  1524.         }
  1525.     }
  1526. }
  1527. void IDRangeImpl::updateRangeForInsertedNode(IDOM_Node* node) {
  1528.     if (node == 0) return;
  1529.     if (node->getParentNode() == fStartContainer) {
  1530.         unsigned int index = indexOf(node, fStartContainer);
  1531.         if (index < fStartOffset) {
  1532.             fStartOffset++;
  1533.         }
  1534.     }
  1535.     if (node->getParentNode() == fEndContainer) {
  1536.         unsigned int index = indexOf(node, fEndContainer);
  1537.         if (index < fEndOffset) {
  1538.             fEndOffset++;
  1539.         }
  1540.     }
  1541. }
  1542. void IDRangeImpl::updateSplitInfo(IDOM_Text* oldNode, IDOM_Text* startNode, unsigned int offset)
  1543. {
  1544.     if (startNode == 0) return;
  1545.     if (fStartContainer == oldNode && fStartOffset > offset) {
  1546.           fStartOffset = fStartOffset - offset;
  1547.         fStartContainer = startNode;
  1548.     }
  1549.     if (fEndContainer == oldNode && fEndOffset > offset) {
  1550.             fEndContainer = startNode;
  1551.        fEndOffset = fEndOffset - offset;
  1552.     }
  1553. }