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