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