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