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: DTMDocumentImpl.java 468653 2006-10-28 07:07:05Z minchau $
20 */
21package org.apache.xml.dtm.ref;
22
23import javax.xml.transform.SourceLocator;
24
25import org.apache.xml.dtm.DTM;
26import org.apache.xml.dtm.DTMAxisIterator;
27import org.apache.xml.dtm.DTMAxisTraverser;
28import org.apache.xml.dtm.DTMManager;
29import org.apache.xml.dtm.DTMWSFilter;
30import org.apache.xml.utils.FastStringBuffer;
31import org.apache.xml.utils.XMLString;
32import org.apache.xml.utils.XMLStringFactory;
33
34import org.xml.sax.Attributes;
35import org.xml.sax.ContentHandler;
36import org.xml.sax.Locator;
37import org.xml.sax.ext.LexicalHandler;
38
39/**
40 * This is the implementation of the DTM document interface.  It receives
41 * requests from an XML content handler similar to that of an XML DOM or SAX parser
42 * to store information from the xml document in an array based
43 * dtm table structure.  This informtion is used later for document navigation,
44 * query, and SAX event dispatch functions. The DTM can also be used directly as a
45 * document composition model for an application.  The requests received are:
46 * <ul>
47 * <li>initiating DTM to set the doc handle</li>
48 * <li>resetting DTM for data structure reuse</li>
49 * <li>hinting the end of document to adjust the end of data structure pointers</li>
50 * <li>createnodes (element, comment, text, attribute, ....)</li>
51 * <li>hinting the end of an element to patch parent and siblings<li>
52 * <li>setting application provided symbol name stringpool data structures</li>
53 * </ul>
54 * <p>State: In progress!!</p>
55 *
56 * %REVIEW% I _think_ the SAX convention is that "no namespace" is expressed
57 * as "" rather than as null (which is the DOM's convention). What should
58 * DTM expect? What should it do with the other?
59 *
60 * <p>Origin: the implemention is a composite logic based on the DTM of XalanJ1 and
61 *     DocImpl, DocumentImpl, ElementImpl, TextImpl, etc. of XalanJ2</p>
62 */
63public class DTMDocumentImpl
64implements DTM, org.xml.sax.ContentHandler, org.xml.sax.ext.LexicalHandler
65{
66
67        // Number of lower bits used to represent node index.
68        protected static final byte DOCHANDLE_SHIFT = 22;
69        // Masks the lower order of node handle.
70        // Same as {@link DTMConstructor.IDENT_NODE_DEFAULT}
71        protected static final int NODEHANDLE_MASK = (1 << (DOCHANDLE_SHIFT + 1)) - 1;
72        // Masks the higher order Document handle
73        // Same as {@link DTMConstructor.IDENT_DOC_DEFAULT}
74        protected static final int DOCHANDLE_MASK = -1 - NODEHANDLE_MASK;
75
76        int m_docHandle = NULL;		 // masked document handle for this dtm document
77        int m_docElement = NULL;	 // nodeHandle to the root of the actual dtm doc content
78
79        // Context for parse-and-append operations
80        int currentParent = 0;			// current parent - default is document root
81        int previousSibling = 0;		// previous sibling - no previous sibling
82        protected int m_currentNode = -1;		// current node
83
84        // The tree under construction can itself be used as
85        // the element stack, so m_elemStack isn't needed.
86        //protected Stack m_elemStack = new Stack();	 // element stack
87
88        private boolean previousSiblingWasParent = false;
89        // Local cache for record-at-a-time fetch
90        int gotslot[] = new int[4];
91
92        // endDocument recieved?
93        private boolean done = false;
94        boolean m_isError = false;
95
96        private final boolean DEBUG = false;
97
98        /** The document base URI. */
99        protected String m_documentBaseURI;
100
101  /** If we're building the model incrementally on demand, we need to
102   * be able to tell the source when to send us more data.
103   *
104   * Note that if this has not been set, and you attempt to read ahead
105   * of the current build point, we'll probably throw a null-pointer
106   * exception. We could try to wait-and-retry instead, as a very poor
107   * fallback, but that has all the known problems with multithreading
108   * on multiprocessors and we Don't Want to Go There.
109   *
110   * @see setIncrementalSAXSource
111   */
112  private IncrementalSAXSource m_incrSAXSource=null;
113
114
115        // ========= DTM data structure declarations. ==============
116
117        // nodes array: integer array blocks to hold the first level reference of the nodes,
118        // each reference slot is addressed by a nodeHandle index value.
119        // Assumes indices are not larger than {@link NODEHANDLE_MASK}
120        // ({@link DOCHANDLE_SHIFT} bits).
121        ChunkedIntArray nodes = new ChunkedIntArray(4);
122
123        // text/comment table: string buffer to hold the text string values of the document,
124        // each of which is addressed by the absolute offset and length in the buffer
125        private FastStringBuffer m_char = new FastStringBuffer();
126        // Start of string currently being accumulated into m_char;
127        // needed because the string may be appended in several chunks.
128        private int m_char_current_start=0;
129
130        // %TBD% INITIALIZATION/STARTUP ISSUES
131        // -- Should we really be creating these, or should they be
132        // passed in from outside? Scott want to be able to share
133        // pools across multiple documents, so setting them here is
134        // probably not the right default.
135        private DTMStringPool m_localNames = new DTMStringPool();
136        private DTMStringPool m_nsNames = new DTMStringPool();
137        private DTMStringPool m_prefixNames = new DTMStringPool();
138
139        // %TBD% If we use the current ExpandedNameTable mapper, it
140        // needs to be bound to the NS and local name pools. Which
141        // means it needs to attach to them AFTER we've resolved their
142        // startup. Or it needs to attach to this document and
143        // retrieve them each time. Or this needs to be
144        // an interface _implemented_ by this class... which might be simplest!
145        private ExpandedNameTable m_expandedNames=
146                new ExpandedNameTable();
147
148        private XMLStringFactory m_xsf;
149
150
151        /**
152         * Construct a DTM.
153         *
154         * @param documentNumber the ID number assigned to this document.
155         * It will be shifted up into the high bits and returned as part of
156         * all node ID numbers, so those IDs indicate which document they
157         * came from as well as a location within the document. It is the
158         * DTMManager's responsibility to assign a unique number to each
159         * document.
160         */
161        public DTMDocumentImpl(DTMManager mgr, int documentNumber,
162                               DTMWSFilter whiteSpaceFilter,
163                               XMLStringFactory xstringfactory){
164                initDocument(documentNumber);	 // clear nodes and document handle
165                m_xsf = xstringfactory;
166        }
167
168  /** Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
169   * that have not yet been built, we will ask this object to send us more
170   * events, and it will manage interactions with its data sources.
171   *
172   * Note that we do not actually build the IncrementalSAXSource, since we don't
173   * know what source it's reading from, what thread that source will run in,
174   * or when it will run.
175   *
176   * @param source The IncrementalSAXSource that we want to recieve events from
177   * on demand.
178   */
179  public void setIncrementalSAXSource(IncrementalSAXSource source)
180  {
181    m_incrSAXSource=source;
182
183    // Establish SAX-stream link so we can receive the requested data
184    source.setContentHandler(this);
185    source.setLexicalHandler(this);
186
187    // Are the following really needed? IncrementalSAXSource doesn't yet
188    // support them, and they're mostly no-ops here...
189    //source.setErrorHandler(this);
190    //source.setDTDHandler(this);
191    //source.setDeclHandler(this);
192  }
193
194        /**
195         * Wrapper for ChunkedIntArray.append, to automatically update the
196         * previous sibling's "next" reference (if necessary) and periodically
197         * wake a reader who may have encountered incomplete data and entered
198         * a wait state.
199         * @param w0 int As in ChunkedIntArray.append
200         * @param w1 int As in ChunkedIntArray.append
201         * @param w2 int As in ChunkedIntArray.append
202         * @param w3 int As in ChunkedIntArray.append
203         * @return int As in ChunkedIntArray.append
204         * @see ChunkedIntArray.append
205         */
206        private final int appendNode(int w0, int w1, int w2, int w3)
207        {
208                // A decent compiler may inline this.
209                int slotnumber = nodes.appendSlot(w0, w1, w2, w3);
210
211                if (DEBUG) System.out.println(slotnumber+": "+w0+" "+w1+" "+w2+" "+w3);
212
213                if (previousSiblingWasParent)
214                        nodes.writeEntry(previousSibling,2,slotnumber);
215
216                previousSiblingWasParent = false;	// Set the default; endElement overrides
217
218                return slotnumber;
219        }
220
221        // ========= DTM Implementation Control Functions. ==============
222
223        /**
224         * Set an implementation dependent feature.
225         * <p>
226         * %REVIEW% Do we really expect to set features on DTMs?
227         *
228         * @param featureId A feature URL.
229         * @param state true if this feature should be on, false otherwise.
230         */
231        public void setFeature(String featureId, boolean state) {};
232
233        /**
234         * Set a reference pointer to the element name symbol table.
235         * %REVIEW% Should this really be Public? Changing it while
236         * DTM is in use would be a disaster.
237         *
238         * @param poolRef DTMStringPool reference to an instance of table.
239         */
240        public void setLocalNameTable(DTMStringPool poolRef) {
241                m_localNames = poolRef;
242        }
243
244        /**
245         * Get a reference pointer to the element name symbol table.
246         *
247         * @return DTMStringPool reference to an instance of table.
248         */
249        public DTMStringPool getLocalNameTable() {
250                 return m_localNames;
251         }
252
253        /**
254         * Set a reference pointer to the namespace URI symbol table.
255         * %REVIEW% Should this really be Public? Changing it while
256         * DTM is in use would be a disaster.
257         *
258         * @param poolRef DTMStringPool reference to an instance of table.
259         */
260        public void setNsNameTable(DTMStringPool poolRef) {
261                m_nsNames = poolRef;
262        }
263
264        /**
265         * Get a reference pointer to the namespace URI symbol table.
266         *
267         * @return DTMStringPool reference to an instance of table.
268         */
269        public DTMStringPool getNsNameTable() {
270                 return m_nsNames;
271         }
272
273        /**
274         * Set a reference pointer to the prefix name symbol table.
275         * %REVIEW% Should this really be Public? Changing it while
276         * DTM is in use would be a disaster.
277         *
278         * @param poolRef DTMStringPool reference to an instance of table.
279         */
280        public void setPrefixNameTable(DTMStringPool poolRef) {
281                m_prefixNames = poolRef;
282        }
283
284        /**
285         * Get a reference pointer to the prefix name symbol table.
286         *
287         * @return DTMStringPool reference to an instance of table.
288         */
289        public DTMStringPool getPrefixNameTable() {
290                return m_prefixNames;
291        }
292
293         /**
294          * Set a reference pointer to the content-text repository
295          *
296          * @param buffer FastStringBuffer reference to an instance of
297          * buffer
298          */
299         void setContentBuffer(FastStringBuffer buffer) {
300                 m_char = buffer;
301         }
302
303         /**
304          * Get a reference pointer to the content-text repository
305          *
306          * @return FastStringBuffer reference to an instance of buffer
307          */
308         FastStringBuffer getContentBuffer() {
309                 return m_char;
310         }
311
312  /** getContentHandler returns "our SAX builder" -- the thing that
313   * someone else should send SAX events to in order to extend this
314   * DTM model.
315   *
316   * @return null if this model doesn't respond to SAX events,
317   * "this" if the DTM object has a built-in SAX ContentHandler,
318   * the IncrementalSAXSource if we're bound to one and should receive
319   * the SAX stream via it for incremental build purposes...
320   * */
321  public org.xml.sax.ContentHandler getContentHandler()
322  {
323    if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
324      return (ContentHandler) m_incrSAXSource;
325    else
326      return this;
327  }
328
329  /**
330   * Return this DTM's lexical handler.
331   *
332   * %REVIEW% Should this return null if constrution already done/begun?
333   *
334   * @return null if this model doesn't respond to lexical SAX events,
335   * "this" if the DTM object has a built-in SAX ContentHandler,
336   * the IncrementalSAXSource if we're bound to one and should receive
337   * the SAX stream via it for incremental build purposes...
338   */
339  public LexicalHandler getLexicalHandler()
340  {
341
342    if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
343      return (LexicalHandler) m_incrSAXSource;
344    else
345      return this;
346  }
347
348  /**
349   * Return this DTM's EntityResolver.
350   *
351   * @return null if this model doesn't respond to SAX entity ref events.
352   */
353  public org.xml.sax.EntityResolver getEntityResolver()
354  {
355
356    return null;
357  }
358
359  /**
360   * Return this DTM's DTDHandler.
361   *
362   * @return null if this model doesn't respond to SAX dtd events.
363   */
364  public org.xml.sax.DTDHandler getDTDHandler()
365  {
366
367    return null;
368  }
369
370  /**
371   * Return this DTM's ErrorHandler.
372   *
373   * @return null if this model doesn't respond to SAX error events.
374   */
375  public org.xml.sax.ErrorHandler getErrorHandler()
376  {
377
378    return null;
379  }
380
381  /**
382   * Return this DTM's DeclHandler.
383   *
384   * @return null if this model doesn't respond to SAX Decl events.
385   */
386  public org.xml.sax.ext.DeclHandler getDeclHandler()
387  {
388
389    return null;
390  }
391
392  /** @return true iff we're building this model incrementally (eg
393   * we're partnered with a IncrementalSAXSource) and thus require that the
394   * transformation and the parse run simultaneously. Guidance to the
395   * DTMManager.
396   * */
397  public boolean needsTwoThreads()
398  {
399    return null!=m_incrSAXSource;
400  }
401
402  //================================================================
403  // ========= SAX2 ContentHandler methods =========
404  // Accept SAX events, use them to build/extend the DTM tree.
405  // Replaces the deprecated DocumentHandler interface.
406
407  public void characters(char[] ch, int start, int length)
408       throws org.xml.sax.SAXException
409  {
410    // Actually creating the text node is handled by
411    // processAccumulatedText(); here we just accumulate the
412    // characters into the buffer.
413    m_char.append(ch,start,length);
414  }
415
416  // Flush string accumulation into a text node
417  private void processAccumulatedText()
418  {
419    int len=m_char.length();
420    if(len!=m_char_current_start)
421      {
422        // The FastStringBuffer has been previously agreed upon
423        appendTextChild(m_char_current_start,len-m_char_current_start);
424        m_char_current_start=len;
425      }
426  }
427  public void endDocument()
428       throws org.xml.sax.SAXException
429  {
430    // May need to tell the low-level builder code to pop up a level.
431    // There _should't_ be any significant pending text at this point.
432    appendEndDocument();
433  }
434  public void endElement(java.lang.String namespaceURI, java.lang.String localName,
435      java.lang.String qName)
436       throws org.xml.sax.SAXException
437  {
438    processAccumulatedText();
439    // No args but we do need to tell the low-level builder code to
440    // pop up a level.
441    appendEndElement();
442  }
443  public void endPrefixMapping(java.lang.String prefix)
444       throws org.xml.sax.SAXException
445  {
446    // No-op
447  }
448  public void ignorableWhitespace(char[] ch, int start, int length)
449       throws org.xml.sax.SAXException
450  {
451    // %TBD% I believe ignorable text isn't part of the DTM model...?
452  }
453  public void processingInstruction(java.lang.String target, java.lang.String data)
454       throws org.xml.sax.SAXException
455  {
456    processAccumulatedText();
457    // %TBD% Which pools do target and data go into?
458  }
459  public void setDocumentLocator(Locator locator)
460  {
461    // No-op for DTM
462  }
463  public void skippedEntity(java.lang.String name)
464       throws org.xml.sax.SAXException
465  {
466    processAccumulatedText();
467    //%TBD%
468  }
469  public void startDocument()
470       throws org.xml.sax.SAXException
471  {
472    appendStartDocument();
473  }
474  public void startElement(java.lang.String namespaceURI, java.lang.String localName,
475      java.lang.String qName, Attributes atts)
476       throws org.xml.sax.SAXException
477  {
478    processAccumulatedText();
479
480    // %TBD% Split prefix off qname
481    String prefix=null;
482    int colon=qName.indexOf(':');
483    if(colon>0)
484      prefix=qName.substring(0,colon);
485
486    // %TBD% Where do we pool expandedName, or is it just the union, or...
487    /**/System.out.println("Prefix="+prefix+" index="+m_prefixNames.stringToIndex(prefix));
488    appendStartElement(m_nsNames.stringToIndex(namespaceURI),
489                     m_localNames.stringToIndex(localName),
490                     m_prefixNames.stringToIndex(prefix)); /////// %TBD%
491
492    // %TBD% I'm assuming that DTM will require resequencing of
493    // NS decls before other attrs, hence two passes are taken.
494    // %TBD% Is there an easier way to test for NSDecl?
495    int nAtts=(atts==null) ? 0 : atts.getLength();
496    // %TBD% Countdown is more efficient if nobody cares about sequence.
497    for(int i=nAtts-1;i>=0;--i)
498      {
499        qName=atts.getQName(i);
500        if(qName.startsWith("xmlns:") || "xmlns".equals(qName))
501          {
502            prefix=null;
503            colon=qName.indexOf(':');
504            if(colon>0)
505              {
506                prefix=qName.substring(0,colon);
507              }
508            else
509              {
510                // %REVEIW% Null or ""?
511                prefix=null; // Default prefix
512              }
513
514
515            appendNSDeclaration(
516                                    m_prefixNames.stringToIndex(prefix),
517                                    m_nsNames.stringToIndex(atts.getValue(i)),
518                                    atts.getType(i).equalsIgnoreCase("ID"));
519          }
520      }
521
522    for(int i=nAtts-1;i>=0;--i)
523      {
524        qName=atts.getQName(i);
525        if(!(qName.startsWith("xmlns:") || "xmlns".equals(qName)))
526          {
527            // %TBD% I hate having to extract the prefix into a new
528            // string when we may never use it. Consider pooling whole
529            // qNames, which are already strings?
530            prefix=null;
531            colon=qName.indexOf(':');
532            if(colon>0)
533              {
534                prefix=qName.substring(0,colon);
535                localName=qName.substring(colon+1);
536              }
537            else
538              {
539                prefix=""; // Default prefix
540                localName=qName;
541              }
542
543
544            m_char.append(atts.getValue(i)); // Single-string value
545            int contentEnd=m_char.length();
546
547            if(!("xmlns".equals(prefix) || "xmlns".equals(qName)))
548              appendAttribute(m_nsNames.stringToIndex(atts.getURI(i)),
549                                  m_localNames.stringToIndex(localName),
550                                  m_prefixNames.stringToIndex(prefix),
551                                  atts.getType(i).equalsIgnoreCase("ID"),
552                                  m_char_current_start, contentEnd-m_char_current_start);
553            m_char_current_start=contentEnd;
554          }
555      }
556  }
557  public void startPrefixMapping(java.lang.String prefix, java.lang.String uri)
558       throws org.xml.sax.SAXException
559  {
560    // No-op in DTM, handled during element/attr processing?
561  }
562
563  //
564  // LexicalHandler support. Not all SAX2 parsers support these events
565  // but we may want to pass them through when they exist...
566  //
567  public void comment(char[] ch, int start, int length)
568       throws org.xml.sax.SAXException
569  {
570    processAccumulatedText();
571
572    m_char.append(ch,start,length); // Single-string value
573    appendComment(m_char_current_start,length);
574    m_char_current_start+=length;
575  }
576  public void endCDATA()
577       throws org.xml.sax.SAXException
578  {
579    // No-op in DTM
580  }
581  public void endDTD()
582       throws org.xml.sax.SAXException
583  {
584    // No-op in DTM
585  }
586  public void endEntity(java.lang.String name)
587       throws org.xml.sax.SAXException
588  {
589    // No-op in DTM
590  }
591  public void startCDATA()
592       throws org.xml.sax.SAXException
593  {
594    // No-op in DTM
595  }
596  public void startDTD(java.lang.String name, java.lang.String publicId,
597      java.lang.String systemId)
598       throws org.xml.sax.SAXException
599  {
600    // No-op in DTM
601  }
602  public void startEntity(java.lang.String name)
603       throws org.xml.sax.SAXException
604  {
605    // No-op in DTM
606  }
607
608
609  //================================================================
610  // ========= Document Handler Functions =========
611  // %REVIEW% jjk -- DocumentHandler is  SAX Level 1, and deprecated....
612  // and this wasn't a fully compliant or declared implementation of that API
613  // in any case. Phase out in favor of SAX2 ContentHandler/LexicalHandler
614
615        /**
616         * Reset a dtm document to its initial (empty) state.
617         *
618         * The DTMManager will invoke this method when the dtm is created.
619         *
620         * @param documentNumber the handle for the DTM document.
621         */
622        final void initDocument(int documentNumber)
623        {
624                // save masked DTM document handle
625                m_docHandle = documentNumber<<DOCHANDLE_SHIFT;
626
627                // Initialize the doc -- no parent, no next-sib
628                nodes.writeSlot(0,DOCUMENT_NODE,-1,-1,0);
629                // wait for the first startElement to create the doc root node
630                done = false;
631        }
632
633// 	/**
634// 	 * Receive hint of the end of a document.
635// 	 *
636// 	 * <p>The content handler will invoke this method only once, and it will
637// 	 * be the last method invoked during the parse.  The handler shall not
638// 	 * not invoke this method until it has either abandoned parsing
639// 	 * (because of an unrecoverable error) or reached the end of
640// 	 * input.</p>
641// 	 */
642// 	public void documentEnd()
643// 	{
644// 		done = true;
645// 		// %TBD% may need to notice the last slot number and slot count to avoid
646// 		// residual data from provious use of this DTM
647// 	}
648
649// 	/**
650// 	 * Receive notification of the beginning of a document.
651// 	 *
652// 	 * <p>The SAX parser will invoke this method only once, before any
653// 	 * other methods in this interface.</p>
654// 	 */
655// 	public void reset()
656// 	{
657
658// 		// %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
659// 		//       the next initDocument().
660// 		m_docElement = NULL;	 // reset nodeHandle to the root of the actual dtm doc content
661// 		initDocument(0);
662// 	}
663
664// 	/**
665// 	 * Factory method; creates an Element node in this document.
666// 	 *
667// 	 * The node created will be chained according to its natural order of request
668// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
669// 	 *
670// 	 * <p>The XML content handler will invoke endElement() method after all
671// 	 * of the element's content are processed in order to give DTM the indication
672// 	 * to prepare and patch up parent and sibling node pointers.</p>
673// 	 *
674// 	 * <p>The following interface for createElement will use an index value corresponds
675// 	 * to the symbol entry in the DTMDStringPool based symbol tables.</p>
676// 	 *
677// 	 * @param nsIndex The namespace of the node
678// 	 * @param nameIndex The element name.
679// 	 * @see #endElement
680// 	 * @see org.xml.sax.Attributes
681// 	 * @return nodeHandle int of the element created
682// 	 */
683// 	public int createElement(int nsIndex, int nameIndex, Attributes atts)
684// 	{
685// 		// do document root node creation here on the first element, create nodes for
686// 		// this element and its attributes, store the element, namespace, and attritute
687// 		// name indexes to the nodes array, keep track of the current node and parent
688// 		// element used
689
690// 		// W0  High:  Namespace  Low:  Node Type
691// 		int w0 = (nsIndex << 16) | ELEMENT_NODE;
692// 		// W1: Parent
693// 		int w1 = currentParent;
694// 		// W2: Next  (initialized as 0)
695// 		int w2 = 0;
696// 		// W3: Tagname
697// 		int w3 = nameIndex;
698// 		//int ourslot = nodes.appendSlot(w0, w1, w2, w3);
699// 		int ourslot = appendNode(w0, w1, w2, w3);
700// 		currentParent = ourslot;
701// 		previousSibling = 0;
702// 		setAttributes(atts);
703
704// 		// set the root element pointer when creating the first element node
705// 		if (m_docElement == NULL)
706// 			m_docElement = ourslot;
707// 		return (m_docHandle | ourslot);
708// 	}
709
710// 	// Factory method to create an Element node not associated with a given name space
711// 	// using String value parameters passed in from a content handler or application
712// 	/**
713// 	 * Factory method; creates an Element node not associated with a given name space in this document.
714// 	 *
715// 	 * The node created will be chained according to its natural order of request
716// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
717// 	 *
718// 	 * <p>The XML content handler or application will invoke endElement() method after all
719// 	 * of the element's content are processed in order to give DTM the indication
720// 	 * to prepare and patch up parent and sibling node pointers.</p>
721// 	 *
722// 	 * <p>The following parameters for createElement contains raw string values for name
723// 	 * symbols used in an Element node.</p>
724// 	 *
725// 	 * @param name String the element name, including the prefix if any.
726// 	 * @param atts The attributes attached to the element, if any.
727// 	 * @see #endElement
728// 	 * @see org.xml.sax.Attributes
729// 	 */
730// 	public int createElement(String name, Attributes atts)
731// 	{
732// 		// This method wraps around the index valued interface of the createElement interface.
733// 		// The raw string values are stored into the current DTM name symbol tables.  The method
734// 		// method will then use the index values returned to invoke the other createElement()
735// 		// onverted to index values modified to match a
736// 		// method.
737// 		int nsIndex = NULL;
738// 		int nameIndex = m_localNames.stringToIndex(name);
739// 		// note - there should be no prefix separator in the name because it is not associated
740// 		// with a name space
741
742// 		return createElement(nsIndex, nameIndex, atts);
743// 	}
744
745// 	// Factory method to create an Element node associated with a given name space
746// 	// using String value parameters passed in from a content handler or application
747// 	/**
748// 	 * Factory method; creates an Element node associated with a given name space in this document.
749// 	 *
750// 	 * The node created will be chained according to its natural order of request
751// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
752// 	 *
753// 	 * <p>The XML content handler or application will invoke endElement() method after all
754// 	 * of the element's content are processed in order to give DTM the indication
755// 	 * to prepare and patch up parent and sibling node pointers.</p>
756// 	 *
757// 	 * <p>The following parameters for createElementNS contains raw string values for name
758// 	 * symbols used in an Element node.</p>
759// 	 *
760// 	 * @param ns String the namespace of the node
761// 	 * @param name String the element name, including the prefix if any.
762// 	 * @param atts The attributes attached to the element, if any.
763// 	 * @see #endElement
764// 	 * @see org.xml.sax.Attributes
765// 	 */
766// 	public int createElementNS(String ns, String name, Attributes atts)
767// 	{
768// 		// This method wraps around the index valued interface of the createElement interface.
769// 		// The raw string values are stored into the current DTM name symbol tables.  The method
770// 		// method will then use the index values returned to invoke the other createElement()
771// 		// onverted to index values modified to match a
772// 		// method.
773// 		int nsIndex = m_nsNames.stringToIndex(ns);
774// 		int nameIndex = m_localNames.stringToIndex(name);
775// 		// The prefixIndex is not needed by the indexed interface of the createElement method
776// 		int prefixSep = name.indexOf(":");
777// 		int prefixIndex = m_prefixNames.stringToIndex(name.substring(0, prefixSep));
778// 		return createElement(nsIndex, nameIndex, atts);
779// 	}
780
781// 	/**
782// 	 * Receive an indication for the end of an element.
783// 	 *
784// 	 * <p>The XML content handler will invoke this method at the end of every
785// 	 * element in the XML document to give hint its time to pop up the current
786// 	 * element and parent and patch up parent and sibling pointers if necessary
787// 	 *
788// 	 * <p>%tbd% The following interface may need to be modified to match a
789// 	 * coordinated access to the DTMDStringPool based symbol tables.</p>
790// 		 *
791// 	 * @param ns the namespace of the element
792// 	 * @param name The element name
793// 	 */
794// 	public void endElement(String ns, String name)
795// 	{
796// 		// pop up the stacks
797
798// 		//
799// 		if (previousSiblingWasParent)
800// 			nodes.writeEntry(previousSibling, 2, NULL);
801
802// 		// Pop parentage
803// 		previousSibling = currentParent;
804// 		nodes.readSlot(currentParent, gotslot);
805// 		currentParent = gotslot[1] & 0xFFFF;
806
807// 		// The element just being finished will be
808// 		// the previous sibling for the next operation
809// 		previousSiblingWasParent = true;
810
811// 		// Pop a level of namespace table
812// 		// namespaceTable.removeLastElem();
813// 	}
814
815// 	/**
816// 	 * Creates attributes for the current node.
817// 	 *
818// 	 * @param atts Attributes to be created.
819// 	 */
820// 	void setAttributes(Attributes atts) {
821// 		int atLength = (null == atts) ? 0 : atts.getLength();
822// 		for (int i=0; i < atLength; i++) {
823// 			String qname = atts.getQName(i);
824// 			createAttribute(atts.getQName(i), atts.getValue(i));
825// 		}
826// 	}
827
828// 	/**
829// 	 * Appends an attribute to the document.
830// 	 * @param qname Qualified Name of the attribute
831// 	 * @param value Value of the attribute
832// 	 * @return Handle of node
833// 	 */
834// 	public int createAttribute(String qname, String value) {
835// 		int colonpos = qname.indexOf(":");
836// 		String attName = qname.substring(colonpos+1);
837// 		int w0 = 0;
838// 		if (colonpos > 0) {
839// 			String prefix = qname.substring(0, colonpos);
840// 			if (prefix.equals("xml")) {
841// 				//w0 = ATTRIBUTE_NODE |
842// 				//	(org.apache.xalan.templates.Constants.S_XMLNAMESPACEURI << 16);
843// 			} else {
844// 				//w0 = ATTRIBUTE_NODE |
845// 			}
846// 		} else {
847// 			w0 = ATTRIBUTE_NODE;
848// 		}
849// 		// W1:  Parent
850// 		int w1 = currentParent;
851// 		// W2:  Next (not yet resolved)
852// 		int w2 = 0;
853// 		// W3:  Tag name
854// 		int w3 = m_localNames.stringToIndex(attName);
855// 		// Add node
856// 		int ourslot = appendNode(w0, w1, w2, w3);
857// 		previousSibling = ourslot;	// Should attributes be previous siblings
858
859// 		// W0: Node Type
860// 		w0 = TEXT_NODE;
861// 		// W1: Parent
862// 		w1 = ourslot;
863// 		// W2: Start Position within buffer
864// 		w2 = m_char.length();
865// 		m_char.append(value);
866// 		// W3: Length
867// 		w3 = m_char.length() - w2;
868// 		appendNode(w0, w1, w2, w3);
869// 		charStringStart=m_char.length();
870// 		charStringLength = 0;
871// 		//previousSibling = ourslot;
872// 		// Attrs are Parents
873// 		previousSiblingWasParent = true;
874// 		return (m_docHandle | ourslot);
875// 	}
876
877// 	/**
878// 	 * Factory method; creates a Text node in this document.
879// 	 *
880// 	 * The node created will be chained according to its natural order of request
881// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
882// 	 *
883// 	 * @param text String The characters text string from the XML document.
884// 	 * @return int DTM node-number of the text node created
885// 	 */
886// 	public int createTextNode(String text)
887// 	throws DTMException
888// 	{
889// 		// wraps around the index value based createTextNode method
890// 		return createTextNode(text.toCharArray(), 0, text.length());
891// 	}
892
893// 	/**
894// 	 * Factory method; creates a Text node in this document.
895// 	 *
896// 	 * The node created will be chained according to its natural order of request
897// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
898// 	 *
899// 	 * %REVIEW% for text normalization issues, unless we are willing to
900// 	 * insist that all adjacent text must be merged before this method
901// 	 * is called.
902// 	 *
903// 	 * @param ch The characters from the XML document.
904// 	 * @param start The start position in the array.
905// 	 * @param length The number of characters to read from the array.
906// 	 */
907// 	public int createTextNode(char ch[], int start, int length)
908// 	throws DTMException
909// 	{
910// 		m_char.append(ch, start, length);		// store the chunk to the text/comment string table
911
912// 		// create a Text Node
913// 		// %TBD% may be possible to combine with appendNode()to replace the next chunk of code
914// 		int w0 = TEXT_NODE;
915// 		// W1: Parent
916// 		int w1 = currentParent;
917// 		// W2: Start position within m_char
918// 		int w2 = charStringStart;
919// 		// W3: Length of the full string
920// 		int w3 = length;
921// 		int ourslot = appendNode(w0, w1, w2, w3);
922// 		previousSibling = ourslot;
923
924// 		charStringStart=m_char.length();
925// 		charStringLength = 0;
926// 		return (m_docHandle | ourslot);
927// 	}
928
929// 	/**
930// 	 * Factory method; creates a Comment node in this document.
931// 	 *
932// 	 * The node created will be chained according to its natural order of request
933// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
934// 	 *
935// 	 * @param text String The characters text string from the XML document.
936// 	 * @return int DTM node-number of the text node created
937// 	 */
938// 	public int createComment(String text)
939// 	throws DTMException
940// 	{
941// 		// wraps around the index value based createTextNode method
942// 		return createComment(text.toCharArray(), 0, text.length());
943// 	}
944
945// 	/**
946// 	 * Factory method; creates a Comment node in this document.
947// 	 *
948// 	 * The node created will be chained according to its natural order of request
949// 	 * received.  %TBD% It can be rechained later via the optional DTM writable interface.
950// 	 *
951// 	 * @param ch An array holding the characters in the comment.
952// 	 * @param start The starting position in the array.
953// 	 * @param length The number of characters to use from the array.
954// 	 * @see DTMException
955// 	 */
956// 	public int createComment(char ch[], int start, int length)
957// 	throws DTMException
958// 	{
959// 		m_char.append(ch, start, length);		// store the comment string to the text/comment string table
960
961// 		// create a Comment Node
962// 		// %TBD% may be possible to combine with appendNode()to replace the next chunk of code
963// 		int w0 = COMMENT_NODE;
964// 		// W1: Parent
965// 		int w1 = currentParent;
966// 		// W2: Start position within m_char
967// 		int w2 = charStringStart;
968// 		// W3: Length of the full string
969// 		int w3 = length;
970// 		int ourslot = appendNode(w0, w1, w2, w3);
971// 		previousSibling = ourslot;
972
973// 		charStringStart=m_char.length();
974// 		charStringLength = 0;
975// 		return (m_docHandle | ourslot);
976// 	}
977
978// 	// Counters to keep track of the current text string being accumulated with respect
979// 	// to the text/comment string table: charStringStart should point to the starting
980// 	// offset of the string in the table and charStringLength the acccumulated length when
981// 	// appendAccumulatedText starts, and reset to the end of the table and 0 at the end
982// 	// of appendAccumulatedText for the next set of characters receives
983// 	int charStringStart=0,charStringLength=0;
984
985        // ========= Document Navigation Functions =========
986
987        /** Given a node handle, test if it has child nodes.
988         * <p> %REVIEW% This is obviously useful at the DOM layer, where it
989         * would permit testing this without having to create a proxy
990         * node. It's less useful in the DTM API, where
991         * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
992         * almost as self-evident. But it's a convenience, and eases porting
993         * of DOM code to DTM.  </p>
994         *
995         * @param nodeHandle int Handle of the node.
996         * @return int true if the given node has child nodes.
997         */
998        public boolean hasChildNodes(int nodeHandle) {
999                return(getFirstChild(nodeHandle) != NULL);
1000        }
1001
1002        /**
1003         * Given a node handle, get the handle of the node's first child.
1004         * If not yet resolved, waits for more nodes to be added to the document and
1005         * tries again.
1006         *
1007         * @param nodeHandle int Handle of the node.
1008         * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
1009         */
1010        public int getFirstChild(int nodeHandle) {
1011
1012                // ###shs worry about tracing/debug later
1013                nodeHandle &= NODEHANDLE_MASK;
1014                // Read node into variable
1015                nodes.readSlot(nodeHandle, gotslot);
1016
1017                // type is the last half of first slot
1018                short type = (short) (gotslot[0] & 0xFFFF);
1019
1020                // Check to see if Element or Document node
1021                if ((type == ELEMENT_NODE) || (type == DOCUMENT_NODE) ||
1022                                (type == ENTITY_REFERENCE_NODE)) {
1023
1024                        // In case when Document root is given
1025                        //	if (nodeHandle == 0) nodeHandle = 1;
1026                        // %TBD% Probably was a mistake.
1027                        // If someone explicitly asks for first child
1028                        // of Document, I would expect them to want
1029                        // that and only that.
1030
1031                        int kid = nodeHandle + 1;
1032                        nodes.readSlot(kid, gotslot);
1033                        while (ATTRIBUTE_NODE == (gotslot[0] & 0xFFFF)) {
1034                                // points to next sibling
1035                                kid = gotslot[2];
1036                                // Return NULL if node has only attributes
1037                                if (kid == NULL) return NULL;
1038                                nodes.readSlot(kid, gotslot);
1039                        }
1040                        // If parent slot matches given parent, return kid
1041                        if (gotslot[1] == nodeHandle)
1042                        {
1043                          int firstChild = kid | m_docHandle;
1044
1045                          return firstChild;
1046                        }
1047                }
1048                // No child found
1049
1050                return NULL;
1051        }
1052
1053        /**
1054        * Given a node handle, advance to its last child.
1055        * If not yet resolved, waits for more nodes to be added to the document and
1056        * tries again.
1057        *
1058        * @param nodeHandle int Handle of the node.
1059        * @return int Node-number of last child,
1060        * or DTM.NULL to indicate none exists.
1061        */
1062        public int getLastChild(int nodeHandle) {
1063                // ###shs put trace/debug later
1064                nodeHandle &= NODEHANDLE_MASK;
1065                // do not need to test node type since getFirstChild does that
1066                int lastChild = NULL;
1067                for (int nextkid = getFirstChild(nodeHandle); nextkid != NULL;
1068                                nextkid = getNextSibling(nextkid)) {
1069                        lastChild = nextkid;
1070                }
1071                return lastChild | m_docHandle;
1072        }
1073
1074        /**
1075         * Retrieves an attribute node by by qualified name and namespace URI.
1076         *
1077         * @param nodeHandle int Handle of the node upon which to look up this attribute.
1078         * @param namespaceURI The namespace URI of the attribute to
1079         *   retrieve, or null.
1080         * @param name The local name of the attribute to
1081         *   retrieve.
1082         * @return The attribute node handle with the specified name (
1083         *   <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1084         *   attribute.
1085         */
1086        public int getAttributeNode(int nodeHandle, String namespaceURI, String name) {
1087                int nsIndex = m_nsNames.stringToIndex(namespaceURI),
1088                                                                        nameIndex = m_localNames.stringToIndex(name);
1089                nodeHandle &= NODEHANDLE_MASK;
1090                nodes.readSlot(nodeHandle, gotslot);
1091                short type = (short) (gotslot[0] & 0xFFFF);
1092                // If nodeHandle points to element next slot would be first attribute
1093                if (type == ELEMENT_NODE)
1094                        nodeHandle++;
1095                // Iterate through Attribute Nodes
1096                while (type == ATTRIBUTE_NODE) {
1097                        if ((nsIndex == (gotslot[0] << 16)) && (gotslot[3] == nameIndex))
1098                                return nodeHandle | m_docHandle;
1099                        // Goto next sibling
1100                        nodeHandle = gotslot[2];
1101                        nodes.readSlot(nodeHandle, gotslot);
1102                }
1103                return NULL;
1104        }
1105
1106        /**
1107         * Given a node handle, get the index of the node's first attribute.
1108         *
1109         * @param nodeHandle int Handle of the Element node.
1110         * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1111         */
1112        public int getFirstAttribute(int nodeHandle) {
1113                nodeHandle &= NODEHANDLE_MASK;
1114
1115                // %REVIEW% jjk: Just a quick observation: If you're going to
1116                // call readEntry repeatedly on the same node, it may be
1117                // more efficiently to do a readSlot to get the data locally,
1118                // reducing the addressing and call-and-return overhead.
1119
1120                // Should we check if handle is element (do we want sanity checks?)
1121                if (ELEMENT_NODE != (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1122                        return NULL;
1123                // First Attribute (if any) should be at next position in table
1124                nodeHandle++;
1125                return(ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF)) ?
1126                nodeHandle | m_docHandle : NULL;
1127        }
1128
1129        /**
1130         * Given a node handle, get the index of the node's first child.
1131         * If not yet resolved, waits for more nodes to be added to the document and
1132         * tries again
1133         *
1134         * @param nodeHandle handle to node, which should probably be an element
1135         *                   node, but need not be.
1136         *
1137         * @param inScope    true if all namespaces in scope should be returned,
1138         *                   false if only the namespace declarations should be
1139         *                   returned.
1140         * @return handle of first namespace, or DTM.NULL to indicate none exists.
1141         */
1142        public int getFirstNamespaceNode(int nodeHandle, boolean inScope) {
1143
1144                return NULL;
1145        }
1146
1147        /**
1148         * Given a node handle, advance to its next sibling.
1149         *
1150         * %TBD% This currently uses the DTM-internal definition of
1151         * sibling; eg, the last attr's next sib is the first
1152         * child. In the old DTM, the DOM proxy layer provided the
1153         * additional logic for the public view.  If we're rewriting
1154         * for XPath emulation, that test must be done here.
1155         *
1156         * %TBD% CODE INTERACTION WITH INCREMENTAL PARSE - If not yet
1157         * resolved, should wait for more nodes to be added to the document
1158         * and tries again.
1159         *
1160         * @param nodeHandle int Handle of the node.
1161         * @return int Node-number of next sibling,
1162         * or DTM.NULL to indicate none exists.
1163         * */
1164        public int getNextSibling(int nodeHandle) {
1165                nodeHandle &= NODEHANDLE_MASK;
1166                // Document root has no next sibling
1167                if (nodeHandle == 0)
1168                        return NULL;
1169
1170                short type = (short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1171                if ((type == ELEMENT_NODE) || (type == ATTRIBUTE_NODE) ||
1172                                (type == ENTITY_REFERENCE_NODE)) {
1173                        int nextSib = nodes.readEntry(nodeHandle, 2);
1174                        if (nextSib == NULL)
1175                                return NULL;
1176                        if (nextSib != 0)
1177                                return (m_docHandle | nextSib);
1178                        // ###shs should cycle/wait if nextSib is 0? Working on threading next
1179                }
1180                // Next Sibling is in the next position if it shares the same parent
1181                int thisParent = nodes.readEntry(nodeHandle, 1);
1182
1183                if (nodes.readEntry(++nodeHandle, 1) == thisParent)
1184                        return (m_docHandle | nodeHandle);
1185
1186                return NULL;
1187        }
1188
1189        /**
1190         * Given a node handle, find its preceeding sibling.
1191         * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1192         * relatively expensive.
1193         *
1194         * @param nodeHandle the id of the node.
1195         * @return int Node-number of the previous sib,
1196         * or DTM.NULL to indicate none exists.
1197         */
1198        public int getPreviousSibling(int nodeHandle) {
1199                nodeHandle &= NODEHANDLE_MASK;
1200                // Document root has no previous sibling
1201                if (nodeHandle == 0)
1202                        return NULL;
1203
1204                int parent = nodes.readEntry(nodeHandle, 1);
1205                int kid = NULL;
1206                for (int nextkid = getFirstChild(parent); nextkid != nodeHandle;
1207                                nextkid = getNextSibling(nextkid)) {
1208                        kid = nextkid;
1209                }
1210                return kid | m_docHandle;
1211        }
1212
1213        /**
1214         * Given a node handle, advance to the next attribute. If an
1215         * element, we advance to its first attribute; if an attr, we advance to
1216         * the next attr on the same node.
1217         *
1218         * @param nodeHandle int Handle of the node.
1219         * @return int DTM node-number of the resolved attr,
1220         * or DTM.NULL to indicate none exists.
1221         */
1222        public int getNextAttribute(int nodeHandle) {
1223                nodeHandle &= NODEHANDLE_MASK;
1224                nodes.readSlot(nodeHandle, gotslot);
1225
1226                //%REVIEW% Why are we using short here? There's no storage
1227                //reduction for an automatic variable, especially one used
1228                //so briefly, and it typically costs more cycles to process
1229                //than an int would.
1230                short type = (short) (gotslot[0] & 0xFFFF);
1231
1232                if (type == ELEMENT_NODE) {
1233                        return getFirstAttribute(nodeHandle);
1234                } else if (type == ATTRIBUTE_NODE) {
1235                        if (gotslot[2] != NULL)
1236                                return (m_docHandle | gotslot[2]);
1237                }
1238                return NULL;
1239        }
1240
1241        /**
1242         * Given a namespace handle, advance to the next namespace.
1243         *
1244         * %TBD% THIS METHOD DOES NOT MATCH THE CURRENT SIGNATURE IN
1245         * THE DTM INTERFACE.  FIX IT, OR JUSTIFY CHANGING THE DTM
1246         * API.
1247         *
1248         * @param namespaceHandle handle to node which must be of type NAMESPACE_NODE.
1249         * @return handle of next namespace, or DTM.NULL to indicate none exists.
1250         */
1251        public int getNextNamespaceNode(int baseHandle,int namespaceHandle, boolean inScope) {
1252                // ###shs need to work on namespace
1253                return NULL;
1254        }
1255
1256        /**
1257         * Given a node handle, advance to its next descendant.
1258         * If not yet resolved, waits for more nodes to be added to the document and
1259         * tries again.
1260         *
1261         * @param subtreeRootHandle
1262         * @param nodeHandle int Handle of the node.
1263         * @return handle of next descendant,
1264         * or DTM.NULL to indicate none exists.
1265         */
1266        public int getNextDescendant(int subtreeRootHandle, int nodeHandle) {
1267                subtreeRootHandle &= NODEHANDLE_MASK;
1268                nodeHandle &= NODEHANDLE_MASK;
1269                // Document root [Document Node? -- jjk] - no next-sib
1270                if (nodeHandle == 0)
1271                        return NULL;
1272                while (!m_isError) {
1273                        // Document done and node out of bounds
1274                        if (done && (nodeHandle > nodes.slotsUsed()))
1275                                break;
1276                        if (nodeHandle > subtreeRootHandle) {
1277                                nodes.readSlot(nodeHandle+1, gotslot);
1278                                if (gotslot[2] != 0) {
1279                                        short type = (short) (gotslot[0] & 0xFFFF);
1280                                        if (type == ATTRIBUTE_NODE) {
1281                                                nodeHandle +=2;
1282                                        } else {
1283                                                int nextParentPos = gotslot[1];
1284                                                if (nextParentPos >= subtreeRootHandle)
1285                                                        return (m_docHandle | (nodeHandle+1));
1286                                                else
1287                                                        break;
1288                                        }
1289                                } else if (!done) {
1290                                        // Add wait logic here
1291                                } else
1292                                        break;
1293                        } else {
1294                                nodeHandle++;
1295                        }
1296                }
1297                // Probably should throw error here like original instead of returning
1298                return NULL;
1299        }
1300
1301        /**
1302         * Given a node handle, advance to the next node on the following axis.
1303         *
1304         * @param axisContextHandle the start of the axis that is being traversed.
1305         * @param nodeHandle
1306         * @return handle of next sibling,
1307         * or DTM.NULL to indicate none exists.
1308         */
1309        public int getNextFollowing(int axisContextHandle, int nodeHandle) {
1310                //###shs still working on
1311                return NULL;
1312        }
1313
1314        /**
1315         * Given a node handle, advance to the next node on the preceding axis.
1316         *
1317         * @param axisContextHandle the start of the axis that is being traversed.
1318         * @param nodeHandle the id of the node.
1319         * @return int Node-number of preceding sibling,
1320         * or DTM.NULL to indicate none exists.
1321         */
1322        public int getNextPreceding(int axisContextHandle, int nodeHandle) {
1323                // ###shs copied from Xalan 1, what is this suppose to do?
1324                nodeHandle &= NODEHANDLE_MASK;
1325                while (nodeHandle > 1) {
1326                        nodeHandle--;
1327                        if (ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1328                                continue;
1329
1330                        // if nodeHandle is _not_ an ancestor of
1331                        // axisContextHandle, specialFind will return it.
1332                        // If it _is_ an ancestor, specialFind will return -1
1333
1334                        // %REVIEW% unconditional return defeats the
1335                        // purpose of the while loop -- does this
1336                        // logic make any sense?
1337
1338                        return (m_docHandle | nodes.specialFind(axisContextHandle, nodeHandle));
1339                }
1340                return NULL;
1341        }
1342
1343        /**
1344         * Given a node handle, find its parent node.
1345         *
1346         * @param nodeHandle the id of the node.
1347         * @return int Node-number of parent,
1348         * or DTM.NULL to indicate none exists.
1349         */
1350        public int getParent(int nodeHandle) {
1351                // Should check to see within range?
1352
1353                // Document Root should not have to be handled differently
1354                return (m_docHandle | nodes.readEntry(nodeHandle, 1));
1355        }
1356
1357        /**
1358         * Returns the root element of the document.
1359         * @return nodeHandle to the Document Root.
1360         */
1361        public int getDocumentRoot() {
1362                return (m_docHandle | m_docElement);
1363        }
1364
1365        /**
1366         * Given a node handle, find the owning document node.
1367         *
1368         * @return int Node handle of document, which should always be valid.
1369         */
1370        public int getDocument() {
1371                return m_docHandle;
1372        }
1373
1374        /**
1375         * Given a node handle, find the owning document node.  This has the exact
1376         * same semantics as the DOM Document method of the same name, in that if
1377         * the nodeHandle is a document node, it will return NULL.
1378         *
1379         * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1380         * binding layer. Included here as a convenience function and to
1381         * aid porting of DOM code to DTM.</p>
1382         *
1383         * @param nodeHandle the id of the node.
1384         * @return int Node handle of owning document, or NULL if the nodeHandle is
1385         *             a document.
1386         */
1387        public int getOwnerDocument(int nodeHandle) {
1388                // Assumption that Document Node is always in 0 slot
1389                if ((nodeHandle & NODEHANDLE_MASK) == 0)
1390                        return NULL;
1391                return (nodeHandle & DOCHANDLE_MASK);
1392        }
1393
1394        /**
1395         * Given a node handle, find the owning document node.  This has the DTM
1396         * semantics; a Document node is its own owner.
1397         *
1398         * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1399         * binding layer. Included here as a convenience function and to
1400         * aid porting of DOM code to DTM.</p>
1401         *
1402         * @param nodeHandle the id of the node.
1403         * @return int Node handle of owning document, or NULL if the nodeHandle is
1404         *             a document.
1405         */
1406        public int getDocumentRoot(int nodeHandle) {
1407                // Assumption that Document Node is always in 0 slot
1408                if ((nodeHandle & NODEHANDLE_MASK) == 0)
1409                        return NULL;
1410                return (nodeHandle & DOCHANDLE_MASK);
1411        }
1412
1413        /**
1414         * Get the string-value of a node as a String object
1415         * (see http://www.w3.org/TR/xpath#data-model
1416         * for the definition of a node's string-value).
1417         *
1418         * @param nodeHandle The node ID.
1419         *
1420         * @return A string object that represents the string-value of the given node.
1421         */
1422        public XMLString getStringValue(int nodeHandle) {
1423        // ###zaj - researching
1424        nodes.readSlot(nodeHandle, gotslot);
1425        int nodetype=gotslot[0] & 0xFF;
1426        String value=null;
1427
1428        switch (nodetype) {
1429        case TEXT_NODE:
1430        case COMMENT_NODE:
1431        case CDATA_SECTION_NODE:
1432                value= m_char.getString(gotslot[2], gotslot[3]);
1433                break;
1434        case PROCESSING_INSTRUCTION_NODE:
1435        case ATTRIBUTE_NODE:
1436        case ELEMENT_NODE:
1437        case ENTITY_REFERENCE_NODE:
1438        default:
1439                break;
1440        }
1441        return m_xsf.newstr( value );
1442
1443        }
1444
1445        /**
1446         * Get number of character array chunks in
1447         * the string-value of a node.
1448         * (see http://www.w3.org/TR/xpath#data-model
1449         * for the definition of a node's string-value).
1450         * Note that a single text node may have multiple text chunks.
1451         *
1452         * EXPLANATION: This method is an artifact of the fact that the
1453         * underlying m_chars object may not store characters in a
1454         * single contiguous array -- for example,the current
1455         * FastStringBuffer may split a single node's text across
1456         * multiple allocation units.  This call tells us how many
1457         * separate accesses will be required to retrieve the entire
1458         * content. PLEASE NOTE that this may not be the same as the
1459         * number of SAX characters() events that caused the text node
1460         * to be built in the first place, since m_chars buffering may
1461         * be on different boundaries than the parser's buffers.
1462         *
1463         * @param nodeHandle The node ID.
1464         *
1465         * @return number of character array chunks in
1466         *         the string-value of a node.
1467         * */
1468        //###zaj - tbd
1469        public int getStringValueChunkCount(int nodeHandle)
1470        {
1471                //###zaj    return value
1472                return 0;
1473        }
1474
1475        /**
1476         * Get a character array chunk in the string-value of a node.
1477         * (see http://www.w3.org/TR/xpath#data-model
1478         * for the definition of a node's string-value).
1479         * Note that a single text node may have multiple text chunks.
1480         *
1481         * EXPLANATION: This method is an artifact of the fact that
1482         * the underlying m_chars object may not store characters in a
1483         * single contiguous array -- for example,the current
1484         * FastStringBuffer may split a single node's text across
1485         * multiple allocation units.  This call retrieves a single
1486         * contiguous portion of the text -- as much as m-chars was
1487         * able to store in a single allocation unit.  PLEASE NOTE
1488         * that this may not be the same granularityas the SAX
1489         * characters() events that caused the text node to be built
1490         * in the first place, since m_chars buffering may be on
1491         * different boundaries than the parser's buffers.
1492         *
1493         * @param nodeHandle The node ID.
1494         * @param chunkIndex Which chunk to get.
1495         * @param startAndLen An array of 2 where the start position and length of
1496         *                    the chunk will be returned.
1497         *
1498         * @return The character array reference where the chunk occurs.  */
1499        //###zaj - tbd
1500        public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1501                                                                                                                                                int[] startAndLen) {return new char[0];}
1502
1503        /**
1504         * Given a node handle, return an ID that represents the node's expanded name.
1505         *
1506         * @param nodeHandle The handle to the node in question.
1507         *
1508         * @return the expanded-name id of the node.
1509         */
1510        public int getExpandedTypeID(int nodeHandle) {
1511           nodes.readSlot(nodeHandle, gotslot);
1512           String qName = m_localNames.indexToString(gotslot[3]);
1513           // Remove prefix from qName
1514           // %TBD% jjk This is assuming the elementName is the qName.
1515           int colonpos = qName.indexOf(":");
1516           String localName = qName.substring(colonpos+1);
1517           // Get NS
1518           String namespace = m_nsNames.indexToString(gotslot[0] << 16);
1519           // Create expanded name
1520           String expandedName = namespace + ":" + localName;
1521           int expandedNameID = m_nsNames.stringToIndex(expandedName);
1522
1523        return expandedNameID;
1524        }
1525
1526
1527        /**
1528         * Given an expanded name, return an ID.  If the expanded-name does not
1529         * exist in the internal tables, the entry will be created, and the ID will
1530         * be returned.  Any additional nodes that are created that have this
1531         * expanded name will use this ID.
1532         *
1533         * @return the expanded-name id of the node.
1534         */
1535        public int getExpandedTypeID(String namespace, String localName, int type) {
1536           // Create expanded name
1537          // %TBD% jjk Expanded name is bitfield-encoded as
1538          // typeID[6]nsuriID[10]localID[16]. Switch to that form, and to
1539          // accessing the ns/local via their tables rather than confusing
1540          // nsnames and expandednames.
1541           String expandedName = namespace + ":" + localName;
1542           int expandedNameID = m_nsNames.stringToIndex(expandedName);
1543
1544           return expandedNameID;
1545        }
1546
1547
1548        /**
1549         * Given an expanded-name ID, return the local name part.
1550         *
1551         * @param ExpandedNameID an ID that represents an expanded-name.
1552         * @return String Local name of this node.
1553         */
1554        public String getLocalNameFromExpandedNameID(int ExpandedNameID) {
1555
1556           // Get expanded name
1557           String expandedName = m_localNames.indexToString(ExpandedNameID);
1558           // Remove prefix from expanded name
1559           int colonpos = expandedName.indexOf(":");
1560           String localName = expandedName.substring(colonpos+1);
1561           return localName;
1562        }
1563
1564
1565        /**
1566         * Given an expanded-name ID, return the namespace URI part.
1567         *
1568         * @param ExpandedNameID an ID that represents an expanded-name.
1569         * @return String URI value of this node's namespace, or null if no
1570         * namespace was resolved.
1571        */
1572        public String getNamespaceFromExpandedNameID(int ExpandedNameID) {
1573
1574           String expandedName = m_localNames.indexToString(ExpandedNameID);
1575           // Remove local name from expanded name
1576           int colonpos = expandedName.indexOf(":");
1577           String nsName = expandedName.substring(0, colonpos);
1578
1579        return nsName;
1580        }
1581
1582
1583        /**
1584         * fixednames
1585        */
1586        private static final String[] fixednames=
1587        {
1588                null,null,							// nothing, Element
1589                null,"#text",						// Attr, Text
1590                "#cdata_section",null,	// CDATA, EntityReference
1591                null,null,							// Entity, PI
1592                "#comment","#document",	// Comment, Document
1593                null,"#document-fragment", // Doctype, DocumentFragment
1594                null};									// Notation
1595
1596        /**
1597         * Given a node handle, return its DOM-style node name. This will
1598         * include names such as #text or #document.
1599         *
1600         * @param nodeHandle the id of the node.
1601         * @return String Name of this node, which may be an empty string.
1602         * %REVIEW% Document when empty string is possible...
1603         */
1604        public String getNodeName(int nodeHandle) {
1605                nodes.readSlot(nodeHandle, gotslot);
1606                short type = (short) (gotslot[0] & 0xFFFF);
1607                String name = fixednames[type];
1608                if (null == name) {
1609                  int i=gotslot[3];
1610                  /**/System.out.println("got i="+i+" "+(i>>16)+"/"+(i&0xffff));
1611
1612                  name=m_localNames.indexToString(i & 0xFFFF);
1613                  String prefix=m_prefixNames.indexToString(i >>16);
1614                  if(prefix!=null && prefix.length()>0)
1615                    name=prefix+":"+name;
1616                }
1617                return name;
1618        }
1619
1620        /**
1621         * Given a node handle, return the XPath node name.  This should be
1622         * the name as described by the XPath data model, NOT the DOM-style
1623         * name.
1624         *
1625         * @param nodeHandle the id of the node.
1626         * @return String Name of this node.
1627         */
1628        public String getNodeNameX(int nodeHandle) {return null;}
1629
1630        /**
1631         * Given a node handle, return its DOM-style localname.
1632         * (As defined in Namespaces, this is the portion of the name after any
1633         * colon character)
1634         *
1635         * %REVIEW% What's the local name of something other than Element/Attr?
1636         * Should this be DOM-style (undefined unless namespaced), or other?
1637         *
1638         * @param nodeHandle the id of the node.
1639         * @return String Local name of this node.
1640         */
1641        public String getLocalName(int nodeHandle) {
1642                nodes.readSlot(nodeHandle, gotslot);
1643                short type = (short) (gotslot[0] & 0xFFFF);
1644                String name = "";
1645                if ((type==ELEMENT_NODE) || (type==ATTRIBUTE_NODE)) {
1646                  int i=gotslot[3];
1647                  name=m_localNames.indexToString(i & 0xFFFF);
1648                  if(name==null) name="";
1649                }
1650                return name;
1651        }
1652
1653        /**
1654         * Given a namespace handle, return the prefix that the namespace decl is
1655         * mapping.
1656         * Given a node handle, return the prefix used to map to the namespace.
1657         *
1658         * <p> %REVIEW% Are you sure you want "" for no prefix?  </p>
1659         *
1660         * %REVIEW%  Should this be DOM-style (undefined unless namespaced),
1661         * or other?
1662         *
1663         * @param nodeHandle the id of the node.
1664         * @return String prefix of this node's name, or "" if no explicit
1665         * namespace prefix was given.
1666         */
1667        public String getPrefix(int nodeHandle) {
1668                nodes.readSlot(nodeHandle, gotslot);
1669                short type = (short) (gotslot[0] & 0xFFFF);
1670                String name = "";
1671                if((type==ELEMENT_NODE) || (type==ATTRIBUTE_NODE)) {
1672                  int i=gotslot[3];
1673                  name=m_prefixNames.indexToString(i >>16);
1674                  if(name==null) name="";
1675                }
1676                return name;
1677        }
1678
1679        /**
1680         * Given a node handle, return its DOM-style namespace URI
1681         * (As defined in Namespaces, this is the declared URI which this node's
1682         * prefix -- or default in lieu thereof -- was mapped to.)
1683         *
1684         * @param nodeHandle the id of the node.
1685         * @return String URI value of this node's namespace, or null if no
1686         * namespace was resolved.
1687         */
1688        public String getNamespaceURI(int nodeHandle) {return null;}
1689
1690        /**
1691         * Given a node handle, return its node value. This is mostly
1692         * as defined by the DOM, but may ignore some conveniences.
1693         * <p>
1694         *
1695         * @param nodeHandle The node id.
1696         * @return String Value of this node, or null if not
1697         * meaningful for this node type.
1698         */
1699        public String getNodeValue(int nodeHandle)
1700        {
1701                nodes.readSlot(nodeHandle, gotslot);
1702                int nodetype=gotslot[0] & 0xFF;		// ###zaj use mask to get node type
1703                String value=null;
1704
1705                switch (nodetype) {			// ###zaj todo - document nodetypes
1706                case ATTRIBUTE_NODE:
1707                        nodes.readSlot(nodeHandle+1, gotslot);
1708                case TEXT_NODE:
1709                case COMMENT_NODE:
1710                case CDATA_SECTION_NODE:
1711                        value=m_char.getString(gotslot[2], gotslot[3]);		//###zaj
1712                        break;
1713                case PROCESSING_INSTRUCTION_NODE:
1714                case ELEMENT_NODE:
1715                case ENTITY_REFERENCE_NODE:
1716                default:
1717                        break;
1718                }
1719                return value;
1720        }
1721
1722        /**
1723         * Given a node handle, return its DOM-style node type.
1724         * <p>
1725         * %REVIEW% Generally, returning short is false economy. Return int?
1726         *
1727         * @param nodeHandle The node id.
1728         * @return int Node type, as per the DOM's Node._NODE constants.
1729         */
1730        public short getNodeType(int nodeHandle) {
1731                return(short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1732        }
1733
1734        /**
1735         * Get the depth level of this node in the tree (equals 1 for
1736         * a parentless node).
1737         *
1738         * @param nodeHandle The node id.
1739         * @return the number of ancestors, plus one
1740         * @xsl.usage internal
1741         */
1742        public short getLevel(int nodeHandle) {
1743                short count = 0;
1744                while (nodeHandle != 0) {
1745                        count++;
1746                        nodeHandle = nodes.readEntry(nodeHandle, 1);
1747                }
1748                return count;
1749        }
1750
1751        // ============== Document query functions ==============
1752
1753        /**
1754         * Tests whether DTM DOM implementation implements a specific feature and
1755         * that feature is supported by this node.
1756         *
1757         * @param feature The name of the feature to test.
1758         * @param version This is the version number of the feature to test.
1759         *   If the version is not
1760         *   specified, supporting any version of the feature will cause the
1761         *   method to return <code>true</code>.
1762         * @return Returns <code>true</code> if the specified feature is
1763         *   supported on this node, <code>false</code> otherwise.
1764         */
1765        public boolean isSupported(String feature, String version) {return false;}
1766
1767        /**
1768         * Return the base URI of the document entity. If it is not known
1769         * (because the document was parsed from a socket connection or from
1770         * standard input, for example), the value of this property is unknown.
1771         *
1772         * @return the document base URI String object or null if unknown.
1773         */
1774        public String getDocumentBaseURI()
1775        {
1776
1777          return m_documentBaseURI;
1778        }
1779
1780        /**
1781         * Set the base URI of the document entity.
1782         *
1783         * @param baseURI the document base URI String object or null if unknown.
1784         */
1785        public void setDocumentBaseURI(String baseURI)
1786        {
1787
1788          m_documentBaseURI = baseURI;
1789        }
1790
1791        /**
1792         * Return the system identifier of the document entity. If
1793         * it is not known, the value of this property is unknown.
1794         *
1795         * @param nodeHandle The node id, which can be any valid node handle.
1796         * @return the system identifier String object or null if unknown.
1797         */
1798        public String getDocumentSystemIdentifier(int nodeHandle) {return null;}
1799
1800        /**
1801         * Return the name of the character encoding scheme
1802         *        in which the document entity is expressed.
1803         *
1804         * @param nodeHandle The node id, which can be any valid node handle.
1805         * @return the document encoding String object.
1806         */
1807        public String getDocumentEncoding(int nodeHandle) {return null;}
1808
1809        /**
1810         * Return an indication of the standalone status of the document,
1811         *        either "yes" or "no". This property is derived from the optional
1812         *        standalone document declaration in the XML declaration at the
1813         *        beginning of the document entity, and has no value if there is no
1814         *        standalone document declaration.
1815         *
1816         * @param nodeHandle The node id, which can be any valid node handle.
1817         * @return the document standalone String object, either "yes", "no", or null.
1818         */
1819        public String getDocumentStandalone(int nodeHandle) {return null;}
1820
1821        /**
1822         * Return a string representing the XML version of the document. This
1823         * property is derived from the XML declaration optionally present at the
1824         * beginning of the document entity, and has no value if there is no XML
1825         * declaration.
1826         *
1827         * @param documentHandle the document handle
1828         *
1829         * @return the document version String object
1830         */
1831        public String getDocumentVersion(int documentHandle) {return null;}
1832
1833        /**
1834         * Return an indication of
1835         * whether the processor has read the complete DTD. Its value is a
1836         * boolean. If it is false, then certain properties (indicated in their
1837         * descriptions below) may be unknown. If it is true, those properties
1838         * are never unknown.
1839         *
1840         * @return <code>true</code> if all declarations were processed {};
1841         *         <code>false</code> otherwise.
1842         */
1843        public boolean getDocumentAllDeclarationsProcessed() {return false;}
1844
1845        /**
1846         *   A document type declaration information item has the following properties:
1847         *
1848         *     1. [system identifier] The system identifier of the external subset, if
1849         *        it exists. Otherwise this property has no value.
1850         *
1851         * @return the system identifier String object, or null if there is none.
1852         */
1853        public String getDocumentTypeDeclarationSystemIdentifier() {return null;}
1854
1855        /**
1856         * Return the public identifier of the external subset,
1857         * normalized as described in 4.2.2 External Entities [XML]. If there is
1858         * no external subset or if it has no public identifier, this property
1859         * has no value.
1860         *
1861         * @return the public identifier String object, or null if there is none.
1862         */
1863        public String getDocumentTypeDeclarationPublicIdentifier() {return null;}
1864
1865        /**
1866         * Returns the <code>Element</code> whose <code>ID</code> is given by
1867         * <code>elementId</code>. If no such element exists, returns
1868         * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1869         * has this <code>ID</code>. Attributes (including those
1870         * with the name "ID") are not of type ID unless so defined by DTD/Schema
1871         * information available to the DTM implementation.
1872         * Implementations that do not know whether attributes are of type ID or
1873         * not are expected to return <code>DTM.NULL</code>.
1874         *
1875         * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1876         * and this operation searches only within a single document, right?
1877         * Wouldn't want collisions between DTMs in the same process.</p>
1878         *
1879         * @param elementId The unique <code>id</code> value for an element.
1880         * @return The handle of the matching element.
1881         */
1882        public int getElementById(String elementId) {return 0;}
1883
1884        /**
1885         * The getUnparsedEntityURI function returns the URI of the unparsed
1886         * entity with the specified name in the same document as the context
1887         * node (see [3.3 Unparsed Entities]). It returns the empty string if
1888         * there is no such entity.
1889         * <p>
1890         * XML processors may choose to use the System Identifier (if one
1891         * is provided) to resolve the entity, rather than the URI in the
1892         * Public Identifier. The details are dependent on the processor, and
1893         * we would have to support some form of plug-in resolver to handle
1894         * this properly. Currently, we simply return the System Identifier if
1895         * present, and hope that it a usable URI or that our caller can
1896         * map it to one.
1897         * TODO: Resolve Public Identifiers... or consider changing function name.
1898         * <p>
1899         * If we find a relative URI
1900         * reference, XML expects it to be resolved in terms of the base URI
1901         * of the document. The DOM doesn't do that for us, and it isn't
1902         * entirely clear whether that should be done here; currently that's
1903         * pushed up to a higher level of our application. (Note that DOM Level
1904         * 1 didn't store the document's base URI.)
1905         * TODO: Consider resolving Relative URIs.
1906         * <p>
1907         * (The DOM's statement that "An XML processor may choose to
1908         * completely expand entities before the structure model is passed
1909         * to the DOM" refers only to parsed entities, not unparsed, and hence
1910         * doesn't affect this function.)
1911         *
1912         * @param name A string containing the Entity Name of the unparsed
1913         * entity.
1914         *
1915         * @return String containing the URI of the Unparsed Entity, or an
1916         * empty string if no such entity exists.
1917         */
1918        public String getUnparsedEntityURI(String name) {return null;}
1919
1920
1921        // ============== Boolean methods ================
1922
1923        /**
1924         * Return true if the xsl:strip-space or xsl:preserve-space was processed
1925         * during construction of the DTM document.
1926         *
1927         * <p>%REVEIW% Presumes a 1:1 mapping from DTM to Document, since
1928         * we aren't saying which Document to query...?</p>
1929         */
1930        public boolean supportsPreStripping() {return false;}
1931
1932        /**
1933         * Figure out whether nodeHandle2 should be considered as being later
1934         * in the document than nodeHandle1, in Document Order as defined
1935         * by the XPath model. This may not agree with the ordering defined
1936         * by other XML applications.
1937         * <p>
1938         * There are some cases where ordering isn't defined, and neither are
1939         * the results of this function -- though we'll generally return true.
1940         *
1941         * TODO: Make sure this does the right thing with attribute nodes!!!
1942         *
1943         * @param nodeHandle1 DOM Node to perform position comparison on.
1944         * @param nodeHandle2 DOM Node to perform position comparison on .
1945         *
1946         * @return false if node2 comes before node1, otherwise return true.
1947         * You can think of this as
1948         * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
1949         */
1950        public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {return false;}
1951
1952        /**
1953         *     2. [element content whitespace] A boolean indicating whether the
1954         *        character is white space appearing within element content (see [XML],
1955         *        2.10 "White Space Handling"). Note that validating XML processors are
1956         *        required by XML 1.0 to provide this information. If there is no
1957         *        declaration for the containing element, this property has no value for
1958         *        white space characters. If no declaration has been read, but the [all
1959         *        declarations processed] property of the document information item is
1960         *        false (so there may be an unread declaration), then the value of this
1961         *        property is unknown for white space characters. It is always false for
1962         *        characters that are not white space.
1963         *
1964         * @param nodeHandle the node ID.
1965         * @return <code>true</code> if the character data is whitespace;
1966         *         <code>false</code> otherwise.
1967         */
1968        public boolean isCharacterElementContentWhitespace(int nodeHandle) {return false;}
1969
1970        /**
1971         *    10. [all declarations processed] This property is not strictly speaking
1972         *        part of the infoset of the document. Rather it is an indication of
1973         *        whether the processor has read the complete DTD. Its value is a
1974         *        boolean. If it is false, then certain properties (indicated in their
1975         *        descriptions below) may be unknown. If it is true, those properties
1976         *        are never unknown.
1977         *
1978         * @param documentHandle A node handle that must identify a document.
1979         * @return <code>true</code> if all declarations were processed;
1980         *         <code>false</code> otherwise.
1981         */
1982        public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {return false;}
1983
1984        /**
1985         *     5. [specified] A flag indicating whether this attribute was actually
1986         *        specified in the start-tag of its element, or was defaulted from the
1987         *        DTD.
1988         *
1989         * @param attributeHandle the attribute handle
1990         * @return <code>true</code> if the attribute was specified;
1991         *         <code>false</code> if it was defaulted.
1992         */
1993        public boolean isAttributeSpecified(int attributeHandle) {return false;}
1994
1995        // ========== Direct SAX Dispatch, for optimization purposes ========
1996
1997        /**
1998         * Directly call the
1999         * characters method on the passed ContentHandler for the
2000         * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2001         * for the definition of a node's string-value). Multiple calls to the
2002         * ContentHandler's characters methods may well occur for a single call to
2003         * this method.
2004         *
2005         * @param nodeHandle The node ID.
2006         * @param ch A non-null reference to a ContentHandler.
2007         *
2008         * @throws org.xml.sax.SAXException
2009         */
2010        public void dispatchCharactersEvents(
2011                                                                                                                                                        int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
2012        throws org.xml.sax.SAXException {}
2013
2014        /**
2015         * Directly create SAX parser events from a subtree.
2016         *
2017         * @param nodeHandle The node ID.
2018         * @param ch A non-null reference to a ContentHandler.
2019         *
2020         * @throws org.xml.sax.SAXException
2021         */
2022
2023        public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch)
2024        throws org.xml.sax.SAXException {}
2025
2026        /**
2027         * Return an DOM node for the given node.
2028         *
2029         * @param nodeHandle The node ID.
2030         *
2031         * @return A node representation of the DTM node.
2032         */
2033        public org.w3c.dom.Node getNode(int nodeHandle)
2034        {
2035          return null;
2036        }
2037
2038        // ==== Construction methods (may not be supported by some implementations!) =====
2039        // %REVIEW% jjk: These probably aren't the right API. At the very least
2040        // they need to deal with current-insertion-location and end-element
2041        // issues.
2042
2043        /**
2044         * Append a child to the end of the child list of the current node. Please note that the node
2045         * is always cloned if it is owned by another document.
2046         *
2047         * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2048         * Does it become the last child of the Document? Of the root element?</p>
2049         *
2050         * @param newChild Must be a valid new node handle.
2051         * @param clone true if the child should be cloned into the document.
2052         * @param cloneDepth if the clone argument is true, specifies that the
2053         *                   clone should include all it's children.
2054         */
2055        public void appendChild(int newChild, boolean clone, boolean cloneDepth) {
2056                boolean sameDoc = ((newChild & DOCHANDLE_MASK) == m_docHandle);
2057                if (clone || !sameDoc) {
2058
2059                } else {
2060
2061                }
2062        }
2063
2064        /**
2065         * Append a text node child that will be constructed from a string,
2066         * to the end of the document.
2067         *
2068         * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2069         * Does it become the last child of the Document? Of the root element?</p>
2070         *
2071         * @param str Non-null reference to a string.
2072         */
2073        public void appendTextChild(String str) {
2074                // ###shs Think more about how this differs from createTextNode
2075          //%TBD%
2076        }
2077
2078
2079  //================================================================
2080  // ==== BUILDER methods ====
2081  // %TBD% jjk: SHOULD PROBABLY BE INLINED, unless we want to support
2082  // both SAX1 and SAX2 and share this logic between them.
2083
2084  /** Append a text child at the current insertion point. Assumes that the
2085   * actual content of the text has previously been appended to the m_char
2086   * buffer (shared with the builder).
2087   *
2088   * @param m_char_current_start int Starting offset of node's content in m_char.
2089   * @param contentLength int Length of node's content in m_char.
2090   * */
2091  void appendTextChild(int m_char_current_start,int contentLength)
2092  {
2093    // create a Text Node
2094    // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2095    int w0 = TEXT_NODE;
2096    // W1: Parent
2097    int w1 = currentParent;
2098    // W2: Start position within m_char
2099    int w2 = m_char_current_start;
2100    // W3: Length of the full string
2101    int w3 = contentLength;
2102
2103    int ourslot = appendNode(w0, w1, w2, w3);
2104    previousSibling = ourslot;
2105  }
2106
2107  /** Append a comment child at the current insertion point. Assumes that the
2108   * actual content of the comment has previously been appended to the m_char
2109   * buffer (shared with the builder).
2110   *
2111   * @param m_char_current_start int Starting offset of node's content in m_char.
2112   * @param contentLength int Length of node's content in m_char.
2113   * */
2114  void appendComment(int m_char_current_start,int contentLength)
2115  {
2116    // create a Comment Node
2117    // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2118    int w0 = COMMENT_NODE;
2119    // W1: Parent
2120    int w1 = currentParent;
2121    // W2: Start position within m_char
2122    int w2 = m_char_current_start;
2123    // W3: Length of the full string
2124    int w3 = contentLength;
2125
2126    int ourslot = appendNode(w0, w1, w2, w3);
2127    previousSibling = ourslot;
2128  }
2129
2130
2131  /** Append an Element child at the current insertion point. This
2132   * Element then _becomes_ the insertion point; subsequent appends
2133   * become its lastChild until an appendEndElement() call is made.
2134   *
2135   * Assumes that the symbols (local name, namespace URI and prefix)
2136   * have already been added to the pools
2137   *
2138   * Note that this _only_ handles the Element node itself. Attrs and
2139   * namespace nodes are unbundled in the ContentHandler layer
2140   * and appended separately.
2141   *
2142   * @param namespaceIndex: Index within the namespaceURI string pool
2143   * @param localNameIndex Index within the local name string pool
2144   * @param prefixIndex: Index within the prefix string pool
2145   * */
2146  void appendStartElement(int namespaceIndex,int localNameIndex, int prefixIndex)
2147  {
2148                // do document root node creation here on the first element, create nodes for
2149                // this element and its attributes, store the element, namespace, and attritute
2150                // name indexes to the nodes array, keep track of the current node and parent
2151                // element used
2152
2153                // W0  High:  Namespace  Low:  Node Type
2154                int w0 = (namespaceIndex << 16) | ELEMENT_NODE;
2155                // W1: Parent
2156                int w1 = currentParent;
2157                // W2: Next  (initialized as 0)
2158                int w2 = 0;
2159                // W3: Tagname high: prefix Low: local name
2160                int w3 = localNameIndex | prefixIndex<<16;
2161                /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2162
2163                //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
2164                int ourslot = appendNode(w0, w1, w2, w3);
2165                currentParent = ourslot;
2166                previousSibling = 0;
2167
2168                // set the root element pointer when creating the first element node
2169                if (m_docElement == NULL)
2170                        m_docElement = ourslot;
2171  }
2172
2173  /** Append a Namespace Declaration child at the current insertion point.
2174   * Assumes that the symbols (namespace URI and prefix) have already been
2175   * added to the pools
2176   *
2177   * @param prefixIndex: Index within the prefix string pool
2178   * @param namespaceIndex: Index within the namespaceURI string pool
2179   * @param isID: If someone really insists on writing a bad DTD, it is
2180   * theoretically possible for a namespace declaration to also be declared
2181   * as being a node ID. I don't really want to support that stupidity,
2182   * but I'm not sure we can refuse to accept it.
2183   * */
2184  void appendNSDeclaration(int prefixIndex, int namespaceIndex,
2185                           boolean isID)
2186  {
2187    // %REVIEW% I'm assigning this node the "namespace for namespaces"
2188    // which the DOM defined. It is expected that the Namespace spec will
2189    // adopt this as official. It isn't strictly needed since it's implied
2190    // by the nodetype, but for now...
2191
2192    // %REVIEW% Prefix need not be recorded; it's implied too. But
2193    // recording it might simplify the design.
2194
2195    // %TBD% isID is not currently honored.
2196
2197    final int namespaceForNamespaces=m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/");
2198
2199    // W0  High:  Namespace  Low:  Node Type
2200    int w0 = NAMESPACE_NODE | (m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/")<<16);
2201
2202    // W1:  Parent
2203    int w1 = currentParent;
2204    // W2:  CURRENTLY UNUSED -- It's next-sib in attrs, but we have no kids.
2205    int w2 = 0;
2206    // W3:  namespace name
2207    int w3 = namespaceIndex;
2208    // Add node
2209    int ourslot = appendNode(w0, w1, w2, w3);
2210    previousSibling = ourslot;	// Should attributes be previous siblings
2211    previousSiblingWasParent = false;
2212    return ;//(m_docHandle | ourslot);
2213  }
2214
2215  /** Append an Attribute child at the current insertion
2216   * point.  Assumes that the symbols (namespace URI, local name, and
2217   * prefix) have already been added to the pools, and that the content has
2218   * already been appended to m_char. Note that the attribute's content has
2219   * been flattened into a single string; DTM does _NOT_ attempt to model
2220   * the details of entity references within attribute values.
2221   *
2222   * @param namespaceIndex int Index within the namespaceURI string pool
2223   * @param localNameIndex int Index within the local name string pool
2224   * @param prefixIndex int Index within the prefix string pool
2225   * @param isID boolean True if this attribute was declared as an ID
2226   * (for use in supporting getElementByID).
2227   * @param m_char_current_start int Starting offset of node's content in m_char.
2228   * @param contentLength int Length of node's content in m_char.
2229   * */
2230  void appendAttribute(int namespaceIndex, int localNameIndex, int prefixIndex,
2231                       boolean isID,
2232                       int m_char_current_start, int contentLength)
2233  {
2234    // %TBD% isID is not currently honored.
2235
2236    // W0  High:  Namespace  Low:  Node Type
2237    int w0 = ATTRIBUTE_NODE | namespaceIndex<<16;
2238
2239    // W1:  Parent
2240    int w1 = currentParent;
2241    // W2:  Next (not yet resolved)
2242    int w2 = 0;
2243    // W3:  Tagname high: prefix Low: local name
2244    int w3 = localNameIndex | prefixIndex<<16;
2245    /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2246    // Add node
2247    int ourslot = appendNode(w0, w1, w2, w3);
2248    previousSibling = ourslot;	// Should attributes be previous siblings
2249
2250    // Attribute's content is currently appended as a Text Node
2251
2252    // W0: Node Type
2253    w0 = TEXT_NODE;
2254    // W1: Parent
2255    w1 = ourslot;
2256    // W2: Start Position within buffer
2257    w2 = m_char_current_start;
2258    // W3: Length
2259    w3 = contentLength;
2260    appendNode(w0, w1, w2, w3);
2261
2262    // Attrs are Parents
2263    previousSiblingWasParent = true;
2264    return ;//(m_docHandle | ourslot);
2265  }
2266
2267  /**
2268   * This returns a stateless "traverser", that can navigate over an
2269   * XPath axis, though not in document order.
2270   *
2271   * @param axis One of Axes.ANCESTORORSELF, etc.
2272   *
2273   * @return A DTMAxisIterator, or null if the given axis isn't supported.
2274   */
2275  public DTMAxisTraverser getAxisTraverser(final int axis)
2276  {
2277    return null;
2278  }
2279
2280  /**
2281   * This is a shortcut to the iterators that implement the
2282   * supported XPath axes (only namespace::) is not supported.
2283   * Returns a bare-bones iterator that must be initialized
2284   * with a start node (using iterator.setStartNode()).
2285   *
2286   * @param axis One of Axes.ANCESTORORSELF, etc.
2287   *
2288   * @return A DTMAxisIterator, or null if the given axis isn't supported.
2289   */
2290  public DTMAxisIterator getAxisIterator(final int axis)
2291  {
2292    // %TBD%
2293    return null;
2294  }
2295
2296  /**
2297   * Get an iterator that can navigate over an XPath Axis, predicated by
2298   * the extended type ID.
2299   *
2300   *
2301   * @param axis
2302   * @param type An extended type ID.
2303   *
2304   * @return A DTMAxisIterator, or null if the given axis isn't supported.
2305   */
2306  public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
2307  {
2308    // %TBD%
2309    return null;
2310  }
2311
2312
2313  /** Terminate the element currently acting as an insertion point. Subsequent
2314   * insertions will occur as the last child of this element's parent.
2315   * */
2316  void appendEndElement()
2317  {
2318    // pop up the stacks
2319
2320    if (previousSiblingWasParent)
2321      nodes.writeEntry(previousSibling, 2, NULL);
2322
2323    // Pop parentage
2324    previousSibling = currentParent;
2325    nodes.readSlot(currentParent, gotslot);
2326    currentParent = gotslot[1] & 0xFFFF;
2327
2328    // The element just being finished will be
2329    // the previous sibling for the next operation
2330    previousSiblingWasParent = true;
2331
2332    // Pop a level of namespace table
2333    // namespaceTable.removeLastElem();
2334  }
2335
2336  /**  Starting a new document. Perform any resets/initialization
2337   * not already handled.
2338   * */
2339  void appendStartDocument()
2340  {
2341
2342    // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
2343    //       the next initDocument().
2344    m_docElement = NULL;	 // reset nodeHandle to the root of the actual dtm doc content
2345    initDocument(0);
2346  }
2347
2348  /**  All appends to this document have finished; do whatever final
2349   * cleanup is needed.
2350   * */
2351  void appendEndDocument()
2352  {
2353    done = true;
2354    // %TBD% may need to notice the last slot number and slot count to avoid
2355    // residual data from provious use of this DTM
2356  }
2357
2358  /**
2359   * For the moment all the run time properties are ignored by this
2360   * class.
2361   *
2362   * @param property a <code>String</code> value
2363   * @param value an <code>Object</code> value
2364   */
2365  public void setProperty(String property, Object value)
2366  {
2367  }
2368
2369  /**
2370   * Source information is not handled yet, so return
2371   * <code>null</code> here.
2372   *
2373   * @param node an <code>int</code> value
2374   * @return null
2375   */
2376  public SourceLocator getSourceLocatorFor(int node)
2377  {
2378    return null;
2379  }
2380
2381
2382  /**
2383   * A dummy routine to satisify the abstract interface. If the DTM
2384   * implememtation that extends the default base requires notification
2385   * of registration, they can override this method.
2386   */
2387   public void documentRegistration()
2388   {
2389   }
2390
2391  /**
2392   * A dummy routine to satisify the abstract interface. If the DTM
2393   * implememtation that extends the default base requires notification
2394   * when the document is being released, they can override this method
2395   */
2396   public void documentRelease()
2397   {
2398   }
2399
2400   /**
2401    * Migrate a DTM built with an old DTMManager to a new DTMManager.
2402    * After the migration, the new DTMManager will treat the DTM as
2403    * one that is built by itself.
2404    * This is used to support DTM sharing between multiple transformations.
2405    * @param manager the DTMManager
2406    */
2407   public void migrateTo(DTMManager manager)
2408   {
2409   }
2410
2411}
2412