1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xml.internal.dtm.ref;
22 
23 import com.sun.org.apache.xml.internal.dtm.*;
24 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
25 import com.sun.org.apache.xml.internal.res.XMLMessages;
26 import com.sun.org.apache.xml.internal.utils.BoolStack;
27 import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
28 import com.sun.org.apache.xml.internal.utils.XMLString;
29 import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
30 import java.io.*; // for dumpDTM
31 import java.util.Vector;
32 import javax.xml.transform.Source;
33 
34 /**
35  * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
36  * It sets up structures for navigation and type, while leaving data
37  * management and construction to the derived classes.
38  *
39  * @LastModified: Oct 2017
40  */
41 public abstract class DTMDefaultBase implements DTM
42 {
43     static final boolean JJK_DEBUG=false;
44 
45   // This constant is likely to be removed in the future. Use the
46   // getDocument() method instead of ROOTNODE to get at the root
47   // node of a DTM.
48   /** The identity of the root node. */
49   public static final int ROOTNODE = 0;
50 
51   /**
52    * The number of nodes, which is also used to determine the next
53    *  node index.
54    */
55   protected int m_size = 0;
56 
57   /** The expanded names, one array element for each node. */
58   protected SuballocatedIntVector m_exptype;
59 
60   /** First child values, one array element for each node. */
61   protected SuballocatedIntVector m_firstch;
62 
63   /** Next sibling values, one array element for each node. */
64   protected SuballocatedIntVector m_nextsib;
65 
66   /** Previous sibling values, one array element for each node. */
67   protected SuballocatedIntVector m_prevsib;
68 
69   /** Previous sibling values, one array element for each node. */
70   protected SuballocatedIntVector m_parent;
71 
72   /** Vector of SuballocatedIntVectors of NS decl sets */
73   protected Vector<SuballocatedIntVector> m_namespaceDeclSets = null;
74 
75   /** SuballocatedIntVector  of elements at which corresponding
76    * namespaceDeclSets were defined */
77   protected SuballocatedIntVector m_namespaceDeclSetElements = null;
78 
79   /**
80    * These hold indexes to elements based on namespace and local name.
81    * The base lookup is the the namespace.  The second lookup is the local
82    * name, and the last array contains the the first free element
83    * at the start, and the list of element handles following.
84    */
85   protected int[][][] m_elemIndexes;
86 
87   /** The default block size of the node arrays */
88   public static final int DEFAULT_BLOCKSIZE = 512;  // favor small docs.
89 
90   /** The number of blocks for the node arrays */
91   public static final int DEFAULT_NUMBLOCKS = 32;
92 
93   /** The number of blocks used for small documents & RTFs */
94   public static final int DEFAULT_NUMBLOCKS_SMALL = 4;
95 
96   /** The block size of the node arrays */
97   //protected final int m_blocksize;
98 
99   /**
100    * The value to use when the information has not been built yet.
101    */
102   protected static final int NOTPROCESSED = DTM.NULL - 1;
103 
104   /**
105    * The DTM manager who "owns" this DTM.
106    */
107 
108   public DTMManager m_mgr;
109 
110   /**
111    * m_mgr cast to DTMManagerDefault, or null if it isn't an instance
112    * (Efficiency hook)
113    */
114   protected DTMManagerDefault m_mgrDefault=null;
115 
116 
117   /** The document identity number(s). If we have overflowed the addressing
118    * range of the first that was assigned to us, we may add others. */
119   protected SuballocatedIntVector m_dtmIdent;
120 
121   /** The mask for the identity.
122       %REVIEW% Should this really be set to the _DEFAULT? What if
123       a particular DTM wanted to use another value? */
124   //protected final static int m_mask = DTMManager.IDENT_NODE_DEFAULT;
125 
126   /** The base URI for this document. */
127   protected String m_documentBaseURI;
128 
129   /**
130    * The whitespace filter that enables elements to strip whitespace or not.
131    */
132   protected DTMWSFilter m_wsfilter;
133 
134   /** Flag indicating whether to strip whitespace nodes */
135   protected boolean m_shouldStripWS = false;
136 
137   /** Stack of flags indicating whether to strip whitespace nodes */
138   protected BoolStack m_shouldStripWhitespaceStack;
139 
140   /** The XMLString factory for creating XMLStrings. */
141   protected XMLStringFactory m_xstrf;
142 
143   /**
144    * The table for exandedNameID lookups.  This may or may not be the same
145    * table as is contained in the DTMManagerDefault.
146    */
147   protected ExpandedNameTable m_expandedNameTable;
148 
149   /** true if indexing is turned on. */
150   protected boolean m_indexing;
151 
152   /**
153    * Construct a DTMDefaultBase object using the default block size.
154    *
155    * @param mgr The DTMManager who owns this DTM.
156    * @param source The object that is used to specify the construction source.
157    * @param dtmIdentity The DTM identity ID for this DTM.
158    * @param whiteSpaceFilter The white space filter for this DTM, which may
159    *                         be null.
160    * @param xstringfactory The factory to use for creating XMLStrings.
161    * @param doIndexing true if the caller considers it worth it to use
162    *                   indexing schemes.
163    */
DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)164   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
165                         DTMWSFilter whiteSpaceFilter,
166                         XMLStringFactory xstringfactory, boolean doIndexing)
167   {
168     this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
169          doIndexing, DEFAULT_BLOCKSIZE, true, false);
170   }
171 
172   /**
173    * Construct a DTMDefaultBase object from a DOM node.
174    *
175    * @param mgr The DTMManager who owns this DTM.
176    * @param source The object that is used to specify the construction source.
177    * @param dtmIdentity The DTM identity ID for this DTM.
178    * @param whiteSpaceFilter The white space filter for this DTM, which may
179    *                         be null.
180    * @param xstringfactory The factory to use for creating XMLStrings.
181    * @param doIndexing true if the caller considers it worth it to use
182    *                   indexing schemes.
183    * @param blocksize The block size of the DTM.
184    * @param usePrevsib true if we want to build the previous sibling node array.
185    * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
186    */
DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean newNameTable)187   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
188                         DTMWSFilter whiteSpaceFilter,
189                         XMLStringFactory xstringfactory, boolean doIndexing,
190                         int blocksize, boolean usePrevsib,
191                         boolean newNameTable)
192   {
193     // Use smaller sizes for the internal node arrays if the block size
194     // is small.
195     int numblocks;
196     if (blocksize <= 64)
197     {
198       numblocks = DEFAULT_NUMBLOCKS_SMALL;
199       m_dtmIdent= new SuballocatedIntVector(4, 1);
200     }
201     else
202     {
203       numblocks = DEFAULT_NUMBLOCKS;
204       m_dtmIdent= new SuballocatedIntVector(32);
205     }
206 
207     m_exptype = new SuballocatedIntVector(blocksize, numblocks);
208     m_firstch = new SuballocatedIntVector(blocksize, numblocks);
209     m_nextsib = new SuballocatedIntVector(blocksize, numblocks);
210     m_parent  = new SuballocatedIntVector(blocksize, numblocks);
211 
212     // Only create the m_prevsib array if the usePrevsib flag is true.
213     // Some DTM implementations (e.g. SAXImpl) do not need this array.
214     // We can save the time to build it in those cases.
215     if (usePrevsib)
216       m_prevsib = new SuballocatedIntVector(blocksize, numblocks);
217 
218     m_mgr = mgr;
219     if(mgr instanceof DTMManagerDefault)
220       m_mgrDefault=(DTMManagerDefault)mgr;
221 
222     m_documentBaseURI = (null != source) ? source.getSystemId() : null;
223     m_dtmIdent.setElementAt(dtmIdentity,0);
224     m_wsfilter = whiteSpaceFilter;
225     m_xstrf = xstringfactory;
226     m_indexing = doIndexing;
227 
228     if (doIndexing)
229     {
230       m_expandedNameTable = new ExpandedNameTable();
231     }
232     else
233     {
234       // Note that this fails if we aren't talking to an instance of
235       // DTMManagerDefault
236       m_expandedNameTable = m_mgrDefault.getExpandedNameTable(this);
237     }
238 
239     if (null != whiteSpaceFilter)
240     {
241       m_shouldStripWhitespaceStack = new BoolStack();
242 
243       pushShouldStripWhitespace(false);
244     }
245   }
246 
247   /**
248    * Ensure that the size of the element indexes can hold the information.
249    *
250    * @param namespaceID Namespace ID index.
251    * @param LocalNameID Local name ID.
252    */
ensureSizeOfIndex(int namespaceID, int LocalNameID)253   protected void ensureSizeOfIndex(int namespaceID, int LocalNameID)
254   {
255 
256     if (null == m_elemIndexes)
257     {
258       m_elemIndexes = new int[namespaceID + 20][][];
259     }
260     else if (m_elemIndexes.length <= namespaceID)
261     {
262       int[][][] indexes = m_elemIndexes;
263 
264       m_elemIndexes = new int[namespaceID + 20][][];
265 
266       System.arraycopy(indexes, 0, m_elemIndexes, 0, indexes.length);
267     }
268 
269     int[][] localNameIndex = m_elemIndexes[namespaceID];
270 
271     if (null == localNameIndex)
272     {
273       localNameIndex = new int[LocalNameID + 100][];
274       m_elemIndexes[namespaceID] = localNameIndex;
275     }
276     else if (localNameIndex.length <= LocalNameID)
277     {
278       int[][] indexes = localNameIndex;
279 
280       localNameIndex = new int[LocalNameID + 100][];
281 
282       System.arraycopy(indexes, 0, localNameIndex, 0, indexes.length);
283 
284       m_elemIndexes[namespaceID] = localNameIndex;
285     }
286 
287     int[] elemHandles = localNameIndex[LocalNameID];
288 
289     if (null == elemHandles)
290     {
291       elemHandles = new int[128];
292       localNameIndex[LocalNameID] = elemHandles;
293       elemHandles[0] = 1;
294     }
295     else if (elemHandles.length <= elemHandles[0] + 1)
296     {
297       int[] indexes = elemHandles;
298 
299       elemHandles = new int[elemHandles[0] + 1024];
300 
301       System.arraycopy(indexes, 0, elemHandles, 0, indexes.length);
302 
303       localNameIndex[LocalNameID] = elemHandles;
304     }
305   }
306 
307   /**
308    * Add a node to the element indexes. The node will not be added unless
309    * it's an element.
310    *
311    * @param expandedTypeID The expanded type ID of the node.
312    * @param identity The node identity index.
313    */
indexNode(int expandedTypeID, int identity)314   protected void indexNode(int expandedTypeID, int identity)
315   {
316 
317     ExpandedNameTable ent = m_expandedNameTable;
318     short type = ent.getType(expandedTypeID);
319 
320     if (DTM.ELEMENT_NODE == type)
321     {
322       int namespaceID = ent.getNamespaceID(expandedTypeID);
323       int localNameID = ent.getLocalNameID(expandedTypeID);
324 
325       ensureSizeOfIndex(namespaceID, localNameID);
326 
327       int[] index = m_elemIndexes[namespaceID][localNameID];
328 
329       index[index[0]] = identity;
330 
331       index[0]++;
332     }
333   }
334 
335   /**
336    * Find the first index that occurs in the list that is greater than or
337    * equal to the given value.
338    *
339    * @param list A list of integers.
340    * @param start The start index to begin the search.
341    * @param len The number of items to search.
342    * @param value Find the slot that has a value that is greater than or
343    * identical to this argument.
344    *
345    * @return The index in the list of the slot that is higher or identical
346    * to the identity argument, or -1 if no node is higher or equal.
347    */
findGTE(int[] list, int start, int len, int value)348   protected int findGTE(int[] list, int start, int len, int value)
349   {
350 
351     int low = start;
352     int high = start + (len - 1);
353     int end = high;
354 
355     while (low <= high)
356     {
357       int mid = (low + high) >>> 1;
358       int c = list[mid];
359 
360       if (c > value)
361         high = mid - 1;
362       else if (c < value)
363         low = mid + 1;
364       else
365         return mid;
366     }
367 
368     return (low <= end && list[low] > value) ? low : -1;
369   }
370 
371   /**
372    * Find the first matching element from the index at or after the
373    * given node.
374    *
375    * @param nsIndex The namespace index lookup.
376    * @param lnIndex The local name index lookup.
377    * @param firstPotential The first potential match that is worth looking at.
378    *
379    * @return The first node that is greater than or equal to the
380    *         firstPotential argument, or DTM.NOTPROCESSED if not found.
381    */
findElementFromIndex(int nsIndex, int lnIndex, int firstPotential)382   int findElementFromIndex(int nsIndex, int lnIndex, int firstPotential)
383   {
384 
385     int[][][] indexes = m_elemIndexes;
386 
387     if (null != indexes && nsIndex < indexes.length)
388     {
389       int[][] lnIndexs = indexes[nsIndex];
390 
391       if (null != lnIndexs && lnIndex < lnIndexs.length)
392       {
393         int[] elems = lnIndexs[lnIndex];
394 
395         if (null != elems)
396         {
397           int pos = findGTE(elems, 1, elems[0], firstPotential);
398 
399           if (pos > -1)
400           {
401             return elems[pos];
402           }
403         }
404       }
405     }
406 
407     return NOTPROCESSED;
408   }
409 
410   /**
411    * Get the next node identity value in the list, and call the iterator
412    * if it hasn't been added yet.
413    *
414    * @param identity The node identity (index).
415    * @return identity+1, or DTM.NULL.
416    */
getNextNodeIdentity(int identity)417   protected abstract int getNextNodeIdentity(int identity);
418 
419   /**
420    * This method should try and build one or more nodes in the table.
421    *
422    * @return The true if a next node is found or false if
423    *         there are no more nodes.
424    */
nextNode()425   protected abstract boolean nextNode();
426 
427   /**
428    * Get the number of nodes that have been added.
429    *
430    * @return the number of nodes that have been mapped.
431    */
getNumberOfNodes()432   protected abstract int getNumberOfNodes();
433 
434   /** Stateless axis traversers, lazely built. */
435   protected DTMAxisTraverser[] m_traversers;
436 
437 //    /**
438 //     * Ensure that the size of the information arrays can hold another entry
439 //     * at the given index.
440 //     *
441 //     * @param index On exit from this function, the information arrays sizes must be
442 //     * at least index+1.
443 //     */
444 //    protected void ensureSize(int index)
445 //    {
446 //        // We've cut over to Suballocated*Vector, which are self-sizing.
447 //    }
448 
449   /**
450    * Get the simple type ID for the given node identity.
451    *
452    * @param identity The node identity.
453    *
454    * @return The simple type ID, or DTM.NULL.
455    */
_type(int identity)456   protected short _type(int identity)
457   {
458 
459     int info = _exptype(identity);
460 
461     if (NULL != info)
462       return m_expandedNameTable.getType(info);
463     else
464       return NULL;
465   }
466 
467   /**
468    * Get the expanded type ID for the given node identity.
469    *
470    * @param identity The node identity.
471    *
472    * @return The expanded type ID, or DTM.NULL.
473    */
_exptype(int identity)474   protected int _exptype(int identity)
475   {
476         if (identity == DTM.NULL)
477         return NULL;
478     // Reorganized test and loop into single flow
479     // Tiny performance improvement, saves a few bytes of code, clearer.
480     // %OPT% Other internal getters could be treated simliarly
481     while (identity>=m_size)
482     {
483       if (!nextNode() && identity >= m_size)
484         return NULL;
485     }
486     return m_exptype.elementAt(identity);
487 
488   }
489 
490   /**
491    * Get the level in the tree for the given node identity.
492    *
493    * @param identity The node identity.
494    *
495    * @return The tree level, or DTM.NULL.
496    */
_level(int identity)497   protected int _level(int identity)
498   {
499     while (identity>=m_size)
500     {
501       boolean isMore = nextNode();
502       if (!isMore && identity >= m_size)
503         return NULL;
504     }
505 
506     int i=0;
507     while(NULL != (identity=_parent(identity)))
508       ++i;
509     return i;
510   }
511 
512   /**
513    * Get the first child for the given node identity.
514    *
515    * @param identity The node identity.
516    *
517    * @return The first child identity, or DTM.NULL.
518    */
_firstch(int identity)519   protected int _firstch(int identity)
520   {
521 
522     // Boiler-plate code for each of the _xxx functions, except for the array.
523     int info = (identity >= m_size) ? NOTPROCESSED : m_firstch.elementAt(identity);
524 
525     // Check to see if the information requested has been processed, and,
526     // if not, advance the iterator until we the information has been
527     // processed.
528     while (info == NOTPROCESSED)
529     {
530       boolean isMore = nextNode();
531 
532       if (identity >= m_size &&!isMore)
533         return NULL;
534       else
535       {
536         info = m_firstch.elementAt(identity);
537         if(info == NOTPROCESSED && !isMore)
538           return NULL;
539       }
540     }
541 
542     return info;
543   }
544 
545   /**
546    * Get the next sibling for the given node identity.
547    *
548    * @param identity The node identity.
549    *
550    * @return The next sibling identity, or DTM.NULL.
551    */
_nextsib(int identity)552   protected int _nextsib(int identity)
553   {
554     // Boiler-plate code for each of the _xxx functions, except for the array.
555     int info = (identity >= m_size) ? NOTPROCESSED : m_nextsib.elementAt(identity);
556 
557     // Check to see if the information requested has been processed, and,
558     // if not, advance the iterator until we the information has been
559     // processed.
560     while (info == NOTPROCESSED)
561     {
562       boolean isMore = nextNode();
563 
564       if (identity >= m_size &&!isMore)
565         return NULL;
566       else
567       {
568         info = m_nextsib.elementAt(identity);
569         if(info == NOTPROCESSED && !isMore)
570           return NULL;
571       }
572     }
573 
574     return info;
575   }
576 
577   /**
578    * Get the previous sibling for the given node identity.
579    *
580    * @param identity The node identity.
581    *
582    * @return The previous sibling identity, or DTM.NULL.
583    */
_prevsib(int identity)584   protected int _prevsib(int identity)
585   {
586 
587     if (identity < m_size)
588       return m_prevsib.elementAt(identity);
589 
590     // Check to see if the information requested has been processed, and,
591     // if not, advance the iterator until we the information has been
592     // processed.
593     while (true)
594     {
595       boolean isMore = nextNode();
596 
597       if (identity >= m_size && !isMore)
598         return NULL;
599       else if (identity < m_size)
600         return m_prevsib.elementAt(identity);
601     }
602   }
603 
604   /**
605    * Get the parent for the given node identity.
606    *
607    * @param identity The node identity.
608    *
609    * @return The parent identity, or DTM.NULL.
610    */
_parent(int identity)611   protected int _parent(int identity)
612   {
613 
614     if (identity < m_size)
615       return m_parent.elementAt(identity);
616 
617     // Check to see if the information requested has been processed, and,
618     // if not, advance the iterator until we the information has been
619     // processed.
620     while (true)
621     {
622       boolean isMore = nextNode();
623 
624       if (identity >= m_size && !isMore)
625         return NULL;
626       else if (identity < m_size)
627         return m_parent.elementAt(identity);
628     }
629   }
630 
631   /**
632    * Diagnostics function to dump the DTM.
633    */
dumpDTM(OutputStream os)634   public void dumpDTM(OutputStream os)
635   {
636     try
637     {
638       if(os==null)
639       {
640               File f = new File("DTMDump"+((Object)this).hashCode()+".txt");
641               System.err.println("Dumping... "+f.getAbsolutePath());
642               os=new FileOutputStream(f);
643       }
644       PrintStream ps = new PrintStream(os);
645 
646       while (nextNode()){}
647 
648       int nRecords = m_size;
649 
650       ps.println("Total nodes: " + nRecords);
651 
652       for (int index = 0; index < nRecords; ++index)
653       {
654         int i=makeNodeHandle(index);
655         ps.println("=========== index=" + index + " handle=" + i + " ===========");
656         ps.println("NodeName: " + getNodeName(i));
657         ps.println("NodeNameX: " + getNodeNameX(i));
658         ps.println("LocalName: " + getLocalName(i));
659         ps.println("NamespaceURI: " + getNamespaceURI(i));
660         ps.println("Prefix: " + getPrefix(i));
661 
662         int exTypeID = _exptype(index);
663 
664         ps.println("Expanded Type ID: "
665                            + Integer.toHexString(exTypeID));
666 
667         int type = _type(index);
668         String typestring;
669 
670         switch (type)
671         {
672         case DTM.ATTRIBUTE_NODE :
673           typestring = "ATTRIBUTE_NODE";
674           break;
675         case DTM.CDATA_SECTION_NODE :
676           typestring = "CDATA_SECTION_NODE";
677           break;
678         case DTM.COMMENT_NODE :
679           typestring = "COMMENT_NODE";
680           break;
681         case DTM.DOCUMENT_FRAGMENT_NODE :
682           typestring = "DOCUMENT_FRAGMENT_NODE";
683           break;
684         case DTM.DOCUMENT_NODE :
685           typestring = "DOCUMENT_NODE";
686           break;
687         case DTM.DOCUMENT_TYPE_NODE :
688           typestring = "DOCUMENT_NODE";
689           break;
690         case DTM.ELEMENT_NODE :
691           typestring = "ELEMENT_NODE";
692           break;
693         case DTM.ENTITY_NODE :
694           typestring = "ENTITY_NODE";
695           break;
696         case DTM.ENTITY_REFERENCE_NODE :
697           typestring = "ENTITY_REFERENCE_NODE";
698           break;
699         case DTM.NAMESPACE_NODE :
700           typestring = "NAMESPACE_NODE";
701           break;
702         case DTM.NOTATION_NODE :
703           typestring = "NOTATION_NODE";
704           break;
705         case DTM.NULL :
706           typestring = "NULL";
707           break;
708         case DTM.PROCESSING_INSTRUCTION_NODE :
709           typestring = "PROCESSING_INSTRUCTION_NODE";
710           break;
711         case DTM.TEXT_NODE :
712           typestring = "TEXT_NODE";
713           break;
714         default :
715           typestring = "Unknown!";
716           break;
717         }
718 
719         ps.println("Type: " + typestring);
720 
721         int firstChild = _firstch(index);
722 
723         if (DTM.NULL == firstChild)
724           ps.println("First child: DTM.NULL");
725         else if (NOTPROCESSED == firstChild)
726           ps.println("First child: NOTPROCESSED");
727         else
728           ps.println("First child: " + firstChild);
729 
730         if (m_prevsib != null)
731         {
732           int prevSibling = _prevsib(index);
733 
734           if (DTM.NULL == prevSibling)
735             ps.println("Prev sibling: DTM.NULL");
736           else if (NOTPROCESSED == prevSibling)
737             ps.println("Prev sibling: NOTPROCESSED");
738           else
739             ps.println("Prev sibling: " + prevSibling);
740         }
741 
742         int nextSibling = _nextsib(index);
743 
744         if (DTM.NULL == nextSibling)
745           ps.println("Next sibling: DTM.NULL");
746         else if (NOTPROCESSED == nextSibling)
747           ps.println("Next sibling: NOTPROCESSED");
748         else
749           ps.println("Next sibling: " + nextSibling);
750 
751         int parent = _parent(index);
752 
753         if (DTM.NULL == parent)
754           ps.println("Parent: DTM.NULL");
755         else if (NOTPROCESSED == parent)
756           ps.println("Parent: NOTPROCESSED");
757         else
758           ps.println("Parent: " + parent);
759 
760         int level = _level(index);
761 
762         ps.println("Level: " + level);
763         ps.println("Node Value: " + getNodeValue(i));
764         ps.println("String Value: " + getStringValue(i));
765       }
766     }
767     catch(IOException ioe)
768     {
769       ioe.printStackTrace(System.err);
770         throw new RuntimeException(ioe.getMessage());
771     }
772   }
773 
774   /**
775    * Diagnostics function to dump a single node.
776    *
777    * %REVIEW% KNOWN GLITCH: If you pass it a node index rather than a
778    * node handle, it works just fine... but the displayed identity
779    * number before the colon is different, which complicates comparing
780    * it with nodes printed the other way. We could always OR the DTM ID
781    * into the value, to suppress that distinction...
782    *
783    * %REVIEW% This might want to be moved up to DTMDefaultBase, or possibly
784    * DTM itself, since it's a useful diagnostic and uses only DTM's public
785    * APIs.
786    */
dumpNode(int nodeHandle)787   public String dumpNode(int nodeHandle)
788   {
789           if(nodeHandle==DTM.NULL)
790                   return "[null]";
791 
792         String typestring;
793         switch (getNodeType(nodeHandle))
794         {
795         case DTM.ATTRIBUTE_NODE :
796           typestring = "ATTR";
797           break;
798         case DTM.CDATA_SECTION_NODE :
799           typestring = "CDATA";
800           break;
801         case DTM.COMMENT_NODE :
802           typestring = "COMMENT";
803           break;
804         case DTM.DOCUMENT_FRAGMENT_NODE :
805           typestring = "DOC_FRAG";
806           break;
807         case DTM.DOCUMENT_NODE :
808           typestring = "DOC";
809           break;
810         case DTM.DOCUMENT_TYPE_NODE :
811           typestring = "DOC_TYPE";
812           break;
813         case DTM.ELEMENT_NODE :
814           typestring = "ELEMENT";
815           break;
816         case DTM.ENTITY_NODE :
817           typestring = "ENTITY";
818           break;
819         case DTM.ENTITY_REFERENCE_NODE :
820           typestring = "ENT_REF";
821           break;
822         case DTM.NAMESPACE_NODE :
823           typestring = "NAMESPACE";
824           break;
825         case DTM.NOTATION_NODE :
826           typestring = "NOTATION";
827           break;
828         case DTM.NULL :
829           typestring = "null";
830           break;
831         case DTM.PROCESSING_INSTRUCTION_NODE :
832           typestring = "PI";
833           break;
834         case DTM.TEXT_NODE :
835           typestring = "TEXT";
836           break;
837         default :
838           typestring = "Unknown!";
839           break;
840         }
841 
842       return "[" + nodeHandle + ": " + typestring +
843               "(0x" + Integer.toHexString(getExpandedTypeID(nodeHandle)) + ") " +
844               getNodeNameX(nodeHandle) + " {" + getNamespaceURI(nodeHandle) + "}" +
845               "=\"" + getNodeValue(nodeHandle) + "\"]";
846   }
847 
848   // ========= DTM Implementation Control Functions. ==============
849 
850   /**
851    * Set an implementation dependent feature.
852    * <p>
853    * %REVIEW% Do we really expect to set features on DTMs?
854    *
855    * @param featureId A feature URL.
856    * @param state true if this feature should be on, false otherwise.
857    */
setFeature(String featureId, boolean state)858   public void setFeature(String featureId, boolean state){}
859 
860   // ========= Document Navigation Functions =========
861 
862   /**
863    * Given a node handle, test if it has child nodes.
864    * <p> %REVIEW% This is obviously useful at the DOM layer, where it
865    * would permit testing this without having to create a proxy
866    * node. It's less useful in the DTM API, where
867    * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
868    * almost as self-evident. But it's a convenience, and eases porting
869    * of DOM code to DTM.  </p>
870    *
871    * @param nodeHandle int Handle of the node.
872    * @return int true if the given node has child nodes.
873    */
hasChildNodes(int nodeHandle)874   public boolean hasChildNodes(int nodeHandle)
875   {
876 
877     int identity = makeNodeIdentity(nodeHandle);
878     int firstChild = _firstch(identity);
879 
880     return firstChild != DTM.NULL;
881   }
882 
883   /** Given a node identity, return a node handle. If extended addressing
884    * has been used (multiple DTM IDs), we need to map the high bits of the
885    * identity into the proper DTM ID.
886    *
887    * This has been made FINAL to facilitate inlining, since we do not expect
888    * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
889    * really like doing so, and would love to have an excuse not to...)
890    *
891    * %REVIEW% Is it worth trying to specialcase small documents?
892    * %REVIEW% Should this be exposed at the package/public layers?
893    *
894    * @param nodeIdentity Internal offset to this node's records.
895    * @return NodeHandle (external representation of node)
896    * */
makeNodeHandle(int nodeIdentity)897   final public int makeNodeHandle(int nodeIdentity)
898   {
899     if(NULL==nodeIdentity) return NULL;
900 
901     if(JJK_DEBUG && nodeIdentity>DTMManager.IDENT_NODE_DEFAULT)
902       System.err.println("GONK! (only useful in limited situations)");
903 
904     return m_dtmIdent.elementAt(nodeIdentity >>> DTMManager.IDENT_DTM_NODE_BITS)
905       + (nodeIdentity & DTMManager.IDENT_NODE_DEFAULT) ;
906   }
907 
908   /** Given a node handle, return a node identity. If extended addressing
909    * has been used (multiple DTM IDs), we need to map the high bits of the
910    * identity into the proper DTM ID and thence find the proper offset
911    * to add to the low bits of the identity
912    *
913    * This has been made FINAL to facilitate inlining, since we do not expect
914    * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
915    * really like doing so, and would love to have an excuse not to...)
916    *
917    * %OPT% Performance is critical for this operation.
918    *
919    * %REVIEW% Should this be exposed at the package/public layers?
920    *
921    * @param nodeHandle (external representation of node)
922    * @return nodeIdentity Internal offset to this node's records.
923    * */
makeNodeIdentity(int nodeHandle)924   final public int makeNodeIdentity(int nodeHandle)
925   {
926     if(NULL==nodeHandle) return NULL;
927 
928     if(m_mgrDefault!=null)
929     {
930       // Optimization: use the DTMManagerDefault's fast DTMID-to-offsets
931       // table.  I'm not wild about this solution but this operation
932       // needs need extreme speed.
933 
934       int whichDTMindex=nodeHandle>>>DTMManager.IDENT_DTM_NODE_BITS;
935 
936       // %REVIEW% Wish I didn't have to perform the pre-test, but
937       // someone is apparently asking DTMs whether they contain nodes
938       // which really don't belong to them. That's probably a bug
939       // which should be fixed, but until it is:
940       if(m_mgrDefault.m_dtms[whichDTMindex]!=this)
941         return NULL;
942       else
943         return
944           m_mgrDefault.m_dtm_offsets[whichDTMindex]
945           | (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
946     }
947 
948     int whichDTMid=m_dtmIdent.indexOf(nodeHandle & DTMManager.IDENT_DTM_DEFAULT);
949     return (whichDTMid==NULL)
950       ? NULL
951       : (whichDTMid << DTMManager.IDENT_DTM_NODE_BITS)
952       + (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
953   }
954 
955 
956   /**
957    * Given a node handle, get the handle of the node's first child.
958    * If not yet resolved, waits for more nodes to be added to the document and
959    * tries again.
960    *
961    * @param nodeHandle int Handle of the node.
962    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
963    */
getFirstChild(int nodeHandle)964   public int getFirstChild(int nodeHandle)
965   {
966 
967     int identity = makeNodeIdentity(nodeHandle);
968     int firstChild = _firstch(identity);
969 
970     return makeNodeHandle(firstChild);
971   }
972 
973   /**
974    * Given a node handle, get the handle of the node's first child.
975    * If not yet resolved, waits for more nodes to be added to the document and
976    * tries again.
977    *
978    * @param nodeHandle int Handle of the node.
979    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
980    */
getTypedFirstChild(int nodeHandle, int nodeType)981   public int getTypedFirstChild(int nodeHandle, int nodeType)
982   {
983 
984     int firstChild, eType;
985     if (nodeType < DTM.NTYPES) {
986       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
987            firstChild != DTM.NULL;
988            firstChild = _nextsib(firstChild)) {
989         eType = _exptype(firstChild);
990         if (eType == nodeType
991                || (eType >= DTM.NTYPES
992                       && m_expandedNameTable.getType(eType) == nodeType)) {
993           return makeNodeHandle(firstChild);
994         }
995       }
996     } else {
997       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
998            firstChild != DTM.NULL;
999            firstChild = _nextsib(firstChild)) {
1000         if (_exptype(firstChild) == nodeType) {
1001           return makeNodeHandle(firstChild);
1002         }
1003       }
1004     }
1005     return DTM.NULL;
1006   }
1007 
1008   /**
1009    * Given a node handle, advance to its last child.
1010    * If not yet resolved, waits for more nodes to be added to the document and
1011    * tries again.
1012    *
1013    * @param nodeHandle int Handle of the node.
1014    * @return int Node-number of last child,
1015    * or DTM.NULL to indicate none exists.
1016    */
getLastChild(int nodeHandle)1017   public int getLastChild(int nodeHandle)
1018   {
1019 
1020     int identity = makeNodeIdentity(nodeHandle);
1021     int child = _firstch(identity);
1022     int lastChild = DTM.NULL;
1023 
1024     while (child != DTM.NULL)
1025     {
1026       lastChild = child;
1027       child = _nextsib(child);
1028     }
1029 
1030     return makeNodeHandle(lastChild);
1031   }
1032 
1033   /**
1034    * Retrieves an attribute node by by qualified name and namespace URI.
1035    *
1036    * @param nodeHandle int Handle of the node upon which to look up this attribute..
1037    * @param namespaceURI The namespace URI of the attribute to
1038    *   retrieve, or null.
1039    * @param name The local name of the attribute to
1040    *   retrieve.
1041    * @return The attribute node handle with the specified name (
1042    *   <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1043    *   attribute.
1044    */
getAttributeNode(int nodeHandle, String namespaceURI, String name)1045   public abstract int getAttributeNode(int nodeHandle, String namespaceURI,
1046                                        String name);
1047 
1048   /**
1049    * Given a node handle, get the index of the node's first attribute.
1050    *
1051    * @param nodeHandle int Handle of the node.
1052    * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1053    */
getFirstAttribute(int nodeHandle)1054   public int getFirstAttribute(int nodeHandle)
1055   {
1056     int nodeID = makeNodeIdentity(nodeHandle);
1057 
1058     return makeNodeHandle(getFirstAttributeIdentity(nodeID));
1059   }
1060 
1061   /**
1062    * Given a node identity, get the index of the node's first attribute.
1063    *
1064    * @param identity int identity of the node.
1065    * @return Identity of first attribute, or DTM.NULL to indicate none exists.
1066    */
getFirstAttributeIdentity(int identity)1067   protected int getFirstAttributeIdentity(int identity) {
1068     int type = _type(identity);
1069 
1070     if (DTM.ELEMENT_NODE == type)
1071     {
1072       // Assume that attributes and namespaces immediately follow the element.
1073       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1074       {
1075 
1076         // Assume this can not be null.
1077         type = _type(identity);
1078 
1079         if (type == DTM.ATTRIBUTE_NODE)
1080         {
1081           return identity;
1082         }
1083         else if (DTM.NAMESPACE_NODE != type)
1084         {
1085           break;
1086         }
1087       }
1088     }
1089 
1090     return DTM.NULL;
1091   }
1092 
1093   /**
1094    * Given a node handle and an expanded type ID, get the index of the node's
1095    * attribute of that type, if any.
1096    *
1097    * @param nodeHandle int Handle of the node.
1098    * @param attType int expanded type ID of the required attribute.
1099    * @return Handle of attribute of the required type, or DTM.NULL to indicate
1100    * none exists.
1101    */
getTypedAttribute(int nodeHandle, int attType)1102   protected int getTypedAttribute(int nodeHandle, int attType) {
1103     int type = getNodeType(nodeHandle);
1104     if (DTM.ELEMENT_NODE == type) {
1105       int identity = makeNodeIdentity(nodeHandle);
1106 
1107       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1108       {
1109         type = _type(identity);
1110 
1111         if (type == DTM.ATTRIBUTE_NODE)
1112         {
1113           if (_exptype(identity) == attType) return makeNodeHandle(identity);
1114         }
1115         else if (DTM.NAMESPACE_NODE != type)
1116         {
1117           break;
1118         }
1119       }
1120     }
1121 
1122     return DTM.NULL;
1123   }
1124 
1125   /**
1126    * Given a node handle, advance to its next sibling.
1127    * If not yet resolved, waits for more nodes to be added to the document and
1128    * tries again.
1129    * @param nodeHandle int Handle of the node.
1130    * @return int Node-number of next sibling,
1131    * or DTM.NULL to indicate none exists.
1132    */
getNextSibling(int nodeHandle)1133   public int getNextSibling(int nodeHandle)
1134   {
1135         if (nodeHandle == DTM.NULL)
1136         return DTM.NULL;
1137     return makeNodeHandle(_nextsib(makeNodeIdentity(nodeHandle)));
1138   }
1139 
1140   /**
1141    * Given a node handle, advance to its next sibling.
1142    * If not yet resolved, waits for more nodes to be added to the document and
1143    * tries again.
1144    * @param nodeHandle int Handle of the node.
1145    * @return int Node-number of next sibling,
1146    * or DTM.NULL to indicate none exists.
1147    */
getTypedNextSibling(int nodeHandle, int nodeType)1148   public int getTypedNextSibling(int nodeHandle, int nodeType)
1149   {
1150         if (nodeHandle == DTM.NULL)
1151         return DTM.NULL;
1152         int node = makeNodeIdentity(nodeHandle);
1153         int eType;
1154         while ((node = _nextsib(node)) != DTM.NULL &&
1155         ((eType = _exptype(node)) != nodeType &&
1156         m_expandedNameTable.getType(eType)!= nodeType));
1157         //_type(node) != nodeType));
1158 
1159     return (node == DTM.NULL ? DTM.NULL : makeNodeHandle(node));
1160   }
1161 
1162   /**
1163    * Given a node handle, find its preceeding sibling.
1164    * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1165    * relatively expensive.
1166    *
1167    * @param nodeHandle the id of the node.
1168    * @return int Node-number of the previous sib,
1169    * or DTM.NULL to indicate none exists.
1170    */
getPreviousSibling(int nodeHandle)1171   public int getPreviousSibling(int nodeHandle)
1172   {
1173     if (nodeHandle == DTM.NULL)
1174       return DTM.NULL;
1175 
1176     if (m_prevsib != null)
1177       return makeNodeHandle(_prevsib(makeNodeIdentity(nodeHandle)));
1178     else
1179     {
1180       // If the previous sibling array is not built, we get at
1181       // the previous sibling using the parent, firstch and
1182       // nextsib arrays.
1183       int nodeID = makeNodeIdentity(nodeHandle);
1184       int parent = _parent(nodeID);
1185       int node = _firstch(parent);
1186       int result = DTM.NULL;
1187       while (node != nodeID)
1188       {
1189         result = node;
1190         node = _nextsib(node);
1191       }
1192       return makeNodeHandle(result);
1193     }
1194   }
1195 
1196   /**
1197    * Given a node handle, advance to the next attribute.
1198    * If an attr, we advance to
1199    * the next attr on the same node.  If not an attribute, we return NULL.
1200    *
1201    * @param nodeHandle int Handle of the node.
1202    * @return int DTM node-number of the resolved attr,
1203    * or DTM.NULL to indicate none exists.
1204    */
getNextAttribute(int nodeHandle)1205   public int getNextAttribute(int nodeHandle) {
1206     int nodeID = makeNodeIdentity(nodeHandle);
1207 
1208     if (_type(nodeID) == DTM.ATTRIBUTE_NODE) {
1209       return makeNodeHandle(getNextAttributeIdentity(nodeID));
1210     }
1211 
1212     return DTM.NULL;
1213   }
1214 
1215   /**
1216    * Given a node identity for an attribute, advance to the next attribute.
1217    *
1218    * @param identity int identity of the attribute node.  This
1219    * <strong>must</strong> be an attribute node.
1220    *
1221    * @return int DTM node-identity of the resolved attr,
1222    * or DTM.NULL to indicate none exists.
1223    *
1224    */
getNextAttributeIdentity(int identity)1225   protected int getNextAttributeIdentity(int identity) {
1226     // Assume that attributes and namespace nodes immediately follow the element
1227     while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1228       int type = _type(identity);
1229 
1230       if (type == DTM.ATTRIBUTE_NODE) {
1231         return identity;
1232       } else if (type != DTM.NAMESPACE_NODE) {
1233         break;
1234       }
1235     }
1236 
1237     return DTM.NULL;
1238   }
1239 
1240 
1241   /** Build table of namespace declaration
1242    * locations during DTM construction. Table is aArrayList<>of
1243    * SuballocatedIntVectors containing the namespace node HANDLES declared at
1244    * that ID, plus an SuballocatedIntVector of the element node INDEXES at which
1245    * these declarations appeared.
1246    *
1247    * NOTE: Since this occurs during model build, nodes will be encountered
1248    * in doucment order and thus the table will be ordered by element,
1249    * permitting binary-search as a possible retrieval optimization.
1250    *
1251    * %REVIEW% Directly managed arrays rather than vectors?
1252    * %REVIEW% Handles or IDs? Given usage, I think handles.
1253    * */
declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex)1254   protected void declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex)
1255   {
1256     SuballocatedIntVector nsList=null;
1257     if(m_namespaceDeclSets==null)
1258       {
1259 
1260         // First
1261         m_namespaceDeclSetElements=new SuballocatedIntVector(32);
1262         m_namespaceDeclSetElements.addElement(elementNodeIndex);
1263         m_namespaceDeclSets=new Vector<>();
1264         nsList=new SuballocatedIntVector(32);
1265         m_namespaceDeclSets.add(nsList);
1266       }
1267     else
1268       {
1269         // Most recent. May be -1 (none) if DTM was pruned.
1270         // %OPT% Is there a lastElement() method? Should there be?
1271         int last=m_namespaceDeclSetElements.size()-1;
1272 
1273         if(last>=0 && elementNodeIndex==m_namespaceDeclSetElements.elementAt(last))
1274           {
1275             nsList=m_namespaceDeclSets.get(last);
1276           }
1277       }
1278     if(nsList==null)
1279       {
1280         m_namespaceDeclSetElements.addElement(elementNodeIndex);
1281 
1282         SuballocatedIntVector inherited =
1283                                 findNamespaceContext(_parent(elementNodeIndex));
1284 
1285         if (inherited!=null) {
1286             // %OPT% Count-down might be faster, but debuggability may
1287             // be better this way, and if we ever decide we want to
1288             // keep this ordered by expanded-type...
1289             int isize=inherited.size();
1290 
1291             // Base the size of a new namespace list on the
1292             // size of the inherited list - but within reason!
1293             nsList=new SuballocatedIntVector(Math.max(Math.min(isize+16,2048),
1294                                                       32));
1295 
1296             for(int i=0;i<isize;++i)
1297               {
1298                 nsList.addElement(inherited.elementAt(i));
1299               }
1300         } else {
1301             nsList=new SuballocatedIntVector(32);
1302         }
1303 
1304         m_namespaceDeclSets.add(nsList);
1305       }
1306 
1307     // Handle overwriting inherited.
1308     // %OPT% Keep sorted? (By expanded-name rather than by doc order...)
1309     // Downside: Would require insertElementAt if not found,
1310     // which has recopying costs. But these are generally short lists...
1311     int newEType=_exptype(namespaceNodeIndex);
1312 
1313     for(int i=nsList.size()-1;i>=0;--i)
1314       {
1315         if(newEType==getExpandedTypeID(nsList.elementAt(i)))
1316           {
1317             nsList.setElementAt(makeNodeHandle(namespaceNodeIndex),i);
1318             return;
1319           }
1320       }
1321     nsList.addElement(makeNodeHandle(namespaceNodeIndex));
1322   }
1323 
1324   /** Retrieve list of namespace declaration locations
1325      * active at this node. List is an SuballocatedIntVector whose
1326      * entries are the namespace node HANDLES declared at that ID.
1327      *
1328      * %REVIEW% Directly managed arrays rather than vectors?
1329      * %REVIEW% Handles or IDs? Given usage, I think handles.
1330      * */
findNamespaceContext(int elementNodeIndex)1331   protected SuballocatedIntVector findNamespaceContext(int elementNodeIndex)
1332   {
1333     if (null!=m_namespaceDeclSetElements)
1334       {
1335         // %OPT% Is binary-search really saving us a lot versus linear?
1336         // (... It may be, in large docs with many NS decls.)
1337         int wouldBeAt=findInSortedSuballocatedIntVector(m_namespaceDeclSetElements,
1338                                             elementNodeIndex);
1339         if(wouldBeAt>=0) // Found it
1340           return m_namespaceDeclSets.get(wouldBeAt);
1341         if(wouldBeAt == -1) // -1-wouldbeat == 0
1342           return null; // Not after anything; definitely not found
1343 
1344         // Not found, but we know where it should have been.
1345         // Search back until we find an ancestor or run out.
1346         wouldBeAt=-1-wouldBeAt;
1347 
1348         // Decrement wouldBeAt to find last possible ancestor
1349         int candidate=m_namespaceDeclSetElements.elementAt(-- wouldBeAt);
1350         int ancestor=_parent(elementNodeIndex);
1351 
1352         // Special case: if the candidate is before the given node, and
1353         // is in the earliest possible position in the document, it
1354         // must have the namespace declarations we're interested in.
1355         if (wouldBeAt == 0 && candidate < ancestor) {
1356           int rootHandle = getDocumentRoot(makeNodeHandle(elementNodeIndex));
1357           int rootID = makeNodeIdentity(rootHandle);
1358           int uppermostNSCandidateID;
1359 
1360           if (getNodeType(rootHandle) == DTM.DOCUMENT_NODE) {
1361             int ch = _firstch(rootID);
1362             uppermostNSCandidateID = (ch != DTM.NULL) ? ch : rootID;
1363           } else {
1364             uppermostNSCandidateID = rootID;
1365           }
1366 
1367           if (candidate == uppermostNSCandidateID) {
1368             return m_namespaceDeclSets.get(wouldBeAt);
1369           }
1370         }
1371 
1372         while(wouldBeAt>=0 && ancestor>0)
1373           {
1374             if (candidate==ancestor) {
1375                 // Found ancestor in list
1376                 return m_namespaceDeclSets.get(wouldBeAt);
1377             } else if (candidate<ancestor) {
1378                 // Too deep in tree
1379                 do {
1380                   ancestor=_parent(ancestor);
1381                 } while (candidate < ancestor);
1382             } else if(wouldBeAt > 0){
1383               // Too late in list
1384               candidate=m_namespaceDeclSetElements.elementAt(--wouldBeAt);
1385             }
1386             else
1387                 break;
1388           }
1389       }
1390 
1391     return null; // No namespaces known at this node
1392   }
1393 
1394   /**
1395      * Subroutine: Locate the specified node within
1396      * m_namespaceDeclSetElements, or the last element which
1397      * preceeds it in document order
1398      *
1399      * %REVIEW% Inlne this into findNamespaceContext? Create SortedSuballocatedIntVector type?
1400      *
1401      * @return If positive or zero, the index of the found item.
1402      * If negative, index of the point at which it would have appeared,
1403      * encoded as -1-index and hence reconvertable by subtracting
1404      * it from -1. (Encoding because I don't want to recompare the strings
1405      * but don't want to burn bytes on a datatype to hold a flagged value.)
1406      */
findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor)1407   protected int findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor)
1408   {
1409     // Binary search
1410     int i = 0;
1411     if(vector != null) {
1412       int first = 0;
1413       int last  = vector.size() - 1;
1414 
1415       while (first <= last) {
1416         i = (first + last) / 2;
1417         int test = lookfor-vector.elementAt(i);
1418         if(test == 0) {
1419           return i; // Name found
1420         }
1421         else if (test < 0) {
1422           last = i - 1; // looked too late
1423         }
1424         else {
1425           first = i + 1; // looked ot early
1426         }
1427       }
1428 
1429       if (first > i) {
1430         i = first; // Clean up at loop end
1431       }
1432     }
1433 
1434     return -1 - i; // not-found has to be encoded.
1435   }
1436 
1437 
1438   /**
1439    * Given a node handle, get the index of the node's first child.
1440    * If not yet resolved, waits for more nodes to be added to the document and
1441    * tries again
1442    *
1443    * @param nodeHandle handle to node, which should probably be an element
1444    *                   node, but need not be.
1445    *
1446    * @param inScope    true if all namespaces in scope should be returned,
1447    *                   false if only the namespace declarations should be
1448    *                   returned.
1449    * @return handle of first namespace, or DTM.NULL to indicate none exists.
1450    */
getFirstNamespaceNode(int nodeHandle, boolean inScope)1451   public int getFirstNamespaceNode(int nodeHandle, boolean inScope)
1452   {
1453         if(inScope)
1454         {
1455             int identity = makeNodeIdentity(nodeHandle);
1456             if (_type(identity) == DTM.ELEMENT_NODE)
1457             {
1458               SuballocatedIntVector nsContext=findNamespaceContext(identity);
1459               if(nsContext==null || nsContext.size()<1)
1460                 return NULL;
1461 
1462               return nsContext.elementAt(0);
1463             }
1464             else
1465               return NULL;
1466           }
1467         else
1468           {
1469             // Assume that attributes and namespaces immediately
1470             // follow the element.
1471             //
1472             // %OPT% Would things be faster if all NS nodes were built
1473             // before all Attr nodes? Some costs at build time for 2nd
1474             // pass...
1475             int identity = makeNodeIdentity(nodeHandle);
1476             if (_type(identity) == DTM.ELEMENT_NODE)
1477             {
1478               while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1479               {
1480                 int type = _type(identity);
1481                 if (type == DTM.NAMESPACE_NODE)
1482                     return makeNodeHandle(identity);
1483                 else if (DTM.ATTRIBUTE_NODE != type)
1484                     break;
1485               }
1486               return NULL;
1487             }
1488             else
1489               return NULL;
1490           }
1491   }
1492 
1493   /**
1494    * Given a namespace handle, advance to the next namespace.
1495    *
1496    * @param baseHandle handle to original node from where the first namespace
1497    * was relative to (needed to return nodes in document order).
1498    * @param nodeHandle A namespace handle for which we will find the next node.
1499    * @param inScope true if all namespaces that are in scope should be processed,
1500    * otherwise just process the nodes in the given element handle.
1501    * @return handle of next namespace, or DTM.NULL to indicate none exists.
1502    */
getNextNamespaceNode(int baseHandle, int nodeHandle, boolean inScope)1503   public int getNextNamespaceNode(int baseHandle, int nodeHandle,
1504                                   boolean inScope)
1505   {
1506         if(inScope)
1507           {
1508             //Since we've been given the base, try direct lookup
1509             //(could look from nodeHandle but this is at least one
1510             //comparison/get-parent faster)
1511             //SuballocatedIntVector nsContext=findNamespaceContext(nodeHandle & m_mask);
1512 
1513                 SuballocatedIntVector nsContext=findNamespaceContext(makeNodeIdentity(baseHandle));
1514 
1515             if(nsContext==null)
1516               return NULL;
1517             int i=1 + nsContext.indexOf(nodeHandle);
1518             if(i<=0 || i==nsContext.size())
1519               return NULL;
1520 
1521             return nsContext.elementAt(i);
1522           }
1523         else
1524           {
1525             // Assume that attributes and namespace nodes immediately follow the element.
1526             int identity = makeNodeIdentity(nodeHandle);
1527             while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1528               {
1529                 int type = _type(identity);
1530                 if (type == DTM.NAMESPACE_NODE)
1531                   {
1532                     return makeNodeHandle(identity);
1533                   }
1534                 else if (type != DTM.ATTRIBUTE_NODE)
1535                   {
1536                     break;
1537                   }
1538               }
1539           }
1540      return DTM.NULL;
1541   }
1542 
1543   /**
1544    * Given a node handle, find its parent node.
1545    *
1546    * @param nodeHandle the id of the node.
1547    * @return int Node-number of parent,
1548    * or DTM.NULL to indicate none exists.
1549    */
getParent(int nodeHandle)1550   public int getParent(int nodeHandle)
1551   {
1552 
1553     int identity = makeNodeIdentity(nodeHandle);
1554 
1555     if (identity > 0)
1556       return makeNodeHandle(_parent(identity));
1557     else
1558       return DTM.NULL;
1559   }
1560 
1561   /**
1562    * Find the Document node handle for the document currently under construction.
1563    * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle) instead;
1564    * this version of the operation is primarily intended for use during negotiation
1565    * with the DTM Manager.
1566    *
1567    *  @return int Node handle of document, which should always be valid.
1568    */
getDocument()1569   public int getDocument()
1570   {
1571     return m_dtmIdent.elementAt(0); // makeNodeHandle(0)
1572   }
1573 
1574   /**
1575    * Given a node handle, find the owning document node.  This has the exact
1576    * same semantics as the DOM Document method of the same name, in that if
1577    * the nodeHandle is a document node, it will return NULL.
1578    *
1579    * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1580    * binding layer. Included here as a convenience function and to
1581    * aid porting of DOM code to DTM.</p>
1582    *
1583    * @param nodeHandle the id of the node.
1584    * @return int Node handle of owning document, or -1 if the node was a Docment
1585    */
getOwnerDocument(int nodeHandle)1586   public int getOwnerDocument(int nodeHandle)
1587   {
1588 
1589     if (DTM.DOCUMENT_NODE == getNodeType(nodeHandle))
1590             return DTM.NULL;
1591 
1592     return getDocumentRoot(nodeHandle);
1593   }
1594 
1595   /**
1596    * Given a node handle, find the owning document node.  Unlike the DOM,
1597    * this considers the owningDocument of a Document to be itself.
1598    *
1599    * @param nodeHandle the id of the node.
1600    * @return int Node handle of owning document, or the nodeHandle if it is
1601    *             a Document.
1602    */
getDocumentRoot(int nodeHandle)1603   public int getDocumentRoot(int nodeHandle)
1604   {
1605     return getManager().getDTM(nodeHandle).getDocument();
1606   }
1607 
1608   /**
1609    * Get the string-value of a node as a String object
1610    * (see http://www.w3.org/TR/xpath#data-model
1611    * for the definition of a node's string-value).
1612    *
1613    * @param nodeHandle The node ID.
1614    *
1615    * @return A string object that represents the string-value of the given node.
1616    */
getStringValue(int nodeHandle)1617   public abstract XMLString getStringValue(int nodeHandle);
1618 
1619   /**
1620    * Get number of character array chunks in
1621    * the string-value of a node.
1622    * (see http://www.w3.org/TR/xpath#data-model
1623    * for the definition of a node's string-value).
1624    * Note that a single text node may have multiple text chunks.
1625    *
1626    * @param nodeHandle The node ID.
1627    *
1628    * @return number of character array chunks in
1629    *         the string-value of a node.
1630    */
getStringValueChunkCount(int nodeHandle)1631   public int getStringValueChunkCount(int nodeHandle)
1632   {
1633 
1634     // %TBD%
1635     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//("getStringValueChunkCount not yet supported!");
1636 
1637     return 0;
1638   }
1639 
1640   /**
1641    * Get a character array chunk in the string-value of a node.
1642    * (see http://www.w3.org/TR/xpath#data-model
1643    * for the definition of a node's string-value).
1644    * Note that a single text node may have multiple text chunks.
1645    *
1646    * @param nodeHandle The node ID.
1647    * @param chunkIndex Which chunk to get.
1648    * @param startAndLen An array of 2 where the start position and length of
1649    *                    the chunk will be returned.
1650    *
1651    * @return The character array reference where the chunk occurs.
1652    */
getStringValueChunk(int nodeHandle, int chunkIndex, int[] startAndLen)1653   public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1654                                     int[] startAndLen)
1655   {
1656 
1657     // %TBD%
1658     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"getStringValueChunk not yet supported!");
1659 
1660     return null;
1661   }
1662 
1663   /**
1664    * Given a node handle, return an ID that represents the node's expanded name.
1665    *
1666    * @param nodeHandle The handle to the node in question.
1667    *
1668    * @return the expanded-name id of the node.
1669    */
getExpandedTypeID(int nodeHandle)1670   public int getExpandedTypeID(int nodeHandle)
1671   {
1672     // %REVIEW% This _should_ only be null if someone asked the wrong DTM about the node...
1673     // which one would hope would never happen...
1674     int id=makeNodeIdentity(nodeHandle);
1675     if(id==NULL)
1676       return NULL;
1677     return _exptype(id);
1678   }
1679 
1680   /**
1681    * Given an expanded name, return an ID.  If the expanded-name does not
1682    * exist in the internal tables, the entry will be created, and the ID will
1683    * be returned.  Any additional nodes that are created that have this
1684    * expanded name will use this ID.
1685    *
1686    * @param type The simple type, i.e. one of ELEMENT, ATTRIBUTE, etc.
1687    *
1688    * @param namespace The namespace URI, which may be null, may be an empty
1689    *                  string (which will be the same as null), or may be a
1690    *                  namespace URI.
1691    * @param localName The local name string, which must be a valid
1692    *                  <a href="http://www.w3.org/TR/REC-xml-names/">NCName</a>.
1693    *
1694    * @return the expanded-name id of the node.
1695    */
getExpandedTypeID(String namespace, String localName, int type)1696   public int getExpandedTypeID(String namespace, String localName, int type)
1697   {
1698 
1699     ExpandedNameTable ent = m_expandedNameTable;
1700 
1701     return ent.getExpandedTypeID(namespace, localName, type);
1702   }
1703 
1704   /**
1705    * Given an expanded-name ID, return the local name part.
1706    *
1707    * @param expandedNameID an ID that represents an expanded-name.
1708    * @return String Local name of this node.
1709    */
getLocalNameFromExpandedNameID(int expandedNameID)1710   public String getLocalNameFromExpandedNameID(int expandedNameID)
1711   {
1712     return m_expandedNameTable.getLocalName(expandedNameID);
1713   }
1714 
1715   /**
1716    * Given an expanded-name ID, return the namespace URI part.
1717    *
1718    * @param expandedNameID an ID that represents an expanded-name.
1719    * @return String URI value of this node's namespace, or null if no
1720    * namespace was resolved.
1721    */
getNamespaceFromExpandedNameID(int expandedNameID)1722   public String getNamespaceFromExpandedNameID(int expandedNameID)
1723   {
1724     return m_expandedNameTable.getNamespace(expandedNameID);
1725   }
1726 
1727   /**
1728    * Returns the namespace type of a specific node
1729    * @param nodeHandle the id of the node.
1730    * @return the ID of the namespace.
1731    */
getNamespaceType(final int nodeHandle)1732   public int getNamespaceType(final int nodeHandle)
1733   {
1734 
1735     int identity = makeNodeIdentity(nodeHandle);
1736     int expandedNameID = _exptype(identity);
1737 
1738     return m_expandedNameTable.getNamespaceID(expandedNameID);
1739   }
1740 
1741   /**
1742    * Given a node handle, return its DOM-style node name. This will
1743    * include names such as #text or #document.
1744    *
1745    * @param nodeHandle the id of the node.
1746    * @return String Name of this node, which may be an empty string.
1747    * %REVIEW% Document when empty string is possible...
1748    * %REVIEW-COMMENT% It should never be empty, should it?
1749    */
getNodeName(int nodeHandle)1750   public abstract String getNodeName(int nodeHandle);
1751 
1752   /**
1753    * Given a node handle, return the XPath node name.  This should be
1754    * the name as described by the XPath data model, NOT the DOM-style
1755    * name.
1756    *
1757    * @param nodeHandle the id of the node.
1758    * @return String Name of this node, which may be an empty string.
1759    */
getNodeNameX(int nodeHandle)1760   public String getNodeNameX(int nodeHandle)
1761   {
1762 
1763     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMDefaultBase abstract method */
1764     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
1765 
1766     return null;
1767   }
1768 
1769   /**
1770    * Given a node handle, return its XPath-style localname.
1771    * (As defined in Namespaces, this is the portion of the name after any
1772    * colon character).
1773    *
1774    * @param nodeHandle the id of the node.
1775    * @return String Local name of this node.
1776    */
getLocalName(int nodeHandle)1777   public abstract String getLocalName(int nodeHandle);
1778 
1779   /**
1780    * Given a namespace handle, return the prefix that the namespace decl is
1781    * mapping.
1782    * Given a node handle, return the prefix used to map to the namespace.
1783    *
1784    * <p> %REVIEW% Are you sure you want "" for no prefix?  </p>
1785    * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb  </p>
1786    *
1787    * @param nodeHandle the id of the node.
1788    * @return String prefix of this node's name, or "" if no explicit
1789    * namespace prefix was given.
1790    */
getPrefix(int nodeHandle)1791   public abstract String getPrefix(int nodeHandle);
1792 
1793   /**
1794    * Given a node handle, return its DOM-style namespace URI
1795    * (As defined in Namespaces, this is the declared URI which this node's
1796    * prefix -- or default in lieu thereof -- was mapped to.)
1797    *
1798    * <p>%REVIEW% Null or ""? -sb</p>
1799    *
1800    * @param nodeHandle the id of the node.
1801    * @return String URI value of this node's namespace, or null if no
1802    * namespace was resolved.
1803    */
getNamespaceURI(int nodeHandle)1804   public abstract String getNamespaceURI(int nodeHandle);
1805 
1806   /**
1807    * Given a node handle, return its node value. This is mostly
1808    * as defined by the DOM, but may ignore some conveniences.
1809    * <p>
1810    *
1811    * @param nodeHandle The node id.
1812    * @return String Value of this node, or null if not
1813    * meaningful for this node type.
1814    */
getNodeValue(int nodeHandle)1815   public abstract String getNodeValue(int nodeHandle);
1816 
1817   /**
1818    * Given a node handle, return its DOM-style node type.
1819    * <p>
1820    * %REVIEW% Generally, returning short is false economy. Return int?
1821    * %REVIEW% Make assumption that node has already arrived.  Is OK?
1822    *
1823    * @param nodeHandle The node id.
1824    * @return int Node type, as per the DOM's Node._NODE constants.
1825    */
getNodeType(int nodeHandle)1826   public short getNodeType(int nodeHandle)
1827   {
1828         if (nodeHandle == DTM.NULL)
1829         return DTM.NULL;
1830     return m_expandedNameTable.getType(_exptype(makeNodeIdentity(nodeHandle)));
1831   }
1832 
1833   /**
1834    * Get the depth level of this node in the tree (equals 1 for
1835    * a parentless node).
1836    *
1837    * @param nodeHandle The node id.
1838    * @return the number of ancestors, plus one
1839    * @xsl.usage internal
1840    */
getLevel(int nodeHandle)1841   public short getLevel(int nodeHandle)
1842   {
1843     // Apparently, the axis walker stuff requires levels to count from 1.
1844     int identity = makeNodeIdentity(nodeHandle);
1845     return (short) (_level(identity) + 1);
1846   }
1847 
1848   /**
1849    * Get the identity of this node in the tree
1850    *
1851    * @param nodeHandle The node handle.
1852    * @return the node identity
1853    * @xsl.usage internal
1854    */
getNodeIdent(int nodeHandle)1855   public int getNodeIdent(int nodeHandle)
1856   {
1857     /*if (nodeHandle != DTM.NULL)
1858       return nodeHandle & m_mask;
1859     else
1860       return DTM.NULL;*/
1861 
1862       return makeNodeIdentity(nodeHandle);
1863   }
1864 
1865   /**
1866    * Get the handle of this node in the tree
1867    *
1868    * @param nodeId The node identity.
1869    * @return the node handle
1870    * @xsl.usage internal
1871    */
getNodeHandle(int nodeId)1872   public int getNodeHandle(int nodeId)
1873   {
1874     /*if (nodeId != DTM.NULL)
1875       return nodeId | m_dtmIdent;
1876     else
1877       return DTM.NULL;*/
1878 
1879       return makeNodeHandle(nodeId);
1880   }
1881 
1882   // ============== Document query functions ==============
1883 
1884   /**
1885    * Tests whether DTM DOM implementation implements a specific feature and
1886    * that feature is supported by this node.
1887    *
1888    * @param feature The name of the feature to test.
1889    * @param version This is the version number of the feature to test.
1890    *   If the version is not
1891    *   specified, supporting any version of the feature will cause the
1892    *   method to return <code>true</code>.
1893    * @return Returns <code>true</code> if the specified feature is
1894    *   supported on this node, <code>false</code> otherwise.
1895    */
isSupported(String feature, String version)1896   public boolean isSupported(String feature, String version)
1897   {
1898 
1899     // %TBD%
1900     return false;
1901   }
1902 
1903   /**
1904    * Return the base URI of the document entity. If it is not known
1905    * (because the document was parsed from a socket connection or from
1906    * standard input, for example), the value of this property is unknown.
1907    *
1908    * @return the document base URI String object or null if unknown.
1909    */
getDocumentBaseURI()1910   public String getDocumentBaseURI()
1911   {
1912     return m_documentBaseURI;
1913   }
1914 
1915   /**
1916    * Set the base URI of the document entity.
1917    *
1918    * @param baseURI the document base URI String object or null if unknown.
1919    */
setDocumentBaseURI(String baseURI)1920   public void setDocumentBaseURI(String baseURI)
1921   {
1922     m_documentBaseURI = baseURI;
1923   }
1924 
1925   /**
1926    * Return the system identifier of the document entity. If
1927    * it is not known, the value of this property is unknown.
1928    *
1929    * @param nodeHandle The node id, which can be any valid node handle.
1930    * @return the system identifier String object or null if unknown.
1931    */
getDocumentSystemIdentifier(int nodeHandle)1932   public String getDocumentSystemIdentifier(int nodeHandle)
1933   {
1934 
1935     // %REVIEW%  OK? -sb
1936     return m_documentBaseURI;
1937   }
1938 
1939   /**
1940    * Return the name of the character encoding scheme
1941    *        in which the document entity is expressed.
1942    *
1943    * @param nodeHandle The node id, which can be any valid node handle.
1944    * @return the document encoding String object.
1945    * @xsl.usage internal
1946    */
getDocumentEncoding(int nodeHandle)1947   public String getDocumentEncoding(int nodeHandle)
1948   {
1949 
1950     // %REVIEW%  OK??  -sb
1951     return "UTF-8";
1952   }
1953 
1954   /**
1955    * Return an indication of the standalone status of the document,
1956    *        either "yes" or "no". This property is derived from the optional
1957    *        standalone document declaration in the XML declaration at the
1958    *        beginning of the document entity, and has no value if there is no
1959    *        standalone document declaration.
1960    *
1961    * @param nodeHandle The node id, which can be any valid node handle.
1962    * @return the document standalone String object, either "yes", "no", or null.
1963    */
getDocumentStandalone(int nodeHandle)1964   public String getDocumentStandalone(int nodeHandle)
1965   {
1966     return null;
1967   }
1968 
1969   /**
1970    * Return a string representing the XML version of the document. This
1971    * property is derived from the XML declaration optionally present at the
1972    * beginning of the document entity, and has no value if there is no XML
1973    * declaration.
1974    *
1975    * @param documentHandle The document handle
1976    *
1977    * @return the document version String object.
1978    */
getDocumentVersion(int documentHandle)1979   public String getDocumentVersion(int documentHandle)
1980   {
1981     return null;
1982   }
1983 
1984   /**
1985    * Return an indication of
1986    * whether the processor has read the complete DTD. Its value is a
1987    * boolean. If it is false, then certain properties (indicated in their
1988    * descriptions below) may be unknown. If it is true, those properties
1989    * are never unknown.
1990    *
1991    * @return <code>true</code> if all declarations were processed;
1992    *         <code>false</code> otherwise.
1993    */
getDocumentAllDeclarationsProcessed()1994   public boolean getDocumentAllDeclarationsProcessed()
1995   {
1996 
1997     // %REVIEW% OK?
1998     return true;
1999   }
2000 
2001   /**
2002    *   A document type declaration information item has the following properties:
2003    *
2004    *     1. [system identifier] The system identifier of the external subset, if
2005    *        it exists. Otherwise this property has no value.
2006    *
2007    * @return the system identifier String object, or null if there is none.
2008    */
getDocumentTypeDeclarationSystemIdentifier()2009   public abstract String getDocumentTypeDeclarationSystemIdentifier();
2010 
2011   /**
2012    * Return the public identifier of the external subset,
2013    * normalized as described in 4.2.2 External Entities [XML]. If there is
2014    * no external subset or if it has no public identifier, this property
2015    * has no value.
2016    *
2017    * @return the public identifier String object, or null if there is none.
2018    */
getDocumentTypeDeclarationPublicIdentifier()2019   public abstract String getDocumentTypeDeclarationPublicIdentifier();
2020 
2021   /**
2022    * Returns the <code>Element</code> whose <code>ID</code> is given by
2023    * <code>elementId</code>. If no such element exists, returns
2024    * <code>DTM.NULL</code>. Behavior is not defined if more than one element
2025    * has this <code>ID</code>. Attributes (including those
2026    * with the name "ID") are not of type ID unless so defined by DTD/Schema
2027    * information available to the DTM implementation.
2028    * Implementations that do not know whether attributes are of type ID or
2029    * not are expected to return <code>DTM.NULL</code>.
2030    *
2031    * <p>%REVIEW% Presumably IDs are still scoped to a single document,
2032    * and this operation searches only within a single document, right?
2033    * Wouldn't want collisions between DTMs in the same process.</p>
2034    *
2035    * @param elementId The unique <code>id</code> value for an element.
2036    * @return The handle of the matching element.
2037    */
getElementById(String elementId)2038   public abstract int getElementById(String elementId);
2039 
2040   /**
2041    * The getUnparsedEntityURI function returns the URI of the unparsed
2042    * entity with the specified name in the same document as the context
2043    * node (see [3.3 Unparsed Entities]). It returns the empty string if
2044    * there is no such entity.
2045    * <p>
2046    * XML processors may choose to use the System Identifier (if one
2047    * is provided) to resolve the entity, rather than the URI in the
2048    * Public Identifier. The details are dependent on the processor, and
2049    * we would have to support some form of plug-in resolver to handle
2050    * this properly. Currently, we simply return the System Identifier if
2051    * present, and hope that it a usable URI or that our caller can
2052    * map it to one.
2053    * TODO: Resolve Public Identifiers... or consider changing function name.
2054    * <p>
2055    * If we find a relative URI
2056    * reference, XML expects it to be resolved in terms of the base URI
2057    * of the document. The DOM doesn't do that for us, and it isn't
2058    * entirely clear whether that should be done here; currently that's
2059    * pushed up to a higher level of our application. (Note that DOM Level
2060    * 1 didn't store the document's base URI.)
2061    * TODO: Consider resolving Relative URIs.
2062    * <p>
2063    * (The DOM's statement that "An XML processor may choose to
2064    * completely expand entities before the structure model is passed
2065    * to the DOM" refers only to parsed entities, not unparsed, and hence
2066    * doesn't affect this function.)
2067    *
2068    * @param name A string containing the Entity Name of the unparsed
2069    * entity.
2070    *
2071    * @return String containing the URI of the Unparsed Entity, or an
2072    * empty string if no such entity exists.
2073    */
getUnparsedEntityURI(String name)2074   public abstract String getUnparsedEntityURI(String name);
2075 
2076   // ============== Boolean methods ================
2077 
2078   /**
2079    * Return true if the xsl:strip-space or xsl:preserve-space was processed
2080    * during construction of the DTM document.
2081    *
2082    * @return true if this DTM supports prestripping.
2083    */
supportsPreStripping()2084   public boolean supportsPreStripping()
2085   {
2086     return true;
2087   }
2088 
2089   /**
2090    * Figure out whether nodeHandle2 should be considered as being later
2091    * in the document than nodeHandle1, in Document Order as defined
2092    * by the XPath model. This may not agree with the ordering defined
2093    * by other XML applications.
2094    * <p>
2095    * There are some cases where ordering isn't defined, and neither are
2096    * the results of this function -- though we'll generally return false.
2097    *
2098    * @param nodeHandle1 Node handle to perform position comparison on.
2099    * @param nodeHandle2 Second Node handle to perform position comparison on .
2100    *
2101    * @return true if node1 comes before node2, otherwise return false.
2102    * You can think of this as
2103    * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
2104    */
isNodeAfter(int nodeHandle1, int nodeHandle2)2105   public boolean isNodeAfter(int nodeHandle1, int nodeHandle2)
2106   {
2107                 // These return NULL if the node doesn't belong to this document.
2108     int index1 = makeNodeIdentity(nodeHandle1);
2109     int index2 = makeNodeIdentity(nodeHandle2);
2110 
2111     return index1!=NULL && index2!=NULL && index1 <= index2;
2112   }
2113 
2114   /**
2115    *     2. [element content whitespace] A boolean indicating whether the
2116    *        character is white space appearing within element content (see [XML],
2117    *        2.10 "White Space Handling"). Note that validating XML processors are
2118    *        required by XML 1.0 to provide this information. If there is no
2119    *        declaration for the containing element, this property has no value for
2120    *        white space characters. If no declaration has been read, but the [all
2121    *        declarations processed] property of the document information item is
2122    *        false (so there may be an unread declaration), then the value of this
2123    *        property is unknown for white space characters. It is always false for
2124    *        characters that are not white space.
2125    *
2126    * @param nodeHandle the node ID.
2127    * @return <code>true</code> if the character data is whitespace;
2128    *         <code>false</code> otherwise.
2129    */
isCharacterElementContentWhitespace(int nodeHandle)2130   public boolean isCharacterElementContentWhitespace(int nodeHandle)
2131   {
2132 
2133     // %TBD%
2134     return false;
2135   }
2136 
2137   /**
2138    *    10. [all declarations processed] This property is not strictly speaking
2139    *        part of the infoset of the document. Rather it is an indication of
2140    *        whether the processor has read the complete DTD. Its value is a
2141    *        boolean. If it is false, then certain properties (indicated in their
2142    *        descriptions below) may be unknown. If it is true, those properties
2143    *        are never unknown.
2144    *
2145    * @param documentHandle A node handle that must identify a document.
2146    * @return <code>true</code> if all declarations were processed;
2147    *         <code>false</code> otherwise.
2148    */
isDocumentAllDeclarationsProcessed(int documentHandle)2149   public boolean isDocumentAllDeclarationsProcessed(int documentHandle)
2150   {
2151     return true;
2152   }
2153 
2154   /**
2155    *     5. [specified] A flag indicating whether this attribute was actually
2156    *        specified in the start-tag of its element, or was defaulted from the
2157    *        DTD.
2158    *
2159    * @param attributeHandle The attribute handle in question.
2160    *
2161    * @return <code>true</code> if the attribute was specified;
2162    *         <code>false</code> if it was defaulted.
2163    */
isAttributeSpecified(int attributeHandle)2164   public abstract boolean isAttributeSpecified(int attributeHandle);
2165 
2166   // ========== Direct SAX Dispatch, for optimization purposes ========
2167 
2168   /**
2169    * Directly call the
2170    * characters method on the passed ContentHandler for the
2171    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2172    * for the definition of a node's string-value). Multiple calls to the
2173    * ContentHandler's characters methods may well occur for a single call to
2174    * this method.
2175    *
2176    * @param nodeHandle The node ID.
2177    * @param ch A non-null reference to a ContentHandler.
2178    * @param normalize true if the content should be normalized according to
2179    * the rules for the XPath
2180    * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
2181    * function.
2182    *
2183    * @throws org.xml.sax.SAXException
2184    */
dispatchCharactersEvents( int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)2185   public abstract void dispatchCharactersEvents(
2186     int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
2187       throws org.xml.sax.SAXException;
2188 
2189   /**
2190    * Directly create SAX parser events from a subtree.
2191    *
2192    * @param nodeHandle The node ID.
2193    * @param ch A non-null reference to a ContentHandler.
2194    *
2195    * @throws org.xml.sax.SAXException
2196    */
dispatchToEvents( int nodeHandle, org.xml.sax.ContentHandler ch)2197   public abstract void dispatchToEvents(
2198     int nodeHandle, org.xml.sax.ContentHandler ch)
2199       throws org.xml.sax.SAXException;
2200 
2201   /**
2202    * Return an DOM node for the given node.
2203    *
2204    * @param nodeHandle The node ID.
2205    *
2206    * @return A node representation of the DTM node.
2207    */
getNode(int nodeHandle)2208   public org.w3c.dom.Node getNode(int nodeHandle)
2209   {
2210     return new DTMNodeProxy(this, nodeHandle);
2211   }
2212 
2213   // ==== Construction methods (may not be supported by some implementations!) =====
2214 
2215   /**
2216    * Append a child to the end of the document. Please note that the node
2217    * is always cloned if it is owned by another document.
2218    *
2219    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2220    * Does it become the last child of the Document? Of the root element?</p>
2221    *
2222    * @param newChild Must be a valid new node handle.
2223    * @param clone true if the child should be cloned into the document.
2224    * @param cloneDepth if the clone argument is true, specifies that the
2225    *                   clone should include all it's children.
2226    */
appendChild(int newChild, boolean clone, boolean cloneDepth)2227   public void appendChild(int newChild, boolean clone, boolean cloneDepth)
2228   {
2229     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendChild not yet supported!");
2230   }
2231 
2232   /**
2233    * Append a text node child that will be constructed from a string,
2234    * to the end of the document.
2235    *
2236    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2237    * Does it become the last child of the Document? Of the root element?</p>
2238    *
2239    * @param str Non-null reverence to a string.
2240    */
appendTextChild(String str)2241   public void appendTextChild(String str)
2242   {
2243     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendTextChild not yet supported!");
2244   }
2245 
2246   /**
2247    * Simple error for asserts and the like.
2248    *
2249    * @param msg Error message to report.
2250    */
error(String msg)2251   protected void error(String msg)
2252   {
2253     throw new DTMException(msg);
2254   }
2255 
2256   /**
2257    * Find out whether or not to strip whispace nodes.
2258    *
2259    *
2260    * @return whether or not to strip whispace nodes.
2261    */
getShouldStripWhitespace()2262   protected boolean getShouldStripWhitespace()
2263   {
2264     return m_shouldStripWS;
2265   }
2266 
2267   /**
2268    * Set whether to strip whitespaces and push in current value of
2269    * m_shouldStripWS in m_shouldStripWhitespaceStack.
2270    *
2271    * @param shouldStrip Flag indicating whether to strip whitespace nodes
2272    */
pushShouldStripWhitespace(boolean shouldStrip)2273   protected void pushShouldStripWhitespace(boolean shouldStrip)
2274   {
2275 
2276     m_shouldStripWS = shouldStrip;
2277 
2278     if (null != m_shouldStripWhitespaceStack)
2279       m_shouldStripWhitespaceStack.push(shouldStrip);
2280   }
2281 
2282   /**
2283    * Set whether to strip whitespaces at this point by popping out
2284    * m_shouldStripWhitespaceStack.
2285    *
2286    */
popShouldStripWhitespace()2287   protected void popShouldStripWhitespace()
2288   {
2289     if (null != m_shouldStripWhitespaceStack)
2290       m_shouldStripWS = m_shouldStripWhitespaceStack.popAndTop();
2291   }
2292 
2293   /**
2294    * Set whether to strip whitespaces and set the top of the stack to
2295    * the current value of m_shouldStripWS.
2296    *
2297    *
2298    * @param shouldStrip Flag indicating whether to strip whitespace nodes
2299    */
setShouldStripWhitespace(boolean shouldStrip)2300   protected void setShouldStripWhitespace(boolean shouldStrip)
2301   {
2302 
2303     m_shouldStripWS = shouldStrip;
2304 
2305     if (null != m_shouldStripWhitespaceStack)
2306       m_shouldStripWhitespaceStack.setTop(shouldStrip);
2307   }
2308 
2309   /**
2310    * A dummy routine to satisify the abstract interface. If the DTM
2311    * implememtation that extends the default base requires notification
2312    * of registration, they can override this method.
2313    */
documentRegistration()2314    public void documentRegistration()
2315    {
2316    }
2317 
2318   /**
2319    * A dummy routine to satisify the abstract interface. If the DTM
2320    * implememtation that extends the default base requires notification
2321    * when the document is being released, they can override this method
2322    */
documentRelease()2323    public void documentRelease()
2324    {
2325    }
2326 
2327    /**
2328     * Migrate a DTM built with an old DTMManager to a new DTMManager.
2329     * After the migration, the new DTMManager will treat the DTM as
2330     * one that is built by itself.
2331     * This is used to support DTM sharing between multiple transformations.
2332     * @param mgr the DTMManager
2333     */
migrateTo(DTMManager mgr)2334    public void migrateTo(DTMManager mgr)
2335    {
2336      m_mgr = mgr;
2337      if(mgr instanceof DTMManagerDefault)
2338        m_mgrDefault=(DTMManagerDefault)mgr;
2339    }
2340 
2341          /** Query which DTMManager this DTM is currently being handled by.
2342           *
2343           * %REVEW% Should this become part of the base DTM API?
2344           *
2345           * @return a DTMManager, or null if this is a "stand-alone" DTM.
2346           */
getManager()2347          public DTMManager getManager()
2348          {
2349                  return m_mgr;
2350          }
2351 
2352          /** Query which DTMIDs this DTM is currently using within the DTMManager.
2353           *
2354           * %REVEW% Should this become part of the base DTM API?
2355           *
2356           * @return an IntVector, or null if this is a "stand-alone" DTM.
2357           */
getDTMIDs()2358          public SuballocatedIntVector getDTMIDs()
2359          {
2360                  if(m_mgr==null) return null;
2361                  return m_dtmIdent;
2362          }
2363 }
2364