• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package org.apache.xml.dtm.ref.sax2dtm;
22 
23 import org.apache.xml.dtm.*;
24 import org.apache.xml.dtm.ref.*;
25 import org.apache.xml.utils.FastStringBuffer;
26 import org.apache.xml.utils.XMLString;
27 import org.apache.xml.utils.XMLStringDefault;
28 import org.apache.xml.utils.XMLStringFactory;
29 import org.apache.xml.res.XMLMessages;
30 import org.apache.xml.res.XMLErrorResources;
31 import org.apache.xml.serializer.SerializationHandler;
32 
33 import javax.xml.transform.Source;
34 import java.util.Vector;
35 import org.apache.xml.utils.SuballocatedIntVector;
36 import 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  */
61 public 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      */
setStartNode(int node)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      */
next()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      */
setStartNode(int node)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      */
setNodeType(final int type)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      */
next()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      */
TypedChildrenIterator(int nodeType)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      */
setStartNode(int node)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      */
next()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      */
getNodeByPosition(int position)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      */
TypedRootIterator(int nodeType)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      */
next()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      */
setStartNode(int node)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      */
next()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      */
TypedFollowingSiblingIterator(int type)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      */
next()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      */
setStartNode(int node)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      */
next()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      */
TypedAttributeIterator(int nodeType)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      */
setStartNode(int node)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      */
next()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      */
isReverse()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      */
setStartNode(int node)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      */
next()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      */
TypedPrecedingSiblingIterator(int type)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      */
next()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      */
getLast()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      */
isReverse()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      */
cloneIterator()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      */
setStartNode(int node)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      */
next()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      */
reset()934     public DTMAxisIterator reset()
935     {
936 
937       _sp = _oldsp;
938 
939       return resetPosition();
940     }
941 
setMark()942     public void setMark() {
943         _markedsp = _sp;
944         _markedNode = _currentNode;
945         _markedDescendant = _stack[0];
946     }
947 
gotoMark()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      */
TypedPrecedingIterator(int type)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      */
next()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 
FollowingIterator()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      */
setStartNode(int node)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      */
next()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      */
TypedFollowingIterator(int type)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      */
next()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      */
getStartNode()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      */
isReverse()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      */
cloneIterator()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      */
setStartNode(int node)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      */
reset()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      */
next()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 
setMark()1375     public void setMark() {
1376         m_markedPos = m_ancestorsPos;
1377     }
1378 
gotoMark()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      */
TypedAncestorIterator(int type)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      */
setStartNode(int node)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      */
getNodeByPosition(int position)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      */
getLast()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      */
setStartNode(int node)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      */
isDescendant(int identity)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      */
next()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      */
reset()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      */
TypedDescendantIterator(int nodeType)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      */
next()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      */
TypedSingletonIterator(int nodeType)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      */
next()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    */
SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)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    */
SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean buildIdIndex, boolean newNameTable)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    */
_exptype(int identity)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    */
_exptype2(int identity)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    */
_nextsib2(int identity)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    */
_firstch2(int identity)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    */
_parent2(int identity)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    */
_type2(int identity)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    */
getExpandedTypeID2(int nodeHandle)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    */
_exptype2Type(int exptype)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    */
getIdForNamespace(String uri)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    */
startElement(String uri, String localName, String qName, Attributes attributes)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    */
endElement(String uri, String localName, String qName)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    */
comment(char ch[], int start, int length)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    */
startDocument()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    */
endDocument()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    */
addNode(int type, int expandedTypeID, int parentIndex, int previousSibling, int dataOrPrefix, boolean canHaveFirstChild)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    */
charactersFlush()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    */
processingInstruction(String target, String data)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    */
getFirstAttribute(int nodeHandle)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    */
getFirstAttributeIdentity(int identity)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    */
getNextAttributeIdentity(int identity)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    */
getTypedAttribute(int nodeHandle, int attType)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    */
getLocalName(int nodeHandle)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    */
getNodeNameX(int nodeHandle)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    */
getNodeName(int nodeHandle)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    */
getStringValue(int nodeHandle)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    */
getStringValueX(final int nodeHandle)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    */
getStringValue()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    */
dispatchCharactersEvents(int nodeHandle, ContentHandler ch, boolean normalize)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    */
getNodeValue(int nodeHandle)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      */
copyTextNode(final int nodeID, SerializationHandler handler)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      */
copyElement(int nodeID, int exptype, SerializationHandler handler)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      */
copyNS(final int nodeID, SerializationHandler handler, boolean inScope)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      */
getNextNamespaceNode2(int baseID)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      */
copyAttributes(final int nodeID, SerializationHandler handler)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      */
copyAttribute(int nodeID, int exptype, SerializationHandler handler)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