1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   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 
  22 package com.sun.org.apache.xml.internal.dtm.ref;
  23 
  24 import javax.xml.transform.SourceLocator;
  25 
  26 import com.sun.org.apache.xml.internal.dtm.DTM;
  27 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  28 import com.sun.org.apache.xml.internal.dtm.DTMAxisTraverser;
  29 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  30 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  31 import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
  32 import com.sun.org.apache.xml.internal.utils.XMLString;
  33 import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
  34 
  35 import org.xml.sax.Attributes;
  36 import org.xml.sax.ContentHandler;
  37 import org.xml.sax.Locator;
  38 import 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  */
  64 public class DTMDocumentImpl
  65 implements 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         @SuppressWarnings("fallthrough")
1701         public String getNodeValue(int nodeHandle)
1702         {
1703                 nodes.readSlot(nodeHandle, gotslot);
1704                 int nodetype=gotslot[0] & 0xFF;         // ###zaj use mask to get node type
1705                 String value=null;
1706 
1707                 switch (nodetype) {                     // ###zaj todo - document nodetypes
1708                 case ATTRIBUTE_NODE:
1709                         nodes.readSlot(nodeHandle+1, gotslot);
1710                 case TEXT_NODE:
1711                 case COMMENT_NODE:
1712                 case CDATA_SECTION_NODE:
1713                         value=m_char.getString(gotslot[2], gotslot[3]);         //###zaj
1714                         break;
1715                 case PROCESSING_INSTRUCTION_NODE:
1716                 case ELEMENT_NODE:
1717                 case ENTITY_REFERENCE_NODE:
1718                 default:
1719                         break;
1720                 }
1721                 return value;
1722         }
1723 
1724         /**
1725          * Given a node handle, return its DOM-style node type.
1726          * <p>
1727          * %REVIEW% Generally, returning short is false economy. Return int?
1728          *
1729          * @param nodeHandle The node id.
1730          * @return int Node type, as per the DOM's Node._NODE constants.
1731          */
1732         public short getNodeType(int nodeHandle) {
1733                 return(short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1734         }
1735 
1736         /**
1737          * Get the depth level of this node in the tree (equals 1 for
1738          * a parentless node).
1739          *
1740          * @param nodeHandle The node id.
1741          * @return the number of ancestors, plus one
1742          * @xsl.usage internal
1743          */
1744         public short getLevel(int nodeHandle) {
1745                 short count = 0;
1746                 while (nodeHandle != 0) {
1747                         count++;
1748                         nodeHandle = nodes.readEntry(nodeHandle, 1);
1749                 }
1750                 return count;
1751         }
1752 
1753         // ============== Document query functions ==============
1754 
1755         /**
1756          * Tests whether DTM DOM implementation implements a specific feature and
1757          * that feature is supported by this node.
1758          *
1759          * @param feature The name of the feature to test.
1760          * @param version This is the version number of the feature to test.
1761          *   If the version is not
1762          *   specified, supporting any version of the feature will cause the
1763          *   method to return <code>true</code>.
1764          * @return Returns <code>true</code> if the specified feature is
1765          *   supported on this node, <code>false</code> otherwise.
1766          */
1767         public boolean isSupported(String feature, String version) {return false;}
1768 
1769         /**
1770          * Return the base URI of the document entity. If it is not known
1771          * (because the document was parsed from a socket connection or from
1772          * standard input, for example), the value of this property is unknown.
1773          *
1774          * @return the document base URI String object or null if unknown.
1775          */
1776         public String getDocumentBaseURI()
1777         {
1778 
1779           return m_documentBaseURI;
1780         }
1781 
1782         /**
1783          * Set the base URI of the document entity.
1784          *
1785          * @param baseURI the document base URI String object or null if unknown.
1786          */
1787         public void setDocumentBaseURI(String baseURI)
1788         {
1789 
1790           m_documentBaseURI = baseURI;
1791         }
1792 
1793         /**
1794          * Return the system identifier of the document entity. If
1795          * it is not known, the value of this property is unknown.
1796          *
1797          * @param nodeHandle The node id, which can be any valid node handle.
1798          * @return the system identifier String object or null if unknown.
1799          */
1800         public String getDocumentSystemIdentifier(int nodeHandle) {return null;}
1801 
1802         /**
1803          * Return the name of the character encoding scheme
1804          *        in which the document entity is expressed.
1805          *
1806          * @param nodeHandle The node id, which can be any valid node handle.
1807          * @return the document encoding String object.
1808          */
1809         public String getDocumentEncoding(int nodeHandle) {return null;}
1810 
1811         /**
1812          * Return an indication of the standalone status of the document,
1813          *        either "yes" or "no". This property is derived from the optional
1814          *        standalone document declaration in the XML declaration at the
1815          *        beginning of the document entity, and has no value if there is no
1816          *        standalone document declaration.
1817          *
1818          * @param nodeHandle The node id, which can be any valid node handle.
1819          * @return the document standalone String object, either "yes", "no", or null.
1820          */
1821         public String getDocumentStandalone(int nodeHandle) {return null;}
1822 
1823         /**
1824          * Return a string representing the XML version of the document. This
1825          * property is derived from the XML declaration optionally present at the
1826          * beginning of the document entity, and has no value if there is no XML
1827          * declaration.
1828          *
1829          * @param documentHandle the document handle
1830          *
1831          * @return the document version String object
1832          */
1833         public String getDocumentVersion(int documentHandle) {return null;}
1834 
1835         /**
1836          * Return an indication of
1837          * whether the processor has read the complete DTD. Its value is a
1838          * boolean. If it is false, then certain properties (indicated in their
1839          * descriptions below) may be unknown. If it is true, those properties
1840          * are never unknown.
1841          *
1842          * @return <code>true</code> if all declarations were processed {};
1843          *         <code>false</code> otherwise.
1844          */
1845         public boolean getDocumentAllDeclarationsProcessed() {return false;}
1846 
1847         /**
1848          *   A document type declaration information item has the following properties:
1849          *
1850          *     1. [system identifier] The system identifier of the external subset, if
1851          *        it exists. Otherwise this property has no value.
1852          *
1853          * @return the system identifier String object, or null if there is none.
1854          */
1855         public String getDocumentTypeDeclarationSystemIdentifier() {return null;}
1856 
1857         /**
1858          * Return the public identifier of the external subset,
1859          * normalized as described in 4.2.2 External Entities [XML]. If there is
1860          * no external subset or if it has no public identifier, this property
1861          * has no value.
1862          *
1863          * @return the public identifier String object, or null if there is none.
1864          */
1865         public String getDocumentTypeDeclarationPublicIdentifier() {return null;}
1866 
1867         /**
1868          * Returns the <code>Element</code> whose <code>ID</code> is given by
1869          * <code>elementId</code>. If no such element exists, returns
1870          * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1871          * has this <code>ID</code>. Attributes (including those
1872          * with the name "ID") are not of type ID unless so defined by DTD/Schema
1873          * information available to the DTM implementation.
1874          * Implementations that do not know whether attributes are of type ID or
1875          * not are expected to return <code>DTM.NULL</code>.
1876          *
1877          * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1878          * and this operation searches only within a single document, right?
1879          * Wouldn't want collisions between DTMs in the same process.</p>
1880          *
1881          * @param elementId The unique <code>id</code> value for an element.
1882          * @return The handle of the matching element.
1883          */
1884         public int getElementById(String elementId) {return 0;}
1885 
1886         /**
1887          * The getUnparsedEntityURI function returns the URI of the unparsed
1888          * entity with the specified name in the same document as the context
1889          * node (see [3.3 Unparsed Entities]). It returns the empty string if
1890          * there is no such entity.
1891          * <p>
1892          * XML processors may choose to use the System Identifier (if one
1893          * is provided) to resolve the entity, rather than the URI in the
1894          * Public Identifier. The details are dependent on the processor, and
1895          * we would have to support some form of plug-in resolver to handle
1896          * this properly. Currently, we simply return the System Identifier if
1897          * present, and hope that it a usable URI or that our caller can
1898          * map it to one.
1899          * TODO: Resolve Public Identifiers... or consider changing function name.
1900          * <p>
1901          * If we find a relative URI
1902          * reference, XML expects it to be resolved in terms of the base URI
1903          * of the document. The DOM doesn't do that for us, and it isn't
1904          * entirely clear whether that should be done here; currently that's
1905          * pushed up to a higher level of our application. (Note that DOM Level
1906          * 1 didn't store the document's base URI.)
1907          * TODO: Consider resolving Relative URIs.
1908          * <p>
1909          * (The DOM's statement that "An XML processor may choose to
1910          * completely expand entities before the structure model is passed
1911          * to the DOM" refers only to parsed entities, not unparsed, and hence
1912          * doesn't affect this function.)
1913          *
1914          * @param name A string containing the Entity Name of the unparsed
1915          * entity.
1916          *
1917          * @return String containing the URI of the Unparsed Entity, or an
1918          * empty string if no such entity exists.
1919          */
1920         public String getUnparsedEntityURI(String name) {return null;}
1921 
1922 
1923         // ============== Boolean methods ================
1924 
1925         /**
1926          * Return true if the xsl:strip-space or xsl:preserve-space was processed
1927          * during construction of the DTM document.
1928          *
1929          * <p>%REVEIW% Presumes a 1:1 mapping from DTM to Document, since
1930          * we aren't saying which Document to query...?</p>
1931          */
1932         public boolean supportsPreStripping() {return false;}
1933 
1934         /**
1935          * Figure out whether nodeHandle2 should be considered as being later
1936          * in the document than nodeHandle1, in Document Order as defined
1937          * by the XPath model. This may not agree with the ordering defined
1938          * by other XML applications.
1939          * <p>
1940          * There are some cases where ordering isn't defined, and neither are
1941          * the results of this function -- though we'll generally return true.
1942          *
1943          * TODO: Make sure this does the right thing with attribute nodes!!!
1944          *
1945          * @param nodeHandle1 DOM Node to perform position comparison on.
1946          * @param nodeHandle2 DOM Node to perform position comparison on .
1947          *
1948          * @return false if node2 comes before node1, otherwise return true.
1949          * You can think of this as
1950          * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
1951          */
1952         public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {return false;}
1953 
1954         /**
1955          *     2. [element content whitespace] A boolean indicating whether the
1956          *        character is white space appearing within element content (see [XML],
1957          *        2.10 "White Space Handling"). Note that validating XML processors are
1958          *        required by XML 1.0 to provide this information. If there is no
1959          *        declaration for the containing element, this property has no value for
1960          *        white space characters. If no declaration has been read, but the [all
1961          *        declarations processed] property of the document information item is
1962          *        false (so there may be an unread declaration), then the value of this
1963          *        property is unknown for white space characters. It is always false for
1964          *        characters that are not white space.
1965          *
1966          * @param nodeHandle the node ID.
1967          * @return <code>true</code> if the character data is whitespace;
1968          *         <code>false</code> otherwise.
1969          */
1970         public boolean isCharacterElementContentWhitespace(int nodeHandle) {return false;}
1971 
1972         /**
1973          *    10. [all declarations processed] This property is not strictly speaking
1974          *        part of the infoset of the document. Rather it is an indication of
1975          *        whether the processor has read the complete DTD. Its value is a
1976          *        boolean. If it is false, then certain properties (indicated in their
1977          *        descriptions below) may be unknown. If it is true, those properties
1978          *        are never unknown.
1979          *
1980          * @param documentHandle A node handle that must identify a document.
1981          * @return <code>true</code> if all declarations were processed;
1982          *         <code>false</code> otherwise.
1983          */
1984         public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {return false;}
1985 
1986         /**
1987          *     5. [specified] A flag indicating whether this attribute was actually
1988          *        specified in the start-tag of its element, or was defaulted from the
1989          *        DTD.
1990          *
1991          * @param attributeHandle the attribute handle
1992          * @return <code>true</code> if the attribute was specified;
1993          *         <code>false</code> if it was defaulted.
1994          */
1995         public boolean isAttributeSpecified(int attributeHandle) {return false;}
1996 
1997         // ========== Direct SAX Dispatch, for optimization purposes ========
1998 
1999         /**
2000          * Directly call the
2001          * characters method on the passed ContentHandler for the
2002          * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2003          * for the definition of a node's string-value). Multiple calls to the
2004          * ContentHandler's characters methods may well occur for a single call to
2005          * this method.
2006          *
2007          * @param nodeHandle The node ID.
2008          * @param ch A non-null reference to a ContentHandler.
2009          *
2010          * @throws org.xml.sax.SAXException
2011          */
2012         public void dispatchCharactersEvents(
2013                                                                                                                                                         int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
2014         throws org.xml.sax.SAXException {}
2015 
2016         /**
2017          * Directly create SAX parser events from a subtree.
2018          *
2019          * @param nodeHandle The node ID.
2020          * @param ch A non-null reference to a ContentHandler.
2021          *
2022          * @throws org.xml.sax.SAXException
2023          */
2024 
2025         public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch)
2026         throws org.xml.sax.SAXException {}
2027 
2028         /**
2029          * Return an DOM node for the given node.
2030          *
2031          * @param nodeHandle The node ID.
2032          *
2033          * @return A node representation of the DTM node.
2034          */
2035         public org.w3c.dom.Node getNode(int nodeHandle)
2036         {
2037           return null;
2038         }
2039 
2040         // ==== Construction methods (may not be supported by some implementations!) =====
2041         // %REVIEW% jjk: These probably aren't the right API. At the very least
2042         // they need to deal with current-insertion-location and end-element
2043         // issues.
2044 
2045         /**
2046          * Append a child to the end of the child list of the current node. Please note that the node
2047          * is always cloned if it is owned by another document.
2048          *
2049          * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2050          * Does it become the last child of the Document? Of the root element?</p>
2051          *
2052          * @param newChild Must be a valid new node handle.
2053          * @param clone true if the child should be cloned into the document.
2054          * @param cloneDepth if the clone argument is true, specifies that the
2055          *                   clone should include all it's children.
2056          */
2057         public void appendChild(int newChild, boolean clone, boolean cloneDepth) {
2058                 boolean sameDoc = ((newChild & DOCHANDLE_MASK) == m_docHandle);
2059                 if (clone || !sameDoc) {
2060 
2061                 } else {
2062 
2063                 }
2064         }
2065 
2066         /**
2067          * Append a text node child that will be constructed from a string,
2068          * to the end of the document.
2069          *
2070          * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2071          * Does it become the last child of the Document? Of the root element?</p>
2072          *
2073          * @param str Non-null reference to a string.
2074          */
2075         public void appendTextChild(String str) {
2076                 // ###shs Think more about how this differs from createTextNode
2077           //%TBD%
2078         }
2079 
2080 
2081   //================================================================
2082   // ==== BUILDER methods ====
2083   // %TBD% jjk: SHOULD PROBABLY BE INLINED, unless we want to support
2084   // both SAX1 and SAX2 and share this logic between them.
2085 
2086   /** Append a text child at the current insertion point. Assumes that the
2087    * actual content of the text has previously been appended to the m_char
2088    * buffer (shared with the builder).
2089    *
2090    * @param m_char_current_start int Starting offset of node's content in m_char.
2091    * @param contentLength int Length of node's content in m_char.
2092    * */
2093   void appendTextChild(int m_char_current_start,int contentLength)
2094   {
2095     // create a Text Node
2096     // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2097     int w0 = TEXT_NODE;
2098     // W1: Parent
2099     int w1 = currentParent;
2100     // W2: Start position within m_char
2101     int w2 = m_char_current_start;
2102     // W3: Length of the full string
2103     int w3 = contentLength;
2104 
2105     int ourslot = appendNode(w0, w1, w2, w3);
2106     previousSibling = ourslot;
2107   }
2108 
2109   /** Append a comment child at the current insertion point. Assumes that the
2110    * actual content of the comment has previously been appended to the m_char
2111    * buffer (shared with the builder).
2112    *
2113    * @param m_char_current_start int Starting offset of node's content in m_char.
2114    * @param contentLength int Length of node's content in m_char.
2115    * */
2116   void appendComment(int m_char_current_start,int contentLength)
2117   {
2118     // create a Comment Node
2119     // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2120     int w0 = COMMENT_NODE;
2121     // W1: Parent
2122     int w1 = currentParent;
2123     // W2: Start position within m_char
2124     int w2 = m_char_current_start;
2125     // W3: Length of the full string
2126     int w3 = contentLength;
2127 
2128     int ourslot = appendNode(w0, w1, w2, w3);
2129     previousSibling = ourslot;
2130   }
2131 
2132 
2133   /** Append an Element child at the current insertion point. This
2134    * Element then _becomes_ the insertion point; subsequent appends
2135    * become its lastChild until an appendEndElement() call is made.
2136    *
2137    * Assumes that the symbols (local name, namespace URI and prefix)
2138    * have already been added to the pools
2139    *
2140    * Note that this _only_ handles the Element node itself. Attrs and
2141    * namespace nodes are unbundled in the ContentHandler layer
2142    * and appended separately.
2143    *
2144    * @param namespaceIndex: Index within the namespaceURI string pool
2145    * @param localNameIndex Index within the local name string pool
2146    * @param prefixIndex: Index within the prefix string pool
2147    * */
2148   void appendStartElement(int namespaceIndex,int localNameIndex, int prefixIndex)
2149   {
2150                 // do document root node creation here on the first element, create nodes for
2151                 // this element and its attributes, store the element, namespace, and attritute
2152                 // name indexes to the nodes array, keep track of the current node and parent
2153                 // element used
2154 
2155                 // W0  High:  Namespace  Low:  Node Type
2156                 int w0 = (namespaceIndex << 16) | ELEMENT_NODE;
2157                 // W1: Parent
2158                 int w1 = currentParent;
2159                 // W2: Next  (initialized as 0)
2160                 int w2 = 0;
2161                 // W3: Tagname high: prefix Low: local name
2162                 int w3 = localNameIndex | prefixIndex<<16;
2163                 /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2164 
2165                 //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
2166                 int ourslot = appendNode(w0, w1, w2, w3);
2167                 currentParent = ourslot;
2168                 previousSibling = 0;
2169 
2170                 // set the root element pointer when creating the first element node
2171                 if (m_docElement == NULL)
2172                         m_docElement = ourslot;
2173   }
2174 
2175   /** Append a Namespace Declaration child at the current insertion point.
2176    * Assumes that the symbols (namespace URI and prefix) have already been
2177    * added to the pools
2178    *
2179    * @param prefixIndex: Index within the prefix string pool
2180    * @param namespaceIndex: Index within the namespaceURI string pool
2181    * @param isID: If someone really insists on writing a bad DTD, it is
2182    * theoretically possible for a namespace declaration to also be declared
2183    * as being a node ID. I don't really want to support that stupidity,
2184    * but I'm not sure we can refuse to accept it.
2185    * */
2186   void appendNSDeclaration(int prefixIndex, int namespaceIndex,
2187                            boolean isID)
2188   {
2189     // %REVIEW% I'm assigning this node the "namespace for namespaces"
2190     // which the DOM defined. It is expected that the Namespace spec will
2191     // adopt this as official. It isn't strictly needed since it's implied
2192     // by the nodetype, but for now...
2193 
2194     // %REVIEW% Prefix need not be recorded; it's implied too. But
2195     // recording it might simplify the design.
2196 
2197     // %TBD% isID is not currently honored.
2198 
2199     final int namespaceForNamespaces=m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/");
2200 
2201     // W0  High:  Namespace  Low:  Node Type
2202     int w0 = NAMESPACE_NODE | (m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/")<<16);
2203 
2204     // W1:  Parent
2205     int w1 = currentParent;
2206     // W2:  CURRENTLY UNUSED -- It's next-sib in attrs, but we have no kids.
2207     int w2 = 0;
2208     // W3:  namespace name
2209     int w3 = namespaceIndex;
2210     // Add node
2211     int ourslot = appendNode(w0, w1, w2, w3);
2212     previousSibling = ourslot;  // Should attributes be previous siblings
2213     previousSiblingWasParent = false;
2214     return ;//(m_docHandle | ourslot);
2215   }
2216 
2217   /** Append an Attribute child at the current insertion
2218    * point.  Assumes that the symbols (namespace URI, local name, and
2219    * prefix) have already been added to the pools, and that the content has
2220    * already been appended to m_char. Note that the attribute's content has
2221    * been flattened into a single string; DTM does _NOT_ attempt to model
2222    * the details of entity references within attribute values.
2223    *
2224    * @param namespaceIndex int Index within the namespaceURI string pool
2225    * @param localNameIndex int Index within the local name string pool
2226    * @param prefixIndex int Index within the prefix string pool
2227    * @param isID boolean True if this attribute was declared as an ID
2228    * (for use in supporting getElementByID).
2229    * @param m_char_current_start int Starting offset of node's content in m_char.
2230    * @param contentLength int Length of node's content in m_char.
2231    * */
2232   void appendAttribute(int namespaceIndex, int localNameIndex, int prefixIndex,
2233                        boolean isID,
2234                        int m_char_current_start, int contentLength)
2235   {
2236     // %TBD% isID is not currently honored.
2237 
2238     // W0  High:  Namespace  Low:  Node Type
2239     int w0 = ATTRIBUTE_NODE | namespaceIndex<<16;
2240 
2241     // W1:  Parent
2242     int w1 = currentParent;
2243     // W2:  Next (not yet resolved)
2244     int w2 = 0;
2245     // W3:  Tagname high: prefix Low: local name
2246     int w3 = localNameIndex | prefixIndex<<16;
2247     /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2248     // Add node
2249     int ourslot = appendNode(w0, w1, w2, w3);
2250     previousSibling = ourslot;  // Should attributes be previous siblings
2251 
2252     // Attribute's content is currently appended as a Text Node
2253 
2254     // W0: Node Type
2255     w0 = TEXT_NODE;
2256     // W1: Parent
2257     w1 = ourslot;
2258     // W2: Start Position within buffer
2259     w2 = m_char_current_start;
2260     // W3: Length
2261     w3 = contentLength;
2262     appendNode(w0, w1, w2, w3);
2263 
2264     // Attrs are Parents
2265     previousSiblingWasParent = true;
2266     return ;//(m_docHandle | ourslot);
2267   }
2268 
2269   /**
2270    * This returns a stateless "traverser", that can navigate over an
2271    * XPath axis, though not in document order.
2272    *
2273    * @param axis One of Axes.ANCESTORORSELF, etc.
2274    *
2275    * @return A DTMAxisIterator, or null if the given axis isn't supported.
2276    */
2277   public DTMAxisTraverser getAxisTraverser(final int axis)
2278   {
2279     return null;
2280   }
2281 
2282   /**
2283    * This is a shortcut to the iterators that implement the
2284    * supported XPath axes (only namespace::) is not supported.
2285    * Returns a bare-bones iterator that must be initialized
2286    * with a start node (using iterator.setStartNode()).
2287    *
2288    * @param axis One of Axes.ANCESTORORSELF, etc.
2289    *
2290    * @return A DTMAxisIterator, or null if the given axis isn't supported.
2291    */
2292   public DTMAxisIterator getAxisIterator(final int axis)
2293   {
2294     // %TBD%
2295     return null;
2296   }
2297 
2298   /**
2299    * Get an iterator that can navigate over an XPath Axis, predicated by
2300    * the extended type ID.
2301    *
2302    *
2303    * @param axis
2304    * @param type An extended type ID.
2305    *
2306    * @return A DTMAxisIterator, or null if the given axis isn't supported.
2307    */
2308   public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
2309   {
2310     // %TBD%
2311     return null;
2312   }
2313 
2314 
2315   /** Terminate the element currently acting as an insertion point. Subsequent
2316    * insertions will occur as the last child of this element's parent.
2317    * */
2318   void appendEndElement()
2319   {
2320     // pop up the stacks
2321 
2322     if (previousSiblingWasParent)
2323       nodes.writeEntry(previousSibling, 2, NULL);
2324 
2325     // Pop parentage
2326     previousSibling = currentParent;
2327     nodes.readSlot(currentParent, gotslot);
2328     currentParent = gotslot[1] & 0xFFFF;
2329 
2330     // The element just being finished will be
2331     // the previous sibling for the next operation
2332     previousSiblingWasParent = true;
2333 
2334     // Pop a level of namespace table
2335     // namespaceTable.removeLastElem();
2336   }
2337 
2338   /**  Starting a new document. Perform any resets/initialization
2339    * not already handled.
2340    * */
2341   void appendStartDocument()
2342   {
2343 
2344     // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
2345     //       the next initDocument().
2346     m_docElement = NULL;         // reset nodeHandle to the root of the actual dtm doc content
2347     initDocument(0);
2348   }
2349 
2350   /**  All appends to this document have finished; do whatever final
2351    * cleanup is needed.
2352    * */
2353   void appendEndDocument()
2354   {
2355     done = true;
2356     // %TBD% may need to notice the last slot number and slot count to avoid
2357     // residual data from provious use of this DTM
2358   }
2359 
2360   /**
2361    * For the moment all the run time properties are ignored by this
2362    * class.
2363    *
2364    * @param property a <code>String</code> value
2365    * @param value an <code>Object</code> value
2366    */
2367   public void setProperty(String property, Object value)
2368   {
2369   }
2370 
2371   /**
2372    * Source information is not handled yet, so return
2373    * <code>null</code> here.
2374    *
2375    * @param node an <code>int</code> value
2376    * @return null
2377    */
2378   public SourceLocator getSourceLocatorFor(int node)
2379   {
2380     return null;
2381   }
2382 
2383 
2384   /**
2385    * A dummy routine to satisify the abstract interface. If the DTM
2386    * implememtation that extends the default base requires notification
2387    * of registration, they can override this method.
2388    */
2389    public void documentRegistration()
2390    {
2391    }
2392 
2393   /**
2394    * A dummy routine to satisify the abstract interface. If the DTM
2395    * implememtation that extends the default base requires notification
2396    * when the document is being released, they can override this method
2397    */
2398    public void documentRelease()
2399    {
2400    }
2401 
2402    /**
2403     * Migrate a DTM built with an old DTMManager to a new DTMManager.
2404     * After the migration, the new DTMManager will treat the DTM as
2405     * one that is built by itself.
2406     * This is used to support DTM sharing between multiple transformations.
2407     * @param manager the DTMManager
2408     */
2409    public void migrateTo(DTMManager manager)
2410    {
2411    }
2412 
2413 }