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