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