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