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