1 /*
   2  * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xml.internal.dtm.ref.sax2dtm;
  22 
  23 import com.sun.org.apache.xml.internal.dtm.DTM;
  24 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  25 import com.sun.org.apache.xml.internal.dtm.DTMException;
  26 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  27 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  28 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  29 import com.sun.org.apache.xml.internal.dtm.ref.ExpandedNameTable;
  30 import com.sun.org.apache.xml.internal.dtm.ref.ExtendedType;
  31 import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
  32 import com.sun.org.apache.xml.internal.utils.XMLString;
  33 import com.sun.org.apache.xml.internal.utils.XMLStringDefault;
  34 import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
  35 import com.sun.org.apache.xml.internal.res.XMLMessages;
  36 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  37 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  38 import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
  39 import java.util.ArrayList;
  40 import javax.xml.transform.Source;
  41 import org.xml.sax.Attributes;
  42 import org.xml.sax.ContentHandler;
  43 import org.xml.sax.SAXException;
  44 
  45 /**
  46  * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
  47  * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
  48  * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
  49  * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
  50  * are also overridden in SAX2DTM2 for performance reasons.
  51  * <p>
  52  * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
  53  * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
  54  * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
  55  * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
  56  * SuballocatedIntVectors.
  57  * <p>
  58  * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
  59  * SAX2DTM model, please extend from SAX2DTM instead of this class.
  60  * <p>
  61  * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
  62  * when making changes here!
  63  */
  64 public class SAX2DTM2 extends SAX2DTM
  65 {
  66 
  67   /****************************************************************
  68    *       Optimized version of the nested iterators
  69    ****************************************************************/
  70 
  71   /**
  72    * Iterator that returns all immediate children of a given node
  73    */
  74   public final class ChildrenIterator extends InternalAxisIteratorBase
  75   {
  76 
  77     /**
  78      * Setting start to END should 'close' the iterator,
  79      * i.e. subsequent call to next() should return END.
  80      * <p>
  81      * If the iterator is not restartable, this has no effect.
  82      * %REVIEW% Should it return/throw something in that case,
  83      * or set current node to END, to indicate request-not-honored?
  84      *
  85      * @param node Sets the root of the iteration.
  86      *
  87      * @return A DTMAxisIterator set to the start of the iteration.
  88      */
  89     public DTMAxisIterator setStartNode(int node)
  90     {
  91       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  92       if (node == DTMDefaultBase.ROOTNODE)
  93         node = getDocument();
  94       if (_isRestartable) {
  95         _startNode = node;
  96         _currentNode = (node == DTM.NULL) ? DTM.NULL
  97                                           : _firstch2(makeNodeIdentity(node));
  98 
  99         return resetPosition();
 100       }
 101 
 102       return this;
 103     }
 104 
 105     /**
 106      * Get the next node in the iteration.
 107      *
 108      * @return The next node handle in the iteration, or END if no more
 109      * are available.
 110      */
 111     public int next() {
 112       if (_currentNode != NULL) {
 113         int node = _currentNode;
 114         _currentNode = _nextsib2(node);
 115         return returnNode(makeNodeHandle(node));
 116       }
 117 
 118       return END;
 119     }
 120   }  // end of ChildrenIterator
 121 
 122   /**
 123    * Iterator that returns the parent of a given node. Note that
 124    * this delivers only a single node; if you want all the ancestors,
 125    * see AncestorIterator.
 126    */
 127   public final class ParentIterator extends InternalAxisIteratorBase
 128   {
 129 
 130     /** The extended type ID that was requested. */
 131     private int _nodeType = DTM.NULL;
 132 
 133     /**
 134      * Set start to END should 'close' the iterator,
 135      * i.e. subsequent call to next() should return END.
 136      *
 137      * @param node Sets the root of the iteration.
 138      *
 139      * @return A DTMAxisIterator set to the start of the iteration.
 140      */
 141     public DTMAxisIterator setStartNode(int node) {
 142       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 143       if (node == DTMDefaultBase.ROOTNODE)
 144         node = getDocument();
 145       if (_isRestartable) {
 146         _startNode = node;
 147 
 148         if (node != DTM.NULL)
 149           _currentNode = _parent2(makeNodeIdentity(node));
 150         else
 151           _currentNode = DTM.NULL;
 152 
 153         return resetPosition();
 154       }
 155 
 156       return this;
 157     }
 158 
 159     /**
 160      * Set the node type of the parent that we're looking for.
 161      * Note that this does _not_ mean "find the nearest ancestor of
 162      * this type", but "yield the parent if it is of this type".
 163      *
 164      *
 165      * @param type extended type ID.
 166      *
 167      * @return ParentIterator configured with the type filter set.
 168      */
 169     public DTMAxisIterator setNodeType(final int type)
 170     {
 171 
 172       _nodeType = type;
 173 
 174       return this;
 175     }
 176 
 177     /**
 178      * Get the next node in the iteration. In this case, we return
 179      * only the immediate parent, _if_ it matches the requested nodeType.
 180      *
 181      * @return The next node handle in the iteration, or END.
 182      */
 183     public int next()
 184     {
 185       int result = _currentNode;
 186       if (result == END)
 187         return DTM.NULL;
 188 
 189       // %OPT% The most common case is handled first.
 190       if (_nodeType == NULL) {
 191         _currentNode = END;
 192         return returnNode(makeNodeHandle(result));
 193       }
 194       else if (_nodeType >= DTM.NTYPES) {
 195         if (_nodeType == _exptype2(result)) {
 196           _currentNode = END;
 197           return returnNode(makeNodeHandle(result));
 198         }
 199       }
 200       else {
 201         if (_nodeType == _type2(result)) {
 202           _currentNode = END;
 203           return returnNode(makeNodeHandle(result));
 204         }
 205       }
 206 
 207       return DTM.NULL;
 208     }
 209   }  // end of ParentIterator
 210 
 211   /**
 212    * Iterator that returns children of a given type for a given node.
 213    * The functionality chould be achieved by putting a filter on top
 214    * of a basic child iterator, but a specialised iterator is used
 215    * for efficiency (both speed and size of translet).
 216    */
 217   public final class TypedChildrenIterator extends InternalAxisIteratorBase
 218   {
 219 
 220     /** The extended type ID that was requested. */
 221     private final int _nodeType;
 222 
 223     /**
 224      * Constructor TypedChildrenIterator
 225      *
 226      *
 227      * @param nodeType The extended type ID being requested.
 228      */
 229     public TypedChildrenIterator(int nodeType) {
 230       _nodeType = nodeType;
 231     }
 232 
 233     /**
 234      * Set start to END should 'close' the iterator,
 235      * i.e. subsequent call to next() should return END.
 236      *
 237      * @param node Sets the root of the iteration.
 238      *
 239      * @return A DTMAxisIterator set to the start of the iteration.
 240      */
 241     public DTMAxisIterator setStartNode(int node) {
 242       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 243       if (node == DTMDefaultBase.ROOTNODE)
 244         node = getDocument();
 245       if (_isRestartable) {
 246         _startNode = node;
 247         _currentNode = (node == DTM.NULL) ? DTM.NULL :
 248                          _firstch2(makeNodeIdentity(_startNode));
 249 
 250         return resetPosition();
 251       }
 252 
 253       return this;
 254     }
 255 
 256     /**
 257      * Get the next node in the iteration.
 258      *
 259      * @return The next node handle in the iteration, or END.
 260      */
 261     public int next() {
 262       int node = _currentNode;
 263       if (node == DTM.NULL)
 264         return DTM.NULL;
 265 
 266       final int nodeType = _nodeType;
 267 
 268       if (nodeType != DTM.ELEMENT_NODE) {
 269         while (node != DTM.NULL && _exptype2(node) != nodeType) {
 270           node = _nextsib2(node);
 271         }
 272       }
 273       // %OPT% If the nodeType is element (matching child::*), we only
 274       // need to compare the expType with DTM.NTYPES. A child node of
 275       // an element can be either an element, text, comment or
 276       // processing instruction node. Only element node has an extended
 277       // type greater than or equal to DTM.NTYPES.
 278       else {
 279         int eType;
 280         while (node != DTM.NULL) {
 281           eType = _exptype2(node);
 282           if (eType >= DTM.NTYPES)
 283             break;
 284           else
 285             node = _nextsib2(node);
 286         }
 287       }
 288 
 289       if (node == DTM.NULL) {
 290         _currentNode = DTM.NULL;
 291         return DTM.NULL;
 292       } else {
 293         _currentNode = _nextsib2(node);
 294         return returnNode(makeNodeHandle(node));
 295       }
 296     }
 297 
 298     /**
 299      * Return the node at the given position.
 300      */
 301     public int getNodeByPosition(int position) {
 302       if (position <= 0)
 303         return DTM.NULL;
 304 
 305       int node = _currentNode;
 306       int pos = 0;
 307 
 308       final int nodeType = _nodeType;
 309       if (nodeType != DTM.ELEMENT_NODE) {
 310         while (node != DTM.NULL) {
 311           if (_exptype2(node) == nodeType) {
 312             pos++;
 313             if (pos == position)
 314               return makeNodeHandle(node);
 315           }
 316 
 317           node = _nextsib2(node);
 318         }
 319         return NULL;
 320       } else {
 321         while (node != DTM.NULL) {
 322           if (_exptype2(node) >= DTM.NTYPES) {
 323             pos++;
 324             if (pos == position)
 325               return makeNodeHandle(node);
 326           }
 327           node = _nextsib2(node);
 328         }
 329         return NULL;
 330       }
 331     }
 332 
 333   }  // end of TypedChildrenIterator
 334 
 335   /**
 336    * Iterator that returns the namespace nodes as defined by the XPath data model
 337    * for a given node, filtered by extended type ID.
 338    */
 339   public class TypedRootIterator extends RootIterator
 340   {
 341 
 342     /** The extended type ID that was requested. */
 343     private final int _nodeType;
 344 
 345     /**
 346      * Constructor TypedRootIterator
 347      *
 348      * @param nodeType The extended type ID being requested.
 349      */
 350     public TypedRootIterator(int nodeType)
 351     {
 352       super();
 353       _nodeType = nodeType;
 354     }
 355 
 356     /**
 357      * Get the next node in the iteration.
 358      *
 359      * @return The next node handle in the iteration, or END.
 360      */
 361     public int next()
 362     {
 363       if(_startNode == _currentNode)
 364         return NULL;
 365 
 366       final int node = _startNode;
 367       int expType = _exptype2(makeNodeIdentity(node));
 368 
 369       _currentNode = node;
 370 
 371       if (_nodeType >= DTM.NTYPES) {
 372         if (_nodeType == expType) {
 373           return returnNode(node);
 374         }
 375       }
 376       else {
 377         if (expType < DTM.NTYPES) {
 378           if (expType == _nodeType) {
 379             return returnNode(node);
 380           }
 381         }
 382         else {
 383           if (m_extendedTypes[expType].getNodeType() == _nodeType) {
 384             return returnNode(node);
 385           }
 386         }
 387       }
 388 
 389       return NULL;
 390     }
 391   }  // end of TypedRootIterator
 392 
 393   /**
 394    * Iterator that returns all siblings of a given node.
 395    */
 396   public class FollowingSiblingIterator extends InternalAxisIteratorBase
 397   {
 398 
 399     /**
 400      * Set start to END should 'close' the iterator,
 401      * i.e. subsequent call to next() should return END.
 402      *
 403      * @param node Sets the root of the iteration.
 404      *
 405      * @return A DTMAxisIterator set to the start of the iteration.
 406      */
 407     public DTMAxisIterator setStartNode(int node) {
 408       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 409       if (node == DTMDefaultBase.ROOTNODE)
 410         node = getDocument();
 411       if (_isRestartable) {
 412         _startNode = node;
 413         _currentNode = makeNodeIdentity(node);
 414 
 415         return resetPosition();
 416       }
 417 
 418       return this;
 419     }
 420 
 421     /**
 422      * Get the next node in the iteration.
 423      *
 424      * @return The next node handle in the iteration, or END.
 425      */
 426     public int next() {
 427       _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
 428                                                 : _nextsib2(_currentNode);
 429       return returnNode(makeNodeHandle(_currentNode));
 430     }
 431   }  // end of FollowingSiblingIterator
 432 
 433   /**
 434    * Iterator that returns all following siblings of a given node.
 435    */
 436   public final class TypedFollowingSiblingIterator
 437           extends FollowingSiblingIterator
 438   {
 439 
 440     /** The extended type ID that was requested. */
 441     private final int _nodeType;
 442 
 443     /**
 444      * Constructor TypedFollowingSiblingIterator
 445      *
 446      *
 447      * @param type The extended type ID being requested.
 448      */
 449     public TypedFollowingSiblingIterator(int type) {
 450       _nodeType = type;
 451     }
 452 
 453     /**
 454      * Get the next node in the iteration.
 455      *
 456      * @return The next node handle in the iteration, or END.
 457      */
 458     public int next() {
 459       if (_currentNode == DTM.NULL) {
 460         return DTM.NULL;
 461       }
 462 
 463       int node = _currentNode;
 464       final int nodeType = _nodeType;
 465 
 466       if (nodeType != DTM.ELEMENT_NODE) {
 467         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
 468       } else {
 469         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
 470       }
 471 
 472       _currentNode = node;
 473 
 474       return (node == DTM.NULL)
 475                       ? DTM.NULL
 476                       : returnNode(makeNodeHandle(node));
 477     }
 478 
 479   }  // end of TypedFollowingSiblingIterator
 480 
 481   /**
 482    * Iterator that returns attribute nodes (of what nodes?)
 483    */
 484   public final class AttributeIterator extends InternalAxisIteratorBase {
 485 
 486     // assumes caller will pass element nodes
 487 
 488     /**
 489      * Set start to END should 'close' the iterator,
 490      * i.e. subsequent call to next() should return END.
 491      *
 492      * @param node Sets the root of the iteration.
 493      *
 494      * @return A DTMAxisIterator set to the start of the iteration.
 495      */
 496     public DTMAxisIterator setStartNode(int node) {
 497       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 498       if (node == DTMDefaultBase.ROOTNODE)
 499         node = getDocument();
 500       if (_isRestartable) {
 501         _startNode = node;
 502         _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
 503 
 504         return resetPosition();
 505       }
 506 
 507       return this;
 508     }
 509 
 510     /**
 511      * Get the next node in the iteration.
 512      *
 513      * @return The next node handle in the iteration, or END.
 514      */
 515     public int next() {
 516       final int node = _currentNode;
 517 
 518       if (node != NULL) {
 519         _currentNode = getNextAttributeIdentity(node);
 520         return returnNode(makeNodeHandle(node));
 521       }
 522 
 523       return NULL;
 524     }
 525   }  // end of AttributeIterator
 526 
 527   /**
 528    * Iterator that returns attribute nodes of a given type
 529    */
 530   public final class TypedAttributeIterator extends InternalAxisIteratorBase
 531   {
 532 
 533     /** The extended type ID that was requested. */
 534     private final int _nodeType;
 535 
 536     /**
 537      * Constructor TypedAttributeIterator
 538      *
 539      *
 540      * @param nodeType The extended type ID that is requested.
 541      */
 542     public TypedAttributeIterator(int nodeType) {
 543       _nodeType = nodeType;
 544     }
 545 
 546     // assumes caller will pass element nodes
 547 
 548     /**
 549      * Set start to END should 'close' the iterator,
 550      * i.e. subsequent call to next() should return END.
 551      *
 552      * @param node Sets the root of the iteration.
 553      *
 554      * @return A DTMAxisIterator set to the start of the iteration.
 555      */
 556     public DTMAxisIterator setStartNode(int node) {
 557       if (_isRestartable) {
 558         _startNode = node;
 559         _currentNode = getTypedAttribute(node, _nodeType);
 560         return resetPosition();
 561       }
 562 
 563       return this;
 564     }
 565 
 566     /**
 567      * Get the next node in the iteration.
 568      *
 569      * @return The next node handle in the iteration, or END.
 570      */
 571     public int next() {
 572       final int node = _currentNode;
 573 
 574       // singleton iterator, since there can only be one attribute of
 575       // a given type.
 576       _currentNode = NULL;
 577 
 578       return returnNode(node);
 579     }
 580   }  // end of TypedAttributeIterator
 581 
 582   /**
 583    * Iterator that returns preceding siblings of a given node
 584    */
 585   public class PrecedingSiblingIterator extends InternalAxisIteratorBase
 586   {
 587 
 588     /**
 589      * The node identity of _startNode for this iterator
 590      */
 591     protected int _startNodeID;
 592 
 593     /**
 594      * True if this iterator has a reversed axis.
 595      *
 596      * @return true.
 597      */
 598     public boolean isReverse() {
 599       return true;
 600     }
 601 
 602     /**
 603      * Set start to END should 'close' the iterator,
 604      * i.e. subsequent call to next() should return END.
 605      *
 606      * @param node Sets the root of the iteration.
 607      *
 608      * @return A DTMAxisIterator set to the start of the iteration.
 609      */
 610     public DTMAxisIterator setStartNode(int node) {
 611       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 612       if (node == DTMDefaultBase.ROOTNODE)
 613         node = getDocument();
 614       if (_isRestartable) {
 615         _startNode = node;
 616         node = _startNodeID = makeNodeIdentity(node);
 617 
 618         if(node == NULL) {
 619           _currentNode = node;
 620           return resetPosition();
 621         }
 622 
 623         int type = _type2(node);
 624         if (ExpandedNameTable.ATTRIBUTE == type ||
 625             ExpandedNameTable.NAMESPACE == type)
 626         {
 627           _currentNode = node;
 628         } else {
 629           // Be careful to handle the Document node properly
 630           _currentNode = _parent2(node);
 631           if(NULL!=_currentNode)
 632             _currentNode = _firstch2(_currentNode);
 633           else
 634             _currentNode = node;
 635         }
 636 
 637         return resetPosition();
 638       }
 639 
 640       return this;
 641     }
 642 
 643     /**
 644      * Get the next node in the iteration.
 645      *
 646      * @return The next node handle in the iteration, or END.
 647      */
 648     public int next() {
 649       if (_currentNode == _startNodeID || _currentNode == DTM.NULL) {
 650         return NULL;
 651       } else {
 652         final int node = _currentNode;
 653         _currentNode = _nextsib2(node);
 654         return returnNode(makeNodeHandle(node));
 655       }
 656     }
 657   }  // end of PrecedingSiblingIterator
 658 
 659   /**
 660    * Iterator that returns preceding siblings of a given type for
 661    * a given node
 662    */
 663   public final class TypedPrecedingSiblingIterator
 664           extends PrecedingSiblingIterator
 665   {
 666 
 667     /** The extended type ID that was requested. */
 668     private final int _nodeType;
 669 
 670     /**
 671      * Constructor TypedPrecedingSiblingIterator
 672      *
 673      *
 674      * @param type The extended type ID being requested.
 675      */
 676     public TypedPrecedingSiblingIterator(int type) {
 677       _nodeType = type;
 678     }
 679 
 680     /**
 681      * Get the next node in the iteration.
 682      *
 683      * @return The next node handle in the iteration, or END.
 684      */
 685     public int next() {
 686       int node = _currentNode;
 687 
 688       final int nodeType = _nodeType;
 689       final int startNodeID = _startNodeID;
 690 
 691       if (nodeType != DTM.ELEMENT_NODE) {
 692         while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
 693           node = _nextsib2(node);
 694         }
 695       } else {
 696         while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
 697           node = _nextsib2(node);
 698         }
 699       }
 700 
 701       if (node == DTM.NULL || node == startNodeID) {
 702         _currentNode = NULL;
 703         return NULL;
 704       } else {
 705         _currentNode = _nextsib2(node);
 706         return returnNode(makeNodeHandle(node));
 707       }
 708     }
 709 
 710     /**
 711      * Return the index of the last node in this iterator.
 712      */
 713     public int getLast() {
 714       if (_last != -1)
 715         return _last;
 716 
 717       setMark();
 718 
 719       int node = _currentNode;
 720       final int nodeType = _nodeType;
 721       final int startNodeID = _startNodeID;
 722 
 723       int last = 0;
 724       if (nodeType != DTM.ELEMENT_NODE) {
 725         while (node != NULL && node != startNodeID) {
 726           if (_exptype2(node) == nodeType) {
 727             last++;
 728           }
 729           node = _nextsib2(node);
 730         }
 731       } else {
 732         while (node != NULL && node != startNodeID) {
 733           if (_exptype2(node) >= DTM.NTYPES) {
 734             last++;
 735           }
 736           node = _nextsib2(node);
 737         }
 738       }
 739 
 740       gotoMark();
 741 
 742       return (_last = last);
 743     }
 744   }  // end of TypedPrecedingSiblingIterator
 745 
 746   /**
 747    * Iterator that returns preceding nodes of a given node.
 748    * This includes the node set {root+1, start-1}, but excludes
 749    * all ancestors, attributes, and namespace nodes.
 750    */
 751   public class PrecedingIterator extends InternalAxisIteratorBase
 752   {
 753 
 754     /** The max ancestors, but it can grow... */
 755     private final int _maxAncestors = 8;
 756 
 757     /**
 758      * The stack of start node + ancestors up to the root of the tree,
 759      *  which we must avoid.
 760      */
 761     protected int[] _stack = new int[_maxAncestors];
 762 
 763     /** (not sure yet... -sb) */
 764     protected int _sp, _oldsp;
 765 
 766     protected int _markedsp, _markedNode, _markedDescendant;
 767 
 768     /* _currentNode precedes candidates.  This is the identity, not the handle! */
 769 
 770     /**
 771      * True if this iterator has a reversed axis.
 772      *
 773      * @return true since this iterator is a reversed axis.
 774      */
 775     public boolean isReverse()
 776     {
 777       return true;
 778     }
 779 
 780     /**
 781      * Returns a deep copy of this iterator.   The cloned iterator is not reset.
 782      *
 783      * @return a deep copy of this iterator.
 784      */
 785     public DTMAxisIterator cloneIterator()
 786     {
 787       _isRestartable = false;
 788 
 789       try
 790       {
 791         final PrecedingIterator clone = (PrecedingIterator) super.clone();
 792         final int[] stackCopy = new int[_stack.length];
 793         System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
 794 
 795         clone._stack = stackCopy;
 796 
 797         // return clone.reset();
 798         return clone;
 799       }
 800       catch (CloneNotSupportedException e)
 801       {
 802         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
 803       }
 804     }
 805 
 806     /**
 807      * Set start to END should 'close' the iterator,
 808      * i.e. subsequent call to next() should return END.
 809      *
 810      * @param node Sets the root of the iteration.
 811      *
 812      * @return A DTMAxisIterator set to the start of the iteration.
 813      */
 814     public DTMAxisIterator setStartNode(int node)
 815     {
 816       //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
 817       if (node == DTMDefaultBase.ROOTNODE)
 818         node = getDocument();
 819       if (_isRestartable)
 820       {
 821         node = makeNodeIdentity(node);
 822 
 823         // iterator is not a clone
 824         int parent, index;
 825 
 826        if (_type2(node) == DTM.ATTRIBUTE_NODE)
 827          node = _parent2(node);
 828 
 829         _startNode = node;
 830         _stack[index = 0] = node;
 831 
 832         parent=node;
 833         while ((parent = _parent2(parent)) != NULL)
 834         {
 835           if (++index == _stack.length)
 836           {
 837             final int[] stack = new int[index*2];
 838             System.arraycopy(_stack, 0, stack, 0, index);
 839             _stack = stack;
 840           }
 841           _stack[index] = parent;
 842         }
 843 
 844         if(index>0)
 845           --index; // Pop actual root node (if not start) back off the stack
 846 
 847         _currentNode=_stack[index]; // Last parent before root node
 848 
 849         _oldsp = _sp = index;
 850 
 851         return resetPosition();
 852       }
 853 
 854       return this;
 855     }
 856 
 857     /**
 858      * Get the next node in the iteration.
 859      *
 860      * @return The next node handle in the iteration, or END.
 861      */
 862     public int next()
 863     {
 864         // Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
 865         // Also recoded the loop controls for clarity and to flatten out
 866         // the tail-recursion.
 867         for(++_currentNode; _sp>=0; ++_currentNode)
 868         {
 869           if(_currentNode < _stack[_sp])
 870           {
 871             int type = _type2(_currentNode);
 872             if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
 873               return returnNode(makeNodeHandle(_currentNode));
 874           }
 875           else
 876             --_sp;
 877         }
 878         return NULL;
 879     }
 880 
 881     // redefine DTMAxisIteratorBase's reset
 882 
 883     /**
 884      * Resets the iterator to the last start node.
 885      *
 886      * @return A DTMAxisIterator, which may or may not be the same as this
 887      *         iterator.
 888      */
 889     public DTMAxisIterator reset()
 890     {
 891 
 892       _sp = _oldsp;
 893 
 894       return resetPosition();
 895     }
 896 
 897     public void setMark() {
 898         _markedsp = _sp;
 899         _markedNode = _currentNode;
 900         _markedDescendant = _stack[0];
 901     }
 902 
 903     public void gotoMark() {
 904         _sp = _markedsp;
 905         _currentNode = _markedNode;
 906     }
 907   }  // end of PrecedingIterator
 908 
 909   /**
 910    * Iterator that returns preceding nodes of agiven type for a
 911    * given node. This includes the node set {root+1, start-1}, but
 912    * excludes all ancestors.
 913    */
 914   public final class TypedPrecedingIterator extends PrecedingIterator
 915   {
 916 
 917     /** The extended type ID that was requested. */
 918     private final int _nodeType;
 919 
 920     /**
 921      * Constructor TypedPrecedingIterator
 922      *
 923      *
 924      * @param type The extended type ID being requested.
 925      */
 926     public TypedPrecedingIterator(int type)
 927     {
 928       _nodeType = type;
 929     }
 930 
 931     /**
 932      * Get the next node in the iteration.
 933      *
 934      * @return The next node handle in the iteration, or END.
 935      */
 936     public int next()
 937     {
 938       int node = _currentNode;
 939       final int nodeType = _nodeType;
 940 
 941       if (nodeType >= DTM.NTYPES) {
 942         while (true) {
 943           node++;
 944 
 945           if (_sp < 0) {
 946             node = NULL;
 947             break;
 948           }
 949           else if (node >= _stack[_sp]) {
 950             if (--_sp < 0) {
 951               node = NULL;
 952               break;
 953             }
 954           }
 955           else if (_exptype2(node) == nodeType) {
 956             break;
 957           }
 958         }
 959       }
 960       else {
 961         int expType;
 962 
 963         while (true) {
 964           node++;
 965 
 966           if (_sp < 0) {
 967             node = NULL;
 968             break;
 969           }
 970           else if (node >= _stack[_sp]) {
 971             if (--_sp < 0) {
 972               node = NULL;
 973               break;
 974             }
 975           }
 976           else {
 977             expType = _exptype2(node);
 978             if (expType < DTM.NTYPES) {
 979               if (expType == nodeType) {
 980                 break;
 981               }
 982             }
 983             else {
 984               if (m_extendedTypes[expType].getNodeType() == nodeType) {
 985                 break;
 986               }
 987             }
 988           }
 989         }
 990       }
 991 
 992       _currentNode = node;
 993 
 994       return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
 995     }
 996   }  // end of TypedPrecedingIterator
 997 
 998   /**
 999    * Iterator that returns following nodes of for a given node.
1000    */
1001   public class FollowingIterator extends InternalAxisIteratorBase
1002   {
1003     //DTMAxisTraverser m_traverser; // easier for now
1004 
1005     public FollowingIterator()
1006     {
1007       //m_traverser = getAxisTraverser(Axis.FOLLOWING);
1008     }
1009 
1010     /**
1011      * Set start to END should 'close' the iterator,
1012      * i.e. subsequent call to next() should return END.
1013      *
1014      * @param node Sets the root of the iteration.
1015      *
1016      * @return A DTMAxisIterator set to the start of the iteration.
1017      */
1018     public DTMAxisIterator setStartNode(int node)
1019     {
1020 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1021       if (node == DTMDefaultBase.ROOTNODE)
1022         node = getDocument();
1023       if (_isRestartable)
1024       {
1025         _startNode = node;
1026 
1027         //_currentNode = m_traverser.first(node);
1028 
1029         node = makeNodeIdentity(node);
1030 
1031         int first;
1032         int type = _type2(node);
1033 
1034         if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
1035         {
1036           node = _parent2(node);
1037           first = _firstch2(node);
1038 
1039           if (NULL != first) {
1040             _currentNode = makeNodeHandle(first);
1041             return resetPosition();
1042           }
1043         }
1044 
1045         do
1046         {
1047           first = _nextsib2(node);
1048 
1049           if (NULL == first)
1050             node = _parent2(node);
1051         }
1052         while (NULL == first && NULL != node);
1053 
1054         _currentNode = makeNodeHandle(first);
1055 
1056         // _currentNode precedes possible following(node) nodes
1057         return resetPosition();
1058       }
1059 
1060       return this;
1061     }
1062 
1063     /**
1064      * Get the next node in the iteration.
1065      *
1066      * @return The next node handle in the iteration, or END.
1067      */
1068     public int next()
1069     {
1070 
1071       int node = _currentNode;
1072 
1073       //_currentNode = m_traverser.next(_startNode, _currentNode);
1074       int current = makeNodeIdentity(node);
1075 
1076       while (true)
1077       {
1078         current++;
1079 
1080         int type = _type2(current);
1081         if (NULL == type) {
1082           _currentNode = NULL;
1083           return returnNode(node);
1084         }
1085 
1086         if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
1087           continue;
1088 
1089         _currentNode = makeNodeHandle(current);
1090         return returnNode(node);
1091       }
1092     }
1093 
1094   }  // end of FollowingIterator
1095 
1096   /**
1097    * Iterator that returns following nodes of a given type for a given node.
1098    */
1099   public final class TypedFollowingIterator extends FollowingIterator
1100   {
1101 
1102     /** The extended type ID that was requested. */
1103     private final int _nodeType;
1104 
1105     /**
1106      * Constructor TypedFollowingIterator
1107      *
1108      *
1109      * @param type The extended type ID being requested.
1110      */
1111     public TypedFollowingIterator(int type)
1112     {
1113       _nodeType = type;
1114     }
1115 
1116     /**
1117      * Get the next node in the iteration.
1118      *
1119      * @return The next node handle in the iteration, or END.
1120      */
1121     public int next()
1122     {
1123       int current;
1124       int node;
1125       int type;
1126 
1127       final int nodeType = _nodeType;
1128       int currentNodeID = makeNodeIdentity(_currentNode);
1129 
1130       if (nodeType >= DTM.NTYPES) {
1131         do {
1132           node = currentNodeID;
1133           current = node;
1134 
1135           do {
1136             current++;
1137             type = _type2(current);
1138           }
1139           while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1140 
1141           currentNodeID = (type != NULL) ? current : NULL;
1142         }
1143         while (node != DTM.NULL && _exptype2(node) != nodeType);
1144       }
1145       else {
1146         do {
1147           node = currentNodeID;
1148           current = node;
1149 
1150           do {
1151             current++;
1152             type = _type2(current);
1153           }
1154           while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1155 
1156           currentNodeID = (type != NULL) ? current : NULL;
1157         }
1158         while (node != DTM.NULL
1159                && (_exptype2(node) != nodeType && _type2(node) != nodeType));
1160       }
1161 
1162       _currentNode = makeNodeHandle(currentNodeID);
1163       return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
1164     }
1165   }  // end of TypedFollowingIterator
1166 
1167   /**
1168    * Iterator that returns the ancestors of a given node in document
1169    * order.  (NOTE!  This was changed from the XSLTC code!)
1170    */
1171   public class AncestorIterator extends InternalAxisIteratorBase
1172   {
1173     // The initial size of the ancestor array
1174     private static final int m_blocksize = 32;
1175 
1176     // The array for ancestor nodes. This array will grow dynamically.
1177     int[] m_ancestors = new int[m_blocksize];
1178 
1179     // Number of ancestor nodes in the array
1180     int m_size = 0;
1181 
1182     int m_ancestorsPos;
1183 
1184     int m_markedPos;
1185 
1186     /** The real start node for this axes, since _startNode will be adjusted. */
1187     int m_realStartNode;
1188 
1189     /**
1190      * Get start to END should 'close' the iterator,
1191      * i.e. subsequent call to next() should return END.
1192      *
1193      * @return The root node of the iteration.
1194      */
1195     public int getStartNode()
1196     {
1197       return m_realStartNode;
1198     }
1199 
1200     /**
1201      * True if this iterator has a reversed axis.
1202      *
1203      * @return true since this iterator is a reversed axis.
1204      */
1205     public final boolean isReverse()
1206     {
1207       return true;
1208     }
1209 
1210     /**
1211      * Returns a deep copy of this iterator.  The cloned iterator is not reset.
1212      *
1213      * @return a deep copy of this iterator.
1214      */
1215     public DTMAxisIterator cloneIterator()
1216     {
1217       _isRestartable = false;  // must set to false for any clone
1218 
1219       try
1220       {
1221         final AncestorIterator clone = (AncestorIterator) super.clone();
1222 
1223         clone._startNode = _startNode;
1224 
1225         // return clone.reset();
1226         return clone;
1227       }
1228       catch (CloneNotSupportedException e)
1229       {
1230         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
1231       }
1232     }
1233 
1234     /**
1235      * Set start to END should 'close' the iterator,
1236      * i.e. subsequent call to next() should return END.
1237      *
1238      * @param node Sets the root of the iteration.
1239      *
1240      * @return A DTMAxisIterator set to the start of the iteration.
1241      */
1242     public DTMAxisIterator setStartNode(int node)
1243     {
1244 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1245       if (node == DTMDefaultBase.ROOTNODE)
1246         node = getDocument();
1247       m_realStartNode = node;
1248 
1249       if (_isRestartable)
1250       {
1251         int nodeID = makeNodeIdentity(node);
1252         m_size = 0;
1253 
1254         if (nodeID == DTM.NULL) {
1255           _currentNode = DTM.NULL;
1256           m_ancestorsPos = 0;
1257           return this;
1258         }
1259 
1260         // Start from the current node's parent if
1261         // _includeSelf is false.
1262         if (!_includeSelf) {
1263           nodeID = _parent2(nodeID);
1264           node = makeNodeHandle(nodeID);
1265         }
1266 
1267         _startNode = node;
1268 
1269         while (nodeID != END) {
1270           //m_ancestors.addElement(node);
1271           if (m_size >= m_ancestors.length)
1272           {
1273             int[] newAncestors = new int[m_size * 2];
1274             System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1275             m_ancestors = newAncestors;
1276           }
1277 
1278           m_ancestors[m_size++] = node;
1279           nodeID = _parent2(nodeID);
1280           node = makeNodeHandle(nodeID);
1281         }
1282 
1283         m_ancestorsPos = m_size - 1;
1284 
1285         _currentNode = (m_ancestorsPos>=0)
1286                                ? m_ancestors[m_ancestorsPos]
1287                                : DTM.NULL;
1288 
1289         return resetPosition();
1290       }
1291 
1292       return this;
1293     }
1294 
1295     /**
1296      * Resets the iterator to the last start node.
1297      *
1298      * @return A DTMAxisIterator, which may or may not be the same as this
1299      *         iterator.
1300      */
1301     public DTMAxisIterator reset()
1302     {
1303 
1304       m_ancestorsPos = m_size - 1;
1305 
1306       _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
1307                                          : DTM.NULL;
1308 
1309       return resetPosition();
1310     }
1311 
1312     /**
1313      * Get the next node in the iteration.
1314      *
1315      * @return The next node handle in the iteration, or END.
1316      */
1317     public int next()
1318     {
1319 
1320       int next = _currentNode;
1321 
1322       int pos = --m_ancestorsPos;
1323 
1324       _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
1325                                 : DTM.NULL;
1326 
1327       return returnNode(next);
1328     }
1329 
1330     public void setMark() {
1331         m_markedPos = m_ancestorsPos;
1332     }
1333 
1334     public void gotoMark() {
1335         m_ancestorsPos = m_markedPos;
1336         _currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
1337                                          : DTM.NULL;
1338     }
1339   }  // end of AncestorIterator
1340 
1341   /**
1342    * Typed iterator that returns the ancestors of a given node.
1343    */
1344   public final class TypedAncestorIterator extends AncestorIterator
1345   {
1346 
1347     /** The extended type ID that was requested. */
1348     private final int _nodeType;
1349 
1350     /**
1351      * Constructor TypedAncestorIterator
1352      *
1353      *
1354      * @param type The extended type ID being requested.
1355      */
1356     public TypedAncestorIterator(int type)
1357     {
1358       _nodeType = type;
1359     }
1360 
1361     /**
1362      * Set start to END should 'close' the iterator,
1363      * i.e. subsequent call to next() should return END.
1364      *
1365      * @param node Sets the root of the iteration.
1366      *
1367      * @return A DTMAxisIterator set to the start of the iteration.
1368      */
1369     public DTMAxisIterator setStartNode(int node)
1370     {
1371 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1372       if (node == DTMDefaultBase.ROOTNODE)
1373         node = getDocument();
1374       m_realStartNode = node;
1375 
1376       if (_isRestartable)
1377       {
1378         int nodeID = makeNodeIdentity(node);
1379         m_size = 0;
1380 
1381         if (nodeID == DTM.NULL) {
1382           _currentNode = DTM.NULL;
1383           m_ancestorsPos = 0;
1384           return this;
1385         }
1386 
1387         final int nodeType = _nodeType;
1388 
1389         if (!_includeSelf) {
1390           nodeID = _parent2(nodeID);
1391           node = makeNodeHandle(nodeID);
1392         }
1393 
1394         _startNode = node;
1395 
1396         if (nodeType >= DTM.NTYPES) {
1397           while (nodeID != END) {
1398             int eType = _exptype2(nodeID);
1399 
1400             if (eType == nodeType) {
1401               if (m_size >= m_ancestors.length)
1402               {
1403                 int[] newAncestors = new int[m_size * 2];
1404                 System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1405                 m_ancestors = newAncestors;
1406               }
1407               m_ancestors[m_size++] = makeNodeHandle(nodeID);
1408             }
1409             nodeID = _parent2(nodeID);
1410           }
1411         }
1412         else {
1413           while (nodeID != END) {
1414             int eType = _exptype2(nodeID);
1415 
1416             if ((eType < DTM.NTYPES && eType == nodeType)
1417                 || (eType >= DTM.NTYPES
1418                     && m_extendedTypes[eType].getNodeType() == nodeType)) {
1419               if (m_size >= m_ancestors.length)
1420               {
1421                 int[] newAncestors = new int[m_size * 2];
1422                 System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1423                 m_ancestors = newAncestors;
1424               }
1425               m_ancestors[m_size++] = makeNodeHandle(nodeID);
1426             }
1427             nodeID = _parent2(nodeID);
1428           }
1429         }
1430         m_ancestorsPos = m_size - 1;
1431 
1432         _currentNode = (m_ancestorsPos>=0)
1433                                ? m_ancestors[m_ancestorsPos]
1434                                : DTM.NULL;
1435 
1436         return resetPosition();
1437       }
1438 
1439       return this;
1440     }
1441 
1442     /**
1443      * Return the node at the given position.
1444      */
1445     public int getNodeByPosition(int position)
1446     {
1447       if (position > 0 && position <= m_size) {
1448         return m_ancestors[position-1];
1449       }
1450       else
1451         return DTM.NULL;
1452     }
1453 
1454     /**
1455      * Returns the position of the last node within the iteration, as
1456      * defined by XPath.
1457      */
1458     public int getLast() {
1459       return m_size;
1460     }
1461   }  // end of TypedAncestorIterator
1462 
1463   /**
1464    * Iterator that returns the descendants of a given node.
1465    */
1466   public class DescendantIterator extends InternalAxisIteratorBase
1467   {
1468 
1469     /**
1470      * Set start to END should 'close' the iterator,
1471      * i.e. subsequent call to next() should return END.
1472      *
1473      * @param node Sets the root of the iteration.
1474      *
1475      * @return A DTMAxisIterator set to the start of the iteration.
1476      */
1477     public DTMAxisIterator setStartNode(int node)
1478     {
1479 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1480       if (node == DTMDefaultBase.ROOTNODE)
1481         node = getDocument();
1482       if (_isRestartable)
1483       {
1484         node = makeNodeIdentity(node);
1485         _startNode = node;
1486 
1487         if (_includeSelf)
1488           node--;
1489 
1490         _currentNode = node;
1491 
1492         return resetPosition();
1493       }
1494 
1495       return this;
1496     }
1497 
1498     /**
1499      * Tell if this node identity is a descendant.  Assumes that
1500      * the node info for the element has already been obtained.
1501      *
1502      * This one-sided test works only if the parent has been
1503      * previously tested and is known to be a descendent. It fails if
1504      * the parent is the _startNode's next sibling, or indeed any node
1505      * that follows _startNode in document order.  That may suffice
1506      * for this iterator, but it's not really an isDescendent() test.
1507      * %REVIEW% rename?
1508      *
1509      * @param identity The index number of the node in question.
1510      * @return true if the index is a descendant of _startNode.
1511      */
1512     protected final boolean isDescendant(int identity)
1513     {
1514       return (_parent2(identity) >= _startNode) || (_startNode == identity);
1515     }
1516 
1517     /**
1518      * Get the next node in the iteration.
1519      *
1520      * @return The next node handle in the iteration, or END.
1521      */
1522     public int next()
1523     {
1524       final int startNode = _startNode;
1525       if (startNode == NULL) {
1526         return NULL;
1527       }
1528 
1529       if (_includeSelf && (_currentNode + 1) == startNode)
1530           return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
1531 
1532       int node = _currentNode;
1533       int type;
1534 
1535       // %OPT% If the startNode is the root node, do not need
1536       // to do the isDescendant() check.
1537       if (startNode == ROOTNODE) {
1538         int eType;
1539         do {
1540           node++;
1541           eType = _exptype2(node);
1542 
1543           if (NULL == eType) {
1544             _currentNode = NULL;
1545             return END;
1546           }
1547         } while (eType == TEXT_NODE
1548                  || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
1549                  || type == NAMESPACE_NODE);
1550       }
1551       else {
1552         do {
1553           node++;
1554           type = _type2(node);
1555 
1556           if (NULL == type ||!isDescendant(node)) {
1557             _currentNode = NULL;
1558             return END;
1559           }
1560         } while(ATTRIBUTE_NODE == type || TEXT_NODE == type
1561                  || NAMESPACE_NODE == type);
1562       }
1563 
1564       _currentNode = node;
1565       return returnNode(makeNodeHandle(node));  // make handle.
1566     }
1567 
1568     /**
1569      * Reset.
1570      *
1571      */
1572   public DTMAxisIterator reset()
1573   {
1574 
1575     final boolean temp = _isRestartable;
1576 
1577     _isRestartable = true;
1578 
1579     setStartNode(makeNodeHandle(_startNode));
1580 
1581     _isRestartable = temp;
1582 
1583     return this;
1584   }
1585 
1586   }  // end of DescendantIterator
1587 
1588   /**
1589    * Typed iterator that returns the descendants of a given node.
1590    */
1591   public final class TypedDescendantIterator extends DescendantIterator
1592   {
1593 
1594     /** The extended type ID that was requested. */
1595     private final int _nodeType;
1596 
1597     /**
1598      * Constructor TypedDescendantIterator
1599      *
1600      *
1601      * @param nodeType Extended type ID being requested.
1602      */
1603     public TypedDescendantIterator(int nodeType)
1604     {
1605       _nodeType = nodeType;
1606     }
1607 
1608     /**
1609      * Get the next node in the iteration.
1610      *
1611      * @return The next node handle in the iteration, or END.
1612      */
1613     public int next()
1614     {
1615       final int startNode = _startNode;
1616       if (_startNode == NULL) {
1617         return NULL;
1618       }
1619 
1620       int node = _currentNode;
1621 
1622       int expType;
1623       final int nodeType = _nodeType;
1624 
1625       if (nodeType != DTM.ELEMENT_NODE)
1626       {
1627         do
1628         {
1629           node++;
1630           expType = _exptype2(node);
1631 
1632           if (NULL == expType || _parent2(node) < startNode && startNode != node) {
1633             _currentNode = NULL;
1634             return END;
1635           }
1636         }
1637         while (expType != nodeType);
1638       }
1639       // %OPT% If the start node is root (e.g. in the case of //node),
1640       // we can save the isDescendant() check, because all nodes are
1641       // descendants of root.
1642       else if (startNode == DTMDefaultBase.ROOTNODE)
1643       {
1644         do
1645         {
1646           node++;
1647           expType = _exptype2(node);
1648 
1649           if (NULL == expType) {
1650             _currentNode = NULL;
1651             return END;
1652           }
1653         } while (expType < DTM.NTYPES
1654                 || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1655       }
1656       else
1657       {
1658         do
1659         {
1660           node++;
1661           expType = _exptype2(node);
1662 
1663           if (NULL == expType || _parent2(node) < startNode && startNode != node) {
1664             _currentNode = NULL;
1665             return END;
1666           }
1667         }
1668         while (expType < DTM.NTYPES
1669                || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1670       }
1671 
1672       _currentNode = node;
1673       return returnNode(makeNodeHandle(node));
1674     }
1675   }  // end of TypedDescendantIterator
1676 
1677   /**
1678    * Iterator that returns a given node only if it is of a given type.
1679    */
1680   public final class TypedSingletonIterator extends SingletonIterator
1681   {
1682 
1683     /** The extended type ID that was requested. */
1684     private final int _nodeType;
1685 
1686     /**
1687      * Constructor TypedSingletonIterator
1688      *
1689      *
1690      * @param nodeType The extended type ID being requested.
1691      */
1692     public TypedSingletonIterator(int nodeType)
1693     {
1694       _nodeType = nodeType;
1695     }
1696 
1697     /**
1698      * Get the next node in the iteration.
1699      *
1700      * @return The next node handle in the iteration, or END.
1701      */
1702     public int next()
1703     {
1704 
1705       final int result = _currentNode;
1706       if (result == END)
1707         return DTM.NULL;
1708 
1709       _currentNode = END;
1710 
1711       if (_nodeType >= DTM.NTYPES) {
1712         if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
1713           return returnNode(result);
1714         }
1715       }
1716       else {
1717         if (_type2(makeNodeIdentity(result)) == _nodeType) {
1718           return returnNode(result);
1719         }
1720       }
1721 
1722       return NULL;
1723     }
1724   }  // end of TypedSingletonIterator
1725 
1726   /*******************************************************************
1727    *                End of nested iterators
1728    *******************************************************************/
1729 
1730 
1731   // %OPT% Array references which are used to cache the map0 arrays in
1732   // SuballocatedIntVectors. Using the cached arrays reduces the level
1733   // of indirection and results in better performance than just calling
1734   // SuballocatedIntVector.elementAt().
1735   private int[] m_exptype_map0;
1736   private int[] m_nextsib_map0;
1737   private int[] m_firstch_map0;
1738   private int[] m_parent_map0;
1739 
1740   // Double array references to the map arrays in SuballocatedIntVectors.
1741   private int[][] m_exptype_map;
1742   private int[][] m_nextsib_map;
1743   private int[][] m_firstch_map;
1744   private int[][] m_parent_map;
1745 
1746   // %OPT% Cache the array of extended types in this class
1747   protected ExtendedType[] m_extendedTypes;
1748 
1749   // A Vector which is used to store the values of attribute, namespace,
1750   // comment and PI nodes.
1751   //
1752   // %OPT% These values are unlikely to be equal. Storing
1753   // them in a plain Vector is more efficient than storing in the
1754   // DTMStringPool because we can save the cost for hash calculation.
1755   protected ArrayList<String> m_values;
1756 
1757   // The current index into the m_values Vector.
1758   private int m_valueIndex = 0;
1759 
1760   // The maximum value of the current node index.
1761   private int m_maxNodeIndex;
1762 
1763   // Cache the shift and mask values for the SuballocatedIntVectors.
1764   protected int m_SHIFT;
1765   protected int m_MASK;
1766   protected int m_blocksize;
1767 
1768   /** %OPT% If the offset and length of a Text node are within certain limits,
1769    * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
1770    * for length and 21 bits for offset. We can save two SuballocatedIntVector
1771    * calls for each getStringValueX() and dispatchCharacterEvents() call by
1772    * doing this.
1773    */
1774   // The number of bits for the length of a Text node.
1775   protected final static int TEXT_LENGTH_BITS = 10;
1776 
1777   // The number of bits for the offset of a Text node.
1778   protected final static int TEXT_OFFSET_BITS = 21;
1779 
1780   // The maximum length value
1781   protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
1782 
1783   // The maximum offset value
1784   protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
1785 
1786   // True if we want to build the ID index table.
1787   protected boolean m_buildIdIndex = true;
1788 
1789   // Constant for empty String
1790   private static final String EMPTY_STR = "";
1791 
1792   // Constant for empty XMLString
1793   private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
1794 
1795   /**
1796    * Construct a SAX2DTM2 object using the default block size.
1797    */
1798   public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
1799                  DTMWSFilter whiteSpaceFilter,
1800                  XMLStringFactory xstringfactory,
1801                  boolean doIndexing)
1802   {
1803 
1804     this(mgr, source, dtmIdentity, whiteSpaceFilter,
1805           xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
1806   }
1807 
1808   /**
1809    * Construct a SAX2DTM2 object using the given block size.
1810    */
1811   public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
1812                  DTMWSFilter whiteSpaceFilter,
1813                  XMLStringFactory xstringfactory,
1814                  boolean doIndexing,
1815                  int blocksize,
1816                  boolean usePrevsib,
1817                  boolean buildIdIndex,
1818                  boolean newNameTable)
1819   {
1820 
1821     super(mgr, source, dtmIdentity, whiteSpaceFilter,
1822           xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
1823 
1824     // Initialize the values of m_SHIFT and m_MASK.
1825     int shift;
1826     for(shift=0; (blocksize>>>=1) != 0; ++shift);
1827 
1828     m_blocksize = 1<<shift;
1829     m_SHIFT = shift;
1830     m_MASK = m_blocksize - 1;
1831 
1832     m_buildIdIndex = buildIdIndex;
1833 
1834     // Some documents do not have attribute nodes. That is why
1835     // we set the initial size of this ArrayList to be small.
1836     m_values = new ArrayList<>(32);
1837 
1838     m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
1839 
1840     // Set the map0 values in the constructor.
1841     m_exptype_map0 = m_exptype.getMap0();
1842     m_nextsib_map0 = m_nextsib.getMap0();
1843     m_firstch_map0 = m_firstch.getMap0();
1844     m_parent_map0  = m_parent.getMap0();
1845   }
1846 
1847   /**
1848    * Override DTMDefaultBase._exptype() by dropping the incremental code.
1849    *
1850    * <p>This one is less efficient than _exptype2. It is only used during
1851    * DTM building. _exptype2 is used after the document is fully built.
1852    */
1853   public final int _exptype(int identity)
1854   {
1855     return m_exptype.elementAt(identity);
1856   }
1857 
1858   /************************************************************************
1859    *             DTM base accessor interfaces
1860    *
1861    * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
1862    * very important to the DTM performance. To have the best performace,
1863    * these several interfaces have direct access to the internal arrays of
1864    * the SuballocatedIntVectors. The final modifier also has a noticeable
1865    * impact on performance.
1866    ***********************************************************************/
1867 
1868   /**
1869    * The optimized version of DTMDefaultBase._exptype().
1870    *
1871    * @param identity A node identity, which <em>must not</em> be equal to
1872    *        <code>DTM.NULL</code>
1873    */
1874   public final int _exptype2(int identity)
1875   {
1876     //return m_exptype.elementAt(identity);
1877 
1878     if (identity < m_blocksize)
1879       return m_exptype_map0[identity];
1880     else
1881       return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
1882   }
1883 
1884   /**
1885    * The optimized version of DTMDefaultBase._nextsib().
1886    *
1887    * @param identity A node identity, which <em>must not</em> be equal to
1888    *        <code>DTM.NULL</code>
1889    */
1890   public final int _nextsib2(int identity)
1891   {
1892     //return m_nextsib.elementAt(identity);
1893 
1894     if (identity < m_blocksize)
1895       return m_nextsib_map0[identity];
1896     else
1897       return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
1898   }
1899 
1900   /**
1901    * The optimized version of DTMDefaultBase._firstch().
1902    *
1903    * @param identity A node identity, which <em>must not</em> be equal to
1904    *        <code>DTM.NULL</code>
1905    */
1906   public final int _firstch2(int identity) {
1907     if (identity < m_blocksize)
1908       return m_firstch_map0[identity];
1909     else
1910       return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
1911   }
1912 
1913   /**
1914    * The optimized version of DTMDefaultBase._parent().
1915    *
1916    * @param identity A node identity, which <em>must not</em> be equal to
1917    *        <code>DTM.NULL</code>
1918    */
1919   public final int _parent2(int identity) {
1920     if (identity < m_blocksize)
1921       return m_parent_map0[identity];
1922     else
1923       return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
1924   }
1925 
1926   /**
1927    * The optimized version of DTMDefaultBase._type().
1928    *
1929    * @param identity A node identity, which <em>must not</em> be equal to
1930    *        <code>DTM.NULL</code>
1931    */
1932   public final int _type2(int identity) {
1933     int eType;
1934     if (identity < m_blocksize)
1935       eType = m_exptype_map0[identity];
1936     else
1937       eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
1938 
1939     if (NULL != eType)
1940       return m_extendedTypes[eType].getNodeType();
1941     else
1942       return NULL;
1943   }
1944 
1945   /**
1946    * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
1947    *
1948    * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
1949    * is mostly called from the compiled translets.
1950    */
1951   public final int getExpandedTypeID2(int nodeHandle) {
1952     int nodeID = makeNodeIdentity(nodeHandle);
1953 
1954     if (nodeID != NULL) {
1955       if (nodeID < m_blocksize)
1956         return m_exptype_map0[nodeID];
1957       else
1958         return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
1959     }
1960     else
1961       return NULL;
1962   }
1963 
1964   /*************************************************************************
1965    *                 END of DTM base accessor interfaces
1966    *************************************************************************/
1967 
1968   /**
1969    * Return the node type from the expanded type
1970    */
1971   public final int _exptype2Type(int exptype) {
1972     if (NULL != exptype)
1973       return m_extendedTypes[exptype].getNodeType();
1974     else
1975       return NULL;
1976   }
1977 
1978   /**
1979    * Get a prefix either from the uri mapping, or just make
1980    * one up!
1981    *
1982    * @param uri The namespace URI, which may be null.
1983    *
1984    * @return The prefix if there is one, or null.
1985    */
1986   public int getIdForNamespace(String uri) {
1987      int index = m_values.indexOf(uri);
1988      if (index < 0) {
1989        m_values.add(uri);
1990        return m_valueIndex++;
1991      } else {
1992        return index;
1993      }
1994   }
1995 
1996   /**
1997    * Override SAX2DTM.startElement()
1998    *
1999    * <p>Receive notification of the start of an element.
2000    *
2001    * <p>By default, do nothing.  Application writers may override this
2002    * method in a subclass to take specific actions at the start of
2003    * each element (such as allocating a new tree node or writing
2004    * output to a file).</p>
2005    *
2006    * @param uri The Namespace URI, or the empty string if the
2007    *        element has no Namespace URI or if Namespace
2008    *        processing is not being performed.
2009    * @param localName The local name (without prefix), or the
2010    *        empty string if Namespace processing is not being
2011    *        performed.
2012    * @param qName The qualified name (with prefix), or the
2013    *        empty string if qualified names are not available.
2014    * @param attributes The specified or defaulted attributes.
2015    * @throws SAXException Any SAX exception, possibly
2016    *            wrapping another exception.
2017    * @see ContentHandler#startElement
2018    */
2019   public void startElement(String uri, String localName, String qName,
2020                            Attributes attributes) throws SAXException
2021   {
2022     charactersFlush();
2023 
2024     // in case URI and localName are empty, the input is not using the
2025     // namespaces feature. Then we should take the part after the last
2026     // colon of qName as localName (strip all namespace prefixes)
2027     if ((uri == null || uri.isEmpty()) &&
2028         (localName == null || localName.isEmpty()))
2029     {
2030       final int colon = qName.lastIndexOf(':');
2031       localName = (colon > -1) ? qName.substring(colon + 1) : qName;
2032     }
2033 
2034     int exName = m_expandedNameTable.getExpandedTypeID(uri, localName,
2035                                                        DTM.ELEMENT_NODE);
2036 
2037     int prefixIndex = (qName.length() != localName.length())
2038                       ? m_valuesOrPrefixes.stringToIndex(qName) : 0;
2039 
2040     int elemNode = addNode(DTM.ELEMENT_NODE, exName,
2041                            m_parents.peek(), m_previous, prefixIndex, true);
2042 
2043     if (m_indexing)
2044       indexNode(exName, elemNode);
2045 
2046     m_parents.push(elemNode);
2047 
2048     int startDecls = m_contextIndexes.peek();
2049     int nDecls = m_prefixMappings.size();
2050     String prefix;
2051 
2052     if (!m_pastFirstElement) {
2053       // SPECIAL CASE: Implied declaration at root element
2054       prefix = "xml";
2055       String declURL = "http://www.w3.org/XML/1998/namespace";
2056       exName = m_expandedNameTable.getExpandedTypeID(null, prefix,
2057                                                      DTM.NAMESPACE_NODE);
2058       m_values.add(declURL);
2059       int val = m_valueIndex++;
2060       addNode(DTM.NAMESPACE_NODE, exName, elemNode,
2061                      DTM.NULL, val, false);
2062       m_pastFirstElement=true;
2063     }
2064 
2065     for (int i = startDecls; i < nDecls; i += 2) {
2066       prefix = m_prefixMappings.elementAt(i);
2067 
2068       if (prefix == null)
2069         continue;
2070 
2071       String declURL = m_prefixMappings.elementAt(i + 1);
2072 
2073       exName = m_expandedNameTable.getExpandedTypeID(null, prefix,
2074                                                      DTM.NAMESPACE_NODE);
2075 
2076       m_values.add(declURL);
2077       int val = m_valueIndex++;
2078 
2079       addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false);
2080     }
2081 
2082     int n = attributes.getLength();
2083 
2084     for (int i = 0; i < n; i++) {
2085       String attrUri = attributes.getURI(i);
2086       String attrLocalName = attributes.getLocalName(i);
2087       String attrQName = attributes.getQName(i);
2088       String valString = attributes.getValue(i);
2089 
2090       // in case URI and localName are empty, the input is not using the
2091       // namespaces feature. Then we should take the part after the last
2092       // colon of qName as localName (strip all namespace prefixes)
2093       // When the URI is empty but localName has colons then we can also
2094       // assume non namespace aware and prefixes can be stripped
2095       if (attrUri == null || attrUri.isEmpty()) {
2096         if (attrLocalName == null || attrLocalName.isEmpty()) {
2097           final int colon = attrQName.lastIndexOf(':');
2098           attrLocalName = (colon > -1) ? attrQName.substring(colon + 1) : attrQName;
2099         } else {
2100           final int colon = attrLocalName.lastIndexOf(':');
2101           attrLocalName = (colon > -1) ? attrLocalName.substring(colon + 1) : attrLocalName;
2102         }
2103       }
2104 
2105       int nodeType;
2106       if ((null != attrQName) &&
2107           (attrQName.equals("xmlns") || attrQName.startsWith("xmlns:")))
2108       {
2109         prefix = getPrefix(attrQName, attrUri);
2110         if (declAlreadyDeclared(prefix))
2111           continue;  // go to the next attribute.
2112 
2113         nodeType = DTM.NAMESPACE_NODE;
2114       } else {
2115         nodeType = DTM.ATTRIBUTE_NODE;
2116 
2117         if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID"))
2118           setIDAttribute(valString, elemNode);
2119       }
2120 
2121       // Bit of a hack... if somehow valString is null, stringToIndex will
2122       // return -1, which will make things very unhappy.
2123       if (null == valString)
2124         valString = "";
2125 
2126       m_values.add(valString);
2127       int val = m_valueIndex++;
2128 
2129       if (attrLocalName.length() != attrQName.length()) {
2130         prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
2131         int dataIndex = m_data.size();
2132         m_data.addElement(prefixIndex);
2133         m_data.addElement(val);
2134         val = -dataIndex;
2135       }
2136 
2137       exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName,
2138                                                      nodeType);
2139       addNode(nodeType, exName, elemNode, DTM.NULL, val, false);
2140     }
2141 
2142     if (null != m_wsfilter) {
2143       short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode),
2144                                                  this);
2145       boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ?
2146                             getShouldStripWhitespace() :
2147                             (DTMWSFilter.STRIP == wsv);
2148 
2149       pushShouldStripWhitespace(shouldStrip);
2150     }
2151 
2152     m_previous = DTM.NULL;
2153 
2154     m_contextIndexes.push(m_prefixMappings.size());  // for the children.
2155   }
2156 
2157   /**
2158    * Receive notification of the end of an element.
2159    *
2160    * <p>By default, do nothing.  Application writers may override this
2161    * method in a subclass to take specific actions at the end of
2162    * each element (such as finalising a tree node or writing
2163    * output to a file).</p>
2164    *
2165    * @param uri The Namespace URI, or the empty string if the
2166    *        element has no Namespace URI or if Namespace
2167    *        processing is not being performed.
2168    * @param localName The local name (without prefix), or the
2169    *        empty string if Namespace processing is not being
2170    *        performed.
2171    * @param qName The qualified XML 1.0 name (with prefix), or the
2172    *        empty string if qualified names are not available.
2173    * @throws SAXException Any SAX exception, possibly
2174    *            wrapping another exception.
2175    * @see ContentHandler#endElement
2176    */
2177   public void endElement(String uri, String localName, String qName)
2178           throws SAXException
2179   {
2180     charactersFlush();
2181 
2182     // If no one noticed, startPrefixMapping is a drag.
2183     // Pop the context for the last child (the one pushed by startElement)
2184     m_contextIndexes.quickPop(1);
2185 
2186     // Do it again for this one (the one pushed by the last endElement).
2187     int topContextIndex = m_contextIndexes.peek();
2188     if (topContextIndex != m_prefixMappings.size()) {
2189       m_prefixMappings.setSize(topContextIndex);
2190     }
2191 
2192     m_previous = m_parents.pop();
2193 
2194     popShouldStripWhitespace();
2195   }
2196 
2197   /**
2198    * Report an XML comment anywhere in the document.
2199    *
2200    * <p>This callback will be used for comments inside or outside the
2201    * document element, including comments in the external DTD
2202    * subset (if read).</p>
2203    *
2204    * @param ch An array holding the characters in the comment.
2205    * @param start The starting position in the array.
2206    * @param length The number of characters to use from the array.
2207    * @throws SAXException The application may raise an exception.
2208    */
2209   public void comment(char ch[], int start, int length) throws SAXException {
2210     if (m_insideDTD)      // ignore comments if we're inside the DTD
2211       return;
2212 
2213     charactersFlush();
2214 
2215     // %OPT% Saving the comment string in a Vector has a lower cost than
2216     // saving it in DTMStringPool.
2217     m_values.add(new String(ch, start, length));
2218     int dataIndex = m_valueIndex++;
2219 
2220     m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
2221                          m_parents.peek(), m_previous, dataIndex, false);
2222   }
2223 
2224   /**
2225    * Receive notification of the beginning of the document.
2226    *
2227    * @throws SAXException Any SAX exception, possibly
2228    *            wrapping another exception.
2229    * @see ContentHandler#startDocument
2230    */
2231   public void startDocument() throws SAXException {
2232     int doc = addNode(DTM.DOCUMENT_NODE, DTM.DOCUMENT_NODE,
2233                       DTM.NULL, DTM.NULL, 0, true);
2234 
2235     m_parents.push(doc);
2236     m_previous = DTM.NULL;
2237 
2238     m_contextIndexes.push(m_prefixMappings.size());  // for the next element.
2239   }
2240 
2241   /**
2242    * Receive notification of the end of the document.
2243    *
2244    * @throws SAXException Any SAX exception, possibly
2245    *            wrapping another exception.
2246    * @see ContentHandler#endDocument
2247    */
2248   public void endDocument() throws SAXException {
2249     super.endDocument();
2250 
2251     // Add a NULL entry to the end of the node arrays as
2252     // the end indication.
2253     m_exptype.addElement(NULL);
2254     m_parent.addElement(NULL);
2255     m_nextsib.addElement(NULL);
2256     m_firstch.addElement(NULL);
2257 
2258     // Set the cached references after the document is built.
2259     m_extendedTypes = m_expandedNameTable.getExtendedTypes();
2260     m_exptype_map = m_exptype.getMap();
2261     m_nextsib_map = m_nextsib.getMap();
2262     m_firstch_map = m_firstch.getMap();
2263     m_parent_map  = m_parent.getMap();
2264   }
2265 
2266   /**
2267    * Construct the node map from the node.
2268    *
2269    * @param type raw type ID, one of DTM.XXX_NODE.
2270    * @param expandedTypeID The expended type ID.
2271    * @param parentIndex The current parent index.
2272    * @param previousSibling The previous sibling index.
2273    * @param dataOrPrefix index into m_data table, or string handle.
2274    * @param canHaveFirstChild true if the node can have a first child, false
2275    *                          if it is atomic.
2276    *
2277    * @return The index identity of the node that was added.
2278    */
2279   protected final int addNode(int type, int expandedTypeID,
2280                               int parentIndex, int previousSibling,
2281                               int dataOrPrefix, boolean canHaveFirstChild)
2282   {
2283     // Common to all nodes:
2284     int nodeIndex = m_size++;
2285 
2286     // Have we overflowed a DTM Identity's addressing range?
2287     //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
2288     if (nodeIndex == m_maxNodeIndex) {
2289       addNewDTMID(nodeIndex);
2290       m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
2291     }
2292 
2293     m_firstch.addElement(DTM.NULL);
2294     m_nextsib.addElement(DTM.NULL);
2295     m_parent.addElement(parentIndex);
2296     m_exptype.addElement(expandedTypeID);
2297     m_dataOrQName.addElement(dataOrPrefix);
2298 
2299     if (m_prevsib != null) {
2300       m_prevsib.addElement(previousSibling);
2301     }
2302 
2303     if (m_locator != null && m_useSourceLocationProperty) {
2304       setSourceLocation();
2305     }
2306 
2307     // Note that nextSibling is not processed until charactersFlush()
2308     // is called, to handle successive characters() events.
2309 
2310     // Special handling by type: Declare namespaces, attach first child
2311     switch(type) {
2312     case DTM.NAMESPACE_NODE:
2313       declareNamespaceInContext(parentIndex,nodeIndex);
2314       break;
2315     case DTM.ATTRIBUTE_NODE:
2316       break;
2317     default:
2318       if (DTM.NULL != previousSibling) {
2319         m_nextsib.setElementAt(nodeIndex,previousSibling);
2320       } else if (DTM.NULL != parentIndex) {
2321         m_firstch.setElementAt(nodeIndex,parentIndex);
2322       }
2323       break;
2324     }
2325 
2326     return nodeIndex;
2327   }
2328 
2329   /**
2330    * Check whether accumulated text should be stripped; if not,
2331    * append the appropriate flavor of text/cdata node.
2332    */
2333   protected final void charactersFlush() {
2334     if (m_textPendingStart >= 0) { // -1 indicates no-text-in-progress
2335       int length = m_chars.size() - m_textPendingStart;
2336       boolean doStrip = false;
2337 
2338       if (getShouldStripWhitespace()) {
2339         doStrip = m_chars.isWhitespace(m_textPendingStart, length);
2340       }
2341 
2342       if (doStrip) {
2343         m_chars.setLength(m_textPendingStart);  // Discard accumulated text
2344       } else {
2345         // Guard against characters/ignorableWhitespace events that
2346         // contained no characters.  They should not result in a node.
2347         if (length > 0) {
2348           // If the offset and length do not exceed the given limits
2349           // (offset < 2^21 and length < 2^10), then save both the offset
2350           // and length in a bitwise encoded value.
2351           if (length <= TEXT_LENGTH_MAX &&
2352               m_textPendingStart <= TEXT_OFFSET_MAX) {
2353             m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
2354                                  m_parents.peek(), m_previous,
2355                                  length + (m_textPendingStart << TEXT_LENGTH_BITS),
2356                                  false);
2357 
2358           } else {
2359             // Store offset and length in the m_data array if one exceeds
2360             // the given limits. Use a negative dataIndex as an indication.
2361             int dataIndex = m_data.size();
2362             m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
2363                                  m_parents.peek(), m_previous, -dataIndex, false);
2364 
2365             m_data.addElement(m_textPendingStart);
2366             m_data.addElement(length);
2367           }
2368         }
2369       }
2370 
2371       // Reset for next text block
2372       m_textPendingStart = -1;
2373       m_textType = m_coalescedTextType = DTM.TEXT_NODE;
2374     }
2375   }
2376 
2377   /**
2378    * Override the processingInstruction() interface in SAX2DTM2.
2379    * <p>
2380    * %OPT% This one is different from SAX2DTM.processingInstruction()
2381    * in that we do not use extended types for PI nodes. The name of
2382    * the PI is saved in the DTMStringPool.
2383    *
2384    * Receive notification of a processing instruction.
2385    *
2386    * @param target The processing instruction target.
2387    * @param data The processing instruction data, or null if
2388    *             none is supplied.
2389    * @throws SAXException Any SAX exception, possibly
2390    *            wrapping another exception.
2391    * @see ContentHandler#processingInstruction
2392    */
2393   public void processingInstruction(String target, String data)
2394           throws SAXException
2395   {
2396 
2397     charactersFlush();
2398 
2399     int dataIndex = m_data.size();
2400     m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
2401                          DTM.PROCESSING_INSTRUCTION_NODE,
2402                          m_parents.peek(), m_previous,
2403                          -dataIndex, false);
2404 
2405     m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
2406     m_values.add(data);
2407     m_data.addElement(m_valueIndex++);
2408 
2409   }
2410 
2411   /**
2412    * The optimized version of DTMDefaultBase.getFirstAttribute().
2413    * <p>
2414    * Given a node handle, get the index of the node's first attribute.
2415    *
2416    * @param nodeHandle int Handle of the node.
2417    * @return Handle of first attribute, or DTM.NULL to indicate none exists.
2418    */
2419   public final int getFirstAttribute(int nodeHandle)
2420   {
2421     int nodeID = makeNodeIdentity(nodeHandle);
2422 
2423     if (nodeID == DTM.NULL)
2424       return DTM.NULL;
2425 
2426     int type = _type2(nodeID);
2427 
2428     if (DTM.ELEMENT_NODE == type)
2429     {
2430       // Assume that attributes and namespaces immediately follow the element.
2431       while (true)
2432       {
2433         nodeID++;
2434         // Assume this can not be null.
2435         type = _type2(nodeID);
2436 
2437         if (type == DTM.ATTRIBUTE_NODE)
2438         {
2439           return makeNodeHandle(nodeID);
2440         }
2441         else if (DTM.NAMESPACE_NODE != type)
2442         {
2443           break;
2444         }
2445       }
2446     }
2447 
2448     return DTM.NULL;
2449   }
2450 
2451   /**
2452    * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
2453    * <p>
2454    * Given a node identity, get the index of the node's first attribute.
2455    *
2456    * @param identity int identity of the node.
2457    * @return Identity of first attribute, or DTM.NULL to indicate none exists.
2458    */
2459   protected int getFirstAttributeIdentity(int identity) {
2460     if (identity == NULL) {
2461         return NULL;
2462     }
2463     int type = _type2(identity);
2464 
2465     if (DTM.ELEMENT_NODE == type)
2466     {
2467       // Assume that attributes and namespaces immediately follow the element.
2468       while (true)
2469       {
2470         identity++;
2471 
2472         // Assume this can not be null.
2473         type = _type2(identity);
2474 
2475         if (type == DTM.ATTRIBUTE_NODE)
2476         {
2477           return identity;
2478         }
2479         else if (DTM.NAMESPACE_NODE != type)
2480         {
2481           break;
2482         }
2483       }
2484     }
2485 
2486     return DTM.NULL;
2487   }
2488 
2489   /**
2490    * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
2491    * <p>
2492    * Given a node identity for an attribute, advance to the next attribute.
2493    *
2494    * @param identity int identity of the attribute node.  This
2495    * <strong>must</strong> be an attribute node.
2496    *
2497    * @return int DTM node-identity of the resolved attr,
2498    * or DTM.NULL to indicate none exists.
2499    *
2500    */
2501   protected int getNextAttributeIdentity(int identity) {
2502     // Assume that attributes and namespace nodes immediately follow the element
2503     while (true) {
2504       identity++;
2505       int type = _type2(identity);
2506 
2507       if (type == DTM.ATTRIBUTE_NODE) {
2508         return identity;
2509       } else if (type != DTM.NAMESPACE_NODE) {
2510         break;
2511       }
2512     }
2513 
2514     return DTM.NULL;
2515   }
2516 
2517   /**
2518    * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
2519    * <p>
2520    * Given a node handle and an expanded type ID, get the index of the node's
2521    * attribute of that type, if any.
2522    *
2523    * @param nodeHandle int Handle of the node.
2524    * @param attType int expanded type ID of the required attribute.
2525    * @return Handle of attribute of the required type, or DTM.NULL to indicate
2526    * none exists.
2527    */
2528   protected final int getTypedAttribute(int nodeHandle, int attType)
2529   {
2530 
2531     int nodeID = makeNodeIdentity(nodeHandle);
2532 
2533     if (nodeID == DTM.NULL)
2534       return DTM.NULL;
2535 
2536     int type = _type2(nodeID);
2537 
2538     if (DTM.ELEMENT_NODE == type)
2539     {
2540       int expType;
2541       while (true)
2542       {
2543         nodeID++;
2544         expType = _exptype2(nodeID);
2545 
2546         if (expType != DTM.NULL)
2547           type = m_extendedTypes[expType].getNodeType();
2548         else
2549           return DTM.NULL;
2550 
2551         if (type == DTM.ATTRIBUTE_NODE)
2552         {
2553           if (expType == attType) return makeNodeHandle(nodeID);
2554         }
2555         else if (DTM.NAMESPACE_NODE != type)
2556         {
2557           break;
2558         }
2559       }
2560     }
2561 
2562     return DTM.NULL;
2563   }
2564 
2565   /**
2566    * Override SAX2DTM.getLocalName() in SAX2DTM2.
2567    * <p>Processing for PIs is different.
2568    *
2569    * Given a node handle, return its XPath- style localname. (As defined in
2570    * Namespaces, this is the portion of the name after any colon character).
2571    *
2572    * @param nodeHandle the id of the node.
2573    * @return String Local name of this node.
2574    */
2575   public String getLocalName(int nodeHandle)
2576   {
2577     int expType = _exptype(makeNodeIdentity(nodeHandle));
2578 
2579     if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
2580     {
2581       int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
2582       dataIndex = m_data.elementAt(-dataIndex);
2583       return m_valuesOrPrefixes.indexToString(dataIndex);
2584     }
2585     else
2586       return m_expandedNameTable.getLocalName(expType);
2587   }
2588 
2589   /**
2590    * The optimized version of SAX2DTM.getNodeNameX().
2591    * <p>
2592    * Given a node handle, return the XPath node name. This should be the name
2593    * as described by the XPath data model, NOT the DOM- style name.
2594    *
2595    * @param nodeHandle the id of the node.
2596    * @return String Name of this node, which may be an empty string.
2597    */
2598   public final String getNodeNameX(int nodeHandle)
2599   {
2600 
2601     int nodeID = makeNodeIdentity(nodeHandle);
2602     int eType = _exptype2(nodeID);
2603 
2604     if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
2605     {
2606       int dataIndex = _dataOrQName(nodeID);
2607       dataIndex = m_data.elementAt(-dataIndex);
2608       return m_valuesOrPrefixes.indexToString(dataIndex);
2609     }
2610 
2611     final ExtendedType extType = m_extendedTypes[eType];
2612 
2613     if (extType.getNamespace().length() == 0)
2614     {
2615       return extType.getLocalName();
2616     }
2617     else
2618     {
2619       int qnameIndex = m_dataOrQName.elementAt(nodeID);
2620 
2621       if (qnameIndex == 0)
2622         return extType.getLocalName();
2623 
2624       if (qnameIndex < 0)
2625       {
2626         qnameIndex = -qnameIndex;
2627         qnameIndex = m_data.elementAt(qnameIndex);
2628       }
2629 
2630       return m_valuesOrPrefixes.indexToString(qnameIndex);
2631     }
2632   }
2633 
2634   /**
2635    * The optimized version of SAX2DTM.getNodeName().
2636    * <p>
2637    * Given a node handle, return its DOM-style node name. This will include
2638    * names such as #text or #document.
2639    *
2640    * @param nodeHandle the id of the node.
2641    * @return String Name of this node, which may be an empty string.
2642    * %REVIEW% Document when empty string is possible...
2643    * %REVIEW-COMMENT% It should never be empty, should it?
2644    */
2645   public String getNodeName(int nodeHandle)
2646   {
2647 
2648     int nodeID = makeNodeIdentity(nodeHandle);
2649     int eType = _exptype2(nodeID);
2650 
2651     final ExtendedType extType = m_extendedTypes[eType];
2652     if (extType.getNamespace().length() == 0)
2653     {
2654       int type = extType.getNodeType();
2655 
2656       String localName = extType.getLocalName();
2657       if (type == DTM.NAMESPACE_NODE)
2658       {
2659         if (localName.length() == 0)
2660           return "xmlns";
2661         else
2662           return "xmlns:" + localName;
2663       }
2664       else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
2665       {
2666         int dataIndex = _dataOrQName(nodeID);
2667         dataIndex = m_data.elementAt(-dataIndex);
2668         return m_valuesOrPrefixes.indexToString(dataIndex);
2669       }
2670       else if (localName.length() == 0)
2671       {
2672         return getFixedNames(type);
2673       }
2674       else
2675         return localName;
2676     }
2677     else
2678     {
2679       int qnameIndex = m_dataOrQName.elementAt(nodeID);
2680 
2681       if (qnameIndex == 0)
2682         return extType.getLocalName();
2683 
2684       if (qnameIndex < 0)
2685       {
2686         qnameIndex = -qnameIndex;
2687         qnameIndex = m_data.elementAt(qnameIndex);
2688       }
2689 
2690       return m_valuesOrPrefixes.indexToString(qnameIndex);
2691     }
2692   }
2693 
2694   /**
2695    * Override SAX2DTM.getStringValue(int)
2696    * <p>
2697    * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
2698    * <p>
2699    * If the caller supplies an XMLStringFactory, the getStringValue() interface
2700    * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
2701    * wraps the returned String in an XMLString.
2702    *
2703    * Get the string-value of a node as a String object
2704    * (see http://www.w3.org/TR/xpath#data-model
2705    * for the definition of a node's string-value).
2706    *
2707    * @param nodeHandle The node ID.
2708    *
2709    * @return A string object that represents the string-value of the given node.
2710    */
2711   public XMLString getStringValue(int nodeHandle)
2712   {
2713     int identity = makeNodeIdentity(nodeHandle);
2714     if (identity == DTM.NULL)
2715       return EMPTY_XML_STR;
2716 
2717     int type= _type2(identity);
2718 
2719     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
2720     {
2721       int startNode = identity;
2722       identity = _firstch2(identity);
2723       if (DTM.NULL != identity)
2724       {
2725         int offset = -1;
2726         int length = 0;
2727 
2728         do
2729         {
2730           type = _exptype2(identity);
2731 
2732           if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
2733           {
2734             int dataIndex = m_dataOrQName.elementAt(identity);
2735             if (dataIndex >= 0)
2736             {
2737               if (-1 == offset)
2738               {
2739                 offset = dataIndex >>> TEXT_LENGTH_BITS;
2740               }
2741 
2742               length += dataIndex & TEXT_LENGTH_MAX;
2743             }
2744             else
2745             {
2746               if (-1 == offset)
2747               {
2748                 offset = m_data.elementAt(-dataIndex);
2749               }
2750 
2751               length += m_data.elementAt(-dataIndex + 1);
2752             }
2753           }
2754 
2755           identity++;
2756         } while (_parent2(identity) >= startNode);
2757 
2758         if (length > 0)
2759         {
2760           if (m_xstrf != null)
2761             return m_xstrf.newstr(m_chars, offset, length);
2762           else
2763             return new XMLStringDefault(m_chars.getString(offset, length));
2764         }
2765         else
2766           return EMPTY_XML_STR;
2767       }
2768       else
2769         return EMPTY_XML_STR;
2770     }
2771     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
2772     {
2773       int dataIndex = m_dataOrQName.elementAt(identity);
2774       if (dataIndex >= 0)
2775       {
2776         if (m_xstrf != null)
2777           return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
2778                          dataIndex & TEXT_LENGTH_MAX);
2779         else
2780           return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
2781                                       dataIndex & TEXT_LENGTH_MAX));
2782       }
2783       else
2784       {
2785         if (m_xstrf != null)
2786           return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
2787                                 m_data.elementAt(-dataIndex+1));
2788         else
2789           return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
2790                                    m_data.elementAt(-dataIndex+1)));
2791       }
2792     }
2793     else
2794     {
2795       int dataIndex = m_dataOrQName.elementAt(identity);
2796 
2797       if (dataIndex < 0)
2798       {
2799         dataIndex = -dataIndex;
2800         dataIndex = m_data.elementAt(dataIndex + 1);
2801       }
2802 
2803       if (m_xstrf != null)
2804         return m_xstrf.newstr(m_values.get(dataIndex));
2805       else
2806         return new XMLStringDefault(m_values.get(dataIndex));
2807     }
2808   }
2809 
2810   /**
2811    * The optimized version of SAX2DTM.getStringValue(int).
2812    * <p>
2813    * %OPT% This is one of the most often used interfaces. Performance is
2814    * critical here. This one is different from SAX2DTM.getStringValue(int) in
2815    * that it returns a String instead of a XMLString.
2816    *
2817    * Get the string- value of a node as a String object (see http: //www. w3.
2818    * org/TR/xpath#data- model for the definition of a node's string- value).
2819    *
2820    * @param nodeHandle The node ID.
2821    *
2822    * @return A string object that represents the string-value of the given node.
2823    */
2824   public final String getStringValueX(final int nodeHandle)
2825   {
2826     int identity = makeNodeIdentity(nodeHandle);
2827     if (identity == DTM.NULL)
2828       return EMPTY_STR;
2829 
2830     int type= _type2(identity);
2831 
2832     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
2833     {
2834       int startNode = identity;
2835       identity = _firstch2(identity);
2836       if (DTM.NULL != identity)
2837       {
2838         int offset = -1;
2839         int length = 0;
2840 
2841         do
2842         {
2843           type = _exptype2(identity);
2844 
2845           if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
2846           {
2847             int dataIndex = m_dataOrQName.elementAt(identity);
2848             if (dataIndex >= 0)
2849             {
2850               if (-1 == offset)
2851               {
2852                 offset = dataIndex >>> TEXT_LENGTH_BITS;
2853               }
2854 
2855               length += dataIndex & TEXT_LENGTH_MAX;
2856             }
2857             else
2858             {
2859               if (-1 == offset)
2860               {
2861                 offset = m_data.elementAt(-dataIndex);
2862               }
2863 
2864               length += m_data.elementAt(-dataIndex + 1);
2865             }
2866           }
2867 
2868           identity++;
2869         } while (_parent2(identity) >= startNode);
2870 
2871         if (length > 0)
2872         {
2873           return m_chars.getString(offset, length);
2874         }
2875         else
2876           return EMPTY_STR;
2877       }
2878       else
2879         return EMPTY_STR;
2880     }
2881     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
2882     {
2883       int dataIndex = m_dataOrQName.elementAt(identity);
2884       if (dataIndex >= 0)
2885       {
2886         return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
2887                                   dataIndex & TEXT_LENGTH_MAX);
2888       }
2889       else
2890       {
2891         return m_chars.getString(m_data.elementAt(-dataIndex),
2892                                   m_data.elementAt(-dataIndex+1));
2893       }
2894     }
2895     else
2896     {
2897       int dataIndex = m_dataOrQName.elementAt(identity);
2898 
2899       if (dataIndex < 0)
2900       {
2901         dataIndex = -dataIndex;
2902         dataIndex = m_data.elementAt(dataIndex + 1);
2903       }
2904 
2905       return m_values.get(dataIndex);
2906     }
2907   }
2908 
2909   /**
2910    * Returns the string value of the entire tree
2911    */
2912   public String getStringValue()
2913   {
2914     int child = _firstch2(ROOTNODE);
2915     if (child == DTM.NULL) return EMPTY_STR;
2916 
2917     // optimization: only create StringBuffer if > 1 child
2918     if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
2919     {
2920       int dataIndex = m_dataOrQName.elementAt(child);
2921       if (dataIndex >= 0)
2922         return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
2923       else
2924         return m_chars.getString(m_data.elementAt(-dataIndex),
2925                                   m_data.elementAt(-dataIndex + 1));
2926     }
2927     else
2928       return getStringValueX(getDocument());
2929 
2930   }
2931 
2932   /**
2933    * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
2934    * <p>
2935    * Directly call the
2936    * characters method on the passed ContentHandler for the
2937    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2938    * for the definition of a node's string-value). Multiple calls to the
2939    * ContentHandler's characters methods may well occur for a single call to
2940    * this method.
2941    *
2942    * @param nodeHandle The node ID.
2943    * @param ch A non-null reference to a ContentHandler.
2944    * @param normalize true if the content should be normalized according to
2945    * the rules for the XPath
2946    * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
2947    * function.
2948    *
2949    * @throws SAXException
2950    */
2951   public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
2952                                              boolean normalize)
2953           throws SAXException
2954   {
2955 
2956     int identity = makeNodeIdentity(nodeHandle);
2957 
2958     if (identity == DTM.NULL)
2959       return;
2960 
2961     int type = _type2(identity);
2962 
2963     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
2964     {
2965       int startNode = identity;
2966       identity = _firstch2(identity);
2967       if (DTM.NULL != identity)
2968       {
2969         int offset = -1;
2970         int length = 0;
2971 
2972         do
2973         {
2974           type = _exptype2(identity);
2975 
2976           if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
2977           {
2978             int dataIndex = m_dataOrQName.elementAt(identity);
2979 
2980             if (dataIndex >= 0)
2981             {
2982               if (-1 == offset)
2983               {
2984                 offset = dataIndex >>> TEXT_LENGTH_BITS;
2985               }
2986 
2987               length += dataIndex & TEXT_LENGTH_MAX;
2988             }
2989             else
2990             {
2991               if (-1 == offset)
2992               {
2993                 offset = m_data.elementAt(-dataIndex);
2994               }
2995 
2996               length += m_data.elementAt(-dataIndex + 1);
2997             }
2998           }
2999 
3000           identity++;
3001         } while (_parent2(identity) >= startNode);
3002 
3003         if (length > 0)
3004         {
3005           if(normalize)
3006             m_chars.sendNormalizedSAXcharacters(ch, offset, length);
3007           else
3008             m_chars.sendSAXcharacters(ch, offset, length);
3009         }
3010       }
3011     }
3012     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
3013     {
3014       int dataIndex = m_dataOrQName.elementAt(identity);
3015 
3016       if (dataIndex >= 0)
3017       {
3018         if (normalize)
3019           m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
3020                                               dataIndex & TEXT_LENGTH_MAX);
3021         else
3022           m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
3023                                     dataIndex & TEXT_LENGTH_MAX);
3024       }
3025       else
3026       {
3027         if (normalize)
3028           m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
3029                                               m_data.elementAt(-dataIndex+1));
3030         else
3031           m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
3032                                     m_data.elementAt(-dataIndex+1));
3033       }
3034     }
3035     else
3036     {
3037       int dataIndex = m_dataOrQName.elementAt(identity);
3038 
3039       if (dataIndex < 0)
3040       {
3041         dataIndex = -dataIndex;
3042         dataIndex = m_data.elementAt(dataIndex + 1);
3043       }
3044 
3045       String str = m_values.get(dataIndex);
3046 
3047       if(normalize)
3048         FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
3049                                                      0, str.length(), ch);
3050       else
3051         ch.characters(str.toCharArray(), 0, str.length());
3052     }
3053   }
3054 
3055   /**
3056    * Given a node handle, return its node value. This is mostly
3057    * as defined by the DOM, but may ignore some conveniences.
3058    * <p>
3059    *
3060    * @param nodeHandle The node id.
3061    * @return String Value of this node, or null if not
3062    * meaningful for this node type.
3063    */
3064   public String getNodeValue(int nodeHandle)
3065   {
3066 
3067     int identity = makeNodeIdentity(nodeHandle);
3068     int type = _type2(identity);
3069 
3070     if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
3071     {
3072       int dataIndex = _dataOrQName(identity);
3073       if (dataIndex > 0)
3074       {
3075         return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
3076                                   dataIndex & TEXT_LENGTH_MAX);
3077       }
3078       else
3079       {
3080         return m_chars.getString(m_data.elementAt(-dataIndex),
3081                                   m_data.elementAt(-dataIndex+1));
3082       }
3083     }
3084     else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
3085              || DTM.DOCUMENT_NODE == type)
3086     {
3087       return null;
3088     }
3089     else
3090     {
3091       int dataIndex = m_dataOrQName.elementAt(identity);
3092 
3093       if (dataIndex < 0)
3094       {
3095         dataIndex = -dataIndex;
3096         dataIndex = m_data.elementAt(dataIndex + 1);
3097       }
3098 
3099       return m_values.get(dataIndex);
3100     }
3101   }
3102 
3103     /**
3104      * Copy the String value of a Text node to a SerializationHandler
3105      */
3106     protected final void copyTextNode(final int nodeID, SerializationHandler handler)
3107         throws SAXException
3108     {
3109         if (nodeID != DTM.NULL) {
3110             int dataIndex = m_dataOrQName.elementAt(nodeID);
3111             if (dataIndex >= 0) {
3112                 m_chars.sendSAXcharacters(handler,
3113                                           dataIndex >>> TEXT_LENGTH_BITS,
3114                                           dataIndex & TEXT_LENGTH_MAX);
3115             } else {
3116                 m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
3117                                           m_data.elementAt(-dataIndex+1));
3118             }
3119         }
3120     }
3121 
3122     /**
3123      * Copy an Element node to a SerializationHandler.
3124      *
3125      * @param nodeID The node identity
3126      * @param exptype The expanded type of the Element node
3127      * @param handler The SerializationHandler
3128      * @return The qualified name of the Element node.
3129      */
3130     protected final String copyElement(int nodeID, int exptype,
3131                                SerializationHandler handler)
3132         throws SAXException
3133     {
3134         final ExtendedType extType = m_extendedTypes[exptype];
3135         String uri = extType.getNamespace();
3136         String name = extType.getLocalName();
3137 
3138         if (uri.length() == 0) {
3139             handler.startElement(name);
3140             return name;
3141         } else {
3142             int qnameIndex = m_dataOrQName.elementAt(nodeID);
3143 
3144             if (qnameIndex == 0) {
3145                 handler.startElement(name);
3146                 handler.namespaceAfterStartElement(EMPTY_STR, uri);
3147                 return name;
3148             }
3149 
3150             if (qnameIndex < 0) {
3151                 qnameIndex = -qnameIndex;
3152                 qnameIndex = m_data.elementAt(qnameIndex);
3153             }
3154 
3155             String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
3156             handler.startElement(qName);
3157             int prefixIndex = qName.indexOf(':');
3158             String prefix;
3159             if (prefixIndex > 0) {
3160                 prefix = qName.substring(0, prefixIndex);
3161             } else {
3162                 prefix = null;
3163             }
3164             handler.namespaceAfterStartElement(prefix, uri);
3165             return qName;
3166         }
3167     }
3168 
3169     /**
3170      * Copy  namespace nodes.
3171      *
3172      * @param nodeID The Element node identity
3173      * @param handler The SerializationHandler
3174      * @param inScope  true if all namespaces in scope should be copied,
3175      *  false if only the namespace declarations should be copied.
3176      */
3177     protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
3178         throws SAXException
3179     {
3180         // %OPT% Optimization for documents which does not have any explicit
3181         // namespace nodes. For these documents, there is an implicit
3182         // namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace")
3183         // declared on the root element node. In this case, there is no
3184         // need to do namespace copying. We can safely return without
3185         // doing anything.
3186         if (m_namespaceDeclSetElements != null &&
3187             m_namespaceDeclSetElements.size() == 1 &&
3188             m_namespaceDeclSets != null &&
3189             ((SuballocatedIntVector)m_namespaceDeclSets.elementAt(0))
3190             .size() == 1)
3191             return;
3192 
3193         SuballocatedIntVector nsContext = null;
3194         int nextNSNode;
3195 
3196         // Find the first namespace node
3197         if (inScope) {
3198             nsContext = findNamespaceContext(nodeID);
3199             if (nsContext == null || nsContext.size() < 1)
3200                 return;
3201             else
3202                 nextNSNode = makeNodeIdentity(nsContext.elementAt(0));
3203         }
3204         else
3205             nextNSNode = getNextNamespaceNode2(nodeID);
3206 
3207         int nsIndex = 1;
3208         while (nextNSNode != DTM.NULL) {
3209             // Retrieve the name of the namespace node
3210             int eType = _exptype2(nextNSNode);
3211             String nodeName = m_extendedTypes[eType].getLocalName();
3212 
3213             // Retrieve the node value of the namespace node
3214             int dataIndex = m_dataOrQName.elementAt(nextNSNode);
3215 
3216             if (dataIndex < 0) {
3217                 dataIndex = -dataIndex;
3218                 dataIndex = m_data.elementAt(dataIndex + 1);
3219             }
3220 
3221             String nodeValue = m_values.get(dataIndex);
3222 
3223             handler.namespaceAfterStartElement(nodeName, nodeValue);
3224 
3225             if (inScope) {
3226                 if (nsIndex < nsContext.size()) {
3227                     nextNSNode = makeNodeIdentity(nsContext.elementAt(nsIndex));
3228                     nsIndex++;
3229                 }
3230                 else
3231                     return;
3232             }
3233             else
3234                 nextNSNode = getNextNamespaceNode2(nextNSNode);
3235         }
3236     }
3237 
3238     /**
3239      * Return the next namespace node following the given base node.
3240      *
3241      * @baseID The node identity of the base node, which can be an
3242      * element, attribute or namespace node.
3243      * @return The namespace node immediately following the base node.
3244      */
3245     protected final int getNextNamespaceNode2(int baseID) {
3246         int type;
3247         while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE);
3248 
3249         if (type == DTM.NAMESPACE_NODE)
3250             return baseID;
3251         else
3252             return NULL;
3253     }
3254 
3255     /**
3256      * Copy  attribute nodes from an element .
3257      *
3258      * @param nodeID The Element node identity
3259      * @param handler The SerializationHandler
3260      */
3261     protected final void copyAttributes(final int nodeID, SerializationHandler handler)
3262         throws SAXException{
3263 
3264        for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
3265             int eType = _exptype2(current);
3266             copyAttribute(current, eType, handler);
3267        }
3268     }
3269 
3270 
3271     /**
3272      * Copy an Attribute node to a SerializationHandler
3273      *
3274      * @param nodeID The node identity
3275      * @param exptype The expanded type of the Element node
3276      * @param handler The SerializationHandler
3277      */
3278     protected final void copyAttribute(int nodeID, int exptype,
3279         SerializationHandler handler)
3280         throws SAXException
3281     {
3282         final ExtendedType extType = m_extendedTypes[exptype];
3283         final String uri = extType.getNamespace();
3284         final String localName = extType.getLocalName();
3285 
3286         String prefix = null;
3287         String qname = null;
3288         int dataIndex = _dataOrQName(nodeID);
3289         int valueIndex = dataIndex;
3290             if (dataIndex <= 0) {
3291                 int prefixIndex = m_data.elementAt(-dataIndex);
3292                 valueIndex = m_data.elementAt(-dataIndex+1);
3293                 qname = m_valuesOrPrefixes.indexToString(prefixIndex);
3294                 int colonIndex = qname.indexOf(':');
3295                 if (colonIndex > 0) {
3296                     prefix = qname.substring(0, colonIndex);
3297                 }
3298             }
3299             if (uri.length() != 0) {
3300                 handler.namespaceAfterStartElement(prefix, uri);
3301             }
3302 
3303         String nodeName = (prefix != null) ? qname : localName;
3304         String nodeValue = m_values.get(valueIndex);
3305 
3306         handler.addAttribute(uri, localName, nodeName, "CDATA", nodeValue);
3307     }
3308 
3309 }