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