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 
 941       // %REVIEW% Wish I didn't have to perform the pre-test, but
 942       // someone is apparently asking DTMs whether they contain nodes
 943       // which really don't belong to them. That's probably a bug
 944       // which should be fixed, but until it is:
 945       if(m_mgrDefault.m_dtms[whichDTMindex]!=this)
 946         return NULL;
 947       else
 948         return
 949           m_mgrDefault.m_dtm_offsets[whichDTMindex]
 950           | (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
 951     }
 952 
 953     int whichDTMid=m_dtmIdent.indexOf(nodeHandle & DTMManager.IDENT_DTM_DEFAULT);
 954     return (whichDTMid==NULL)
 955       ? NULL
 956       : (whichDTMid << DTMManager.IDENT_DTM_NODE_BITS)
 957       + (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
 958   }
 959 
 960 
 961   /**
 962    * Given a node handle, get the handle of the node's first child.
 963    * If not yet resolved, waits for more nodes to be added to the document and
 964    * tries again.
 965    *
 966    * @param nodeHandle int Handle of the node.
 967    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
 968    */
 969   public int getFirstChild(int nodeHandle)
 970   {
 971 
 972     int identity = makeNodeIdentity(nodeHandle);
 973     int firstChild = _firstch(identity);
 974 
 975     return makeNodeHandle(firstChild);
 976   }
 977 
 978   /**
 979    * Given a node handle, get the handle of the node's first child.
 980    * If not yet resolved, waits for more nodes to be added to the document and
 981    * tries again.
 982    *
 983    * @param nodeHandle int Handle of the node.
 984    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
 985    */
 986   public int getTypedFirstChild(int nodeHandle, int nodeType)
 987   {
 988 
 989     int firstChild, eType;
 990     if (nodeType < DTM.NTYPES) {
 991       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
 992            firstChild != DTM.NULL;
 993            firstChild = _nextsib(firstChild)) {
 994         eType = _exptype(firstChild);
 995         if (eType == nodeType
 996                || (eType >= DTM.NTYPES
 997                       && m_expandedNameTable.getType(eType) == nodeType)) {
 998           return makeNodeHandle(firstChild);
 999         }
1000       }
1001     } else {
1002       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
1003            firstChild != DTM.NULL;
1004            firstChild = _nextsib(firstChild)) {
1005         if (_exptype(firstChild) == nodeType) {
1006           return makeNodeHandle(firstChild);
1007         }
1008       }
1009     }
1010     return DTM.NULL;
1011   }
1012 
1013   /**
1014    * Given a node handle, advance to its last child.
1015    * If not yet resolved, waits for more nodes to be added to the document and
1016    * tries again.
1017    *
1018    * @param nodeHandle int Handle of the node.
1019    * @return int Node-number of last child,
1020    * or DTM.NULL to indicate none exists.
1021    */
1022   public int getLastChild(int nodeHandle)
1023   {
1024 
1025     int identity = makeNodeIdentity(nodeHandle);
1026     int child = _firstch(identity);
1027     int lastChild = DTM.NULL;
1028 
1029     while (child != DTM.NULL)
1030     {
1031       lastChild = child;
1032       child = _nextsib(child);
1033     }
1034 
1035     return makeNodeHandle(lastChild);
1036   }
1037 
1038   /**
1039    * Retrieves an attribute node by by qualified name and namespace URI.
1040    *
1041    * @param nodeHandle int Handle of the node upon which to look up this attribute..
1042    * @param namespaceURI The namespace URI of the attribute to
1043    *   retrieve, or null.
1044    * @param name The local name of the attribute to
1045    *   retrieve.
1046    * @return The attribute node handle with the specified name (
1047    *   <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1048    *   attribute.
1049    */
1050   public abstract int getAttributeNode(int nodeHandle, String namespaceURI,
1051                                        String name);
1052 
1053   /**
1054    * Given a node handle, get the index of the node's first attribute.
1055    *
1056    * @param nodeHandle int Handle of the node.
1057    * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1058    */
1059   public int getFirstAttribute(int nodeHandle)
1060   {
1061     int nodeID = makeNodeIdentity(nodeHandle);
1062 
1063     return makeNodeHandle(getFirstAttributeIdentity(nodeID));
1064   }
1065 
1066   /**
1067    * Given a node identity, get the index of the node's first attribute.
1068    *
1069    * @param identity int identity of the node.
1070    * @return Identity of first attribute, or DTM.NULL to indicate none exists.
1071    */
1072   protected int getFirstAttributeIdentity(int identity) {
1073     int type = _type(identity);
1074 
1075     if (DTM.ELEMENT_NODE == type)
1076     {
1077       // Assume that attributes and namespaces immediately follow the element.
1078       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1079       {
1080 
1081         // Assume this can not be null.
1082         type = _type(identity);
1083 
1084         if (type == DTM.ATTRIBUTE_NODE)
1085         {
1086           return identity;
1087         }
1088         else if (DTM.NAMESPACE_NODE != type)
1089         {
1090           break;
1091         }
1092       }
1093     }
1094 
1095     return DTM.NULL;
1096   }
1097 
1098   /**
1099    * Given a node handle and an expanded type ID, get the index of the node's
1100    * attribute of that type, if any.
1101    *
1102    * @param nodeHandle int Handle of the node.
1103    * @param attType int expanded type ID of the required attribute.
1104    * @return Handle of attribute of the required type, or DTM.NULL to indicate
1105    * none exists.
1106    */
1107   protected int getTypedAttribute(int nodeHandle, int attType) {
1108     int type = getNodeType(nodeHandle);
1109     if (DTM.ELEMENT_NODE == type) {
1110       int identity = makeNodeIdentity(nodeHandle);
1111 
1112       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1113       {
1114         type = _type(identity);
1115 
1116         if (type == DTM.ATTRIBUTE_NODE)
1117         {
1118           if (_exptype(identity) == attType) return makeNodeHandle(identity);
1119         }
1120         else if (DTM.NAMESPACE_NODE != type)
1121         {
1122           break;
1123         }
1124       }
1125     }
1126 
1127     return DTM.NULL;
1128   }
1129 
1130   /**
1131    * Given a node handle, advance to its next sibling.
1132    * If not yet resolved, waits for more nodes to be added to the document and
1133    * tries again.
1134    * @param nodeHandle int Handle of the node.
1135    * @return int Node-number of next sibling,
1136    * or DTM.NULL to indicate none exists.
1137    */
1138   public int getNextSibling(int nodeHandle)
1139   {
1140         if (nodeHandle == DTM.NULL)
1141         return DTM.NULL;
1142     return makeNodeHandle(_nextsib(makeNodeIdentity(nodeHandle)));
1143   }
1144 
1145   /**
1146    * Given a node handle, advance to its next sibling.
1147    * If not yet resolved, waits for more nodes to be added to the document and
1148    * tries again.
1149    * @param nodeHandle int Handle of the node.
1150    * @return int Node-number of next sibling,
1151    * or DTM.NULL to indicate none exists.
1152    */
1153   public int getTypedNextSibling(int nodeHandle, int nodeType)
1154   {
1155         if (nodeHandle == DTM.NULL)
1156         return DTM.NULL;
1157         int node = makeNodeIdentity(nodeHandle);
1158         int eType;
1159         while ((node = _nextsib(node)) != DTM.NULL &&
1160         ((eType = _exptype(node)) != nodeType &&
1161         m_expandedNameTable.getType(eType)!= nodeType));
1162         //_type(node) != nodeType));
1163 
1164     return (node == DTM.NULL ? DTM.NULL : makeNodeHandle(node));
1165   }
1166 
1167   /**
1168    * Given a node handle, find its preceeding sibling.
1169    * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1170    * relatively expensive.
1171    *
1172    * @param nodeHandle the id of the node.
1173    * @return int Node-number of the previous sib,
1174    * or DTM.NULL to indicate none exists.
1175    */
1176   public int getPreviousSibling(int nodeHandle)
1177   {
1178     if (nodeHandle == DTM.NULL)
1179       return DTM.NULL;
1180 
1181     if (m_prevsib != null)
1182       return makeNodeHandle(_prevsib(makeNodeIdentity(nodeHandle)));
1183     else
1184     {
1185       // If the previous sibling array is not built, we get at
1186       // the previous sibling using the parent, firstch and
1187       // nextsib arrays.
1188       int nodeID = makeNodeIdentity(nodeHandle);
1189       int parent = _parent(nodeID);
1190       int node = _firstch(parent);
1191       int result = DTM.NULL;
1192       while (node != nodeID)
1193       {
1194         result = node;
1195         node = _nextsib(node);
1196       }
1197       return makeNodeHandle(result);
1198     }
1199   }
1200 
1201   /**
1202    * Given a node handle, advance to the next attribute.
1203    * If an attr, we advance to
1204    * the next attr on the same node.  If not an attribute, we return NULL.
1205    *
1206    * @param nodeHandle int Handle of the node.
1207    * @return int DTM node-number of the resolved attr,
1208    * or DTM.NULL to indicate none exists.
1209    */
1210   public int getNextAttribute(int nodeHandle) {
1211     int nodeID = makeNodeIdentity(nodeHandle);
1212 
1213     if (_type(nodeID) == DTM.ATTRIBUTE_NODE) {
1214       return makeNodeHandle(getNextAttributeIdentity(nodeID));
1215     }
1216 
1217     return DTM.NULL;
1218   }
1219 
1220   /**
1221    * Given a node identity for an attribute, advance to the next attribute.
1222    *
1223    * @param identity int identity of the attribute node.  This
1224    * <strong>must</strong> be an attribute node.
1225    *
1226    * @return int DTM node-identity of the resolved attr,
1227    * or DTM.NULL to indicate none exists.
1228    *
1229    */
1230   protected int getNextAttributeIdentity(int identity) {
1231     // Assume that attributes and namespace nodes immediately follow the element
1232     while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1233       int type = _type(identity);
1234 
1235       if (type == DTM.ATTRIBUTE_NODE) {
1236         return identity;
1237       } else if (type != DTM.NAMESPACE_NODE) {
1238         break;
1239       }
1240     }
1241 
1242     return DTM.NULL;
1243   }
1244 
1245   /** Lazily created namespace lists. */
1246   private Vector m_namespaceLists = null;  // on demand
1247 
1248 
1249   /** Build table of namespace declaration
1250    * locations during DTM construction. Table is a Vector of
1251    * SuballocatedIntVectors containing the namespace node HANDLES declared at
1252    * that ID, plus an SuballocatedIntVector of the element node INDEXES at which
1253    * these declarations appeared.
1254    *
1255    * NOTE: Since this occurs during model build, nodes will be encountered
1256    * in doucment order and thus the table will be ordered by element,
1257    * permitting binary-search as a possible retrieval optimization.
1258    *
1259    * %REVIEW% Directly managed arrays rather than vectors?
1260    * %REVIEW% Handles or IDs? Given usage, I think handles.
1261    * */
1262   protected void declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex)
1263   {
1264     SuballocatedIntVector nsList=null;
1265     if(m_namespaceDeclSets==null)
1266       {
1267 
1268         // First
1269         m_namespaceDeclSetElements=new SuballocatedIntVector(32);
1270         m_namespaceDeclSetElements.addElement(elementNodeIndex);
1271         m_namespaceDeclSets=new Vector();
1272         nsList=new SuballocatedIntVector(32);
1273         m_namespaceDeclSets.addElement(nsList);
1274       }
1275     else
1276       {
1277         // Most recent. May be -1 (none) if DTM was pruned.
1278         // %OPT% Is there a lastElement() method? Should there be?
1279         int last=m_namespaceDeclSetElements.size()-1;
1280 
1281         if(last>=0 && elementNodeIndex==m_namespaceDeclSetElements.elementAt(last))
1282           {
1283             nsList=(SuballocatedIntVector)m_namespaceDeclSets.elementAt(last);
1284           }
1285       }
1286     if(nsList==null)
1287       {
1288         m_namespaceDeclSetElements.addElement(elementNodeIndex);
1289 
1290         SuballocatedIntVector inherited =
1291                                 findNamespaceContext(_parent(elementNodeIndex));
1292 
1293         if (inherited!=null) {
1294             // %OPT% Count-down might be faster, but debuggability may
1295             // be better this way, and if we ever decide we want to
1296             // keep this ordered by expanded-type...
1297             int isize=inherited.size();
1298 
1299             // Base the size of a new namespace list on the
1300             // size of the inherited list - but within reason!
1301             nsList=new SuballocatedIntVector(Math.max(Math.min(isize+16,2048),
1302                                                       32));
1303 
1304             for(int i=0;i<isize;++i)
1305               {
1306                 nsList.addElement(inherited.elementAt(i));
1307               }
1308         } else {
1309             nsList=new SuballocatedIntVector(32);
1310         }
1311 
1312         m_namespaceDeclSets.addElement(nsList);
1313       }
1314 
1315     // Handle overwriting inherited.
1316     // %OPT% Keep sorted? (By expanded-name rather than by doc order...)
1317     // Downside: Would require insertElementAt if not found,
1318     // which has recopying costs. But these are generally short lists...
1319     int newEType=_exptype(namespaceNodeIndex);
1320 
1321     for(int i=nsList.size()-1;i>=0;--i)
1322       {
1323         if(newEType==getExpandedTypeID(nsList.elementAt(i)))
1324           {
1325             nsList.setElementAt(makeNodeHandle(namespaceNodeIndex),i);
1326             return;
1327           }
1328       }
1329     nsList.addElement(makeNodeHandle(namespaceNodeIndex));
1330   }
1331 
1332   /** Retrieve list of namespace declaration locations
1333      * active at this node. List is an SuballocatedIntVector whose
1334      * entries are the namespace node HANDLES declared at that ID.
1335      *
1336      * %REVIEW% Directly managed arrays rather than vectors?
1337      * %REVIEW% Handles or IDs? Given usage, I think handles.
1338      * */
1339   protected SuballocatedIntVector findNamespaceContext(int elementNodeIndex)
1340   {
1341     if (null!=m_namespaceDeclSetElements)
1342       {
1343         // %OPT% Is binary-search really saving us a lot versus linear?
1344         // (... It may be, in large docs with many NS decls.)
1345         int wouldBeAt=findInSortedSuballocatedIntVector(m_namespaceDeclSetElements,
1346                                             elementNodeIndex);
1347         if(wouldBeAt>=0) // Found it
1348           return (SuballocatedIntVector) m_namespaceDeclSets.elementAt(wouldBeAt);
1349         if(wouldBeAt == -1) // -1-wouldbeat == 0
1350           return null; // Not after anything; definitely not found
1351 
1352         // Not found, but we know where it should have been.
1353         // Search back until we find an ancestor or run out.
1354         wouldBeAt=-1-wouldBeAt;
1355 
1356         // Decrement wouldBeAt to find last possible ancestor
1357         int candidate=m_namespaceDeclSetElements.elementAt(-- wouldBeAt);
1358         int ancestor=_parent(elementNodeIndex);
1359 
1360         // Special case: if the candidate is before the given node, and
1361         // is in the earliest possible position in the document, it
1362         // must have the namespace declarations we're interested in.
1363         if (wouldBeAt == 0 && candidate < ancestor) {
1364           int rootHandle = getDocumentRoot(makeNodeHandle(elementNodeIndex));
1365           int rootID = makeNodeIdentity(rootHandle);
1366           int uppermostNSCandidateID;
1367 
1368           if (getNodeType(rootHandle) == DTM.DOCUMENT_NODE) {
1369             int ch = _firstch(rootID);
1370             uppermostNSCandidateID = (ch != DTM.NULL) ? ch : rootID;
1371           } else {
1372             uppermostNSCandidateID = rootID;
1373           }
1374 
1375           if (candidate == uppermostNSCandidateID) {
1376             return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt);
1377           }
1378         }
1379 
1380         while(wouldBeAt>=0 && ancestor>0)
1381           {
1382             if (candidate==ancestor) {
1383                 // Found ancestor in list
1384                 return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt);
1385             } else if (candidate<ancestor) {
1386                 // Too deep in tree
1387                 do {
1388                   ancestor=_parent(ancestor);
1389                 } while (candidate < ancestor);
1390             } else if(wouldBeAt > 0){
1391               // Too late in list
1392               candidate=m_namespaceDeclSetElements.elementAt(--wouldBeAt);
1393             }
1394             else
1395                 break;
1396           }
1397       }
1398 
1399     return null; // No namespaces known at this node
1400   }
1401 
1402   /**
1403      * Subroutine: Locate the specified node within
1404      * m_namespaceDeclSetElements, or the last element which
1405      * preceeds it in document order
1406      *
1407      * %REVIEW% Inlne this into findNamespaceContext? Create SortedSuballocatedIntVector type?
1408      *
1409      * @return If positive or zero, the index of the found item.
1410      * If negative, index of the point at which it would have appeared,
1411      * encoded as -1-index and hence reconvertable by subtracting
1412      * it from -1. (Encoding because I don't want to recompare the strings
1413      * but don't want to burn bytes on a datatype to hold a flagged value.)
1414      */
1415   protected int findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor)
1416   {
1417     // Binary search
1418     int i = 0;
1419     if(vector != null) {
1420       int first = 0;
1421       int last  = vector.size() - 1;
1422 
1423       while (first <= last) {
1424         i = (first + last) / 2;
1425         int test = lookfor-vector.elementAt(i);
1426         if(test == 0) {
1427           return i; // Name found
1428         }
1429         else if (test < 0) {
1430           last = i - 1; // looked too late
1431         }
1432         else {
1433           first = i + 1; // looked ot early
1434         }
1435       }
1436 
1437       if (first > i) {
1438         i = first; // Clean up at loop end
1439       }
1440     }
1441 
1442     return -1 - i; // not-found has to be encoded.
1443   }
1444 
1445 
1446   /**
1447    * Given a node handle, get the index of the node's first child.
1448    * If not yet resolved, waits for more nodes to be added to the document and
1449    * tries again
1450    *
1451    * @param nodeHandle handle to node, which should probably be an element
1452    *                   node, but need not be.
1453    *
1454    * @param inScope    true if all namespaces in scope should be returned,
1455    *                   false if only the namespace declarations should be
1456    *                   returned.
1457    * @return handle of first namespace, or DTM.NULL to indicate none exists.
1458    */
1459   public int getFirstNamespaceNode(int nodeHandle, boolean inScope)
1460   {
1461         if(inScope)
1462         {
1463             int identity = makeNodeIdentity(nodeHandle);
1464             if (_type(identity) == DTM.ELEMENT_NODE)
1465             {
1466               SuballocatedIntVector nsContext=findNamespaceContext(identity);
1467               if(nsContext==null || nsContext.size()<1)
1468                 return NULL;
1469 
1470               return nsContext.elementAt(0);
1471             }
1472             else
1473               return NULL;
1474           }
1475         else
1476           {
1477             // Assume that attributes and namespaces immediately
1478             // follow the element.
1479             //
1480             // %OPT% Would things be faster if all NS nodes were built
1481             // before all Attr nodes? Some costs at build time for 2nd
1482             // pass...
1483             int identity = makeNodeIdentity(nodeHandle);
1484             if (_type(identity) == DTM.ELEMENT_NODE)
1485             {
1486               while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1487               {
1488                 int type = _type(identity);
1489                 if (type == DTM.NAMESPACE_NODE)
1490                     return makeNodeHandle(identity);
1491                 else if (DTM.ATTRIBUTE_NODE != type)
1492                     break;
1493               }
1494               return NULL;
1495             }
1496             else
1497               return NULL;
1498           }
1499   }
1500 
1501   /**
1502    * Given a namespace handle, advance to the next namespace.
1503    *
1504    * @param baseHandle handle to original node from where the first namespace
1505    * was relative to (needed to return nodes in document order).
1506    * @param nodeHandle A namespace handle for which we will find the next node.
1507    * @param inScope true if all namespaces that are in scope should be processed,
1508    * otherwise just process the nodes in the given element handle.
1509    * @return handle of next namespace, or DTM.NULL to indicate none exists.
1510    */
1511   public int getNextNamespaceNode(int baseHandle, int nodeHandle,
1512                                   boolean inScope)
1513   {
1514         if(inScope)
1515           {
1516             //Since we've been given the base, try direct lookup
1517             //(could look from nodeHandle but this is at least one
1518             //comparison/get-parent faster)
1519             //SuballocatedIntVector nsContext=findNamespaceContext(nodeHandle & m_mask);
1520 
1521                 SuballocatedIntVector nsContext=findNamespaceContext(makeNodeIdentity(baseHandle));
1522 
1523             if(nsContext==null)
1524               return NULL;
1525             int i=1 + nsContext.indexOf(nodeHandle);
1526             if(i<=0 || i==nsContext.size())
1527               return NULL;
1528 
1529             return nsContext.elementAt(i);
1530           }
1531         else
1532           {
1533             // Assume that attributes and namespace nodes immediately follow the element.
1534             int identity = makeNodeIdentity(nodeHandle);
1535             while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1536               {
1537                 int type = _type(identity);
1538                 if (type == DTM.NAMESPACE_NODE)
1539                   {
1540                     return makeNodeHandle(identity);
1541                   }
1542                 else if (type != DTM.ATTRIBUTE_NODE)
1543                   {
1544                     break;
1545                   }
1546               }
1547           }
1548      return DTM.NULL;
1549   }
1550 
1551   /**
1552    * Given a node handle, find its parent node.
1553    *
1554    * @param nodeHandle the id of the node.
1555    * @return int Node-number of parent,
1556    * or DTM.NULL to indicate none exists.
1557    */
1558   public int getParent(int nodeHandle)
1559   {
1560 
1561     int identity = makeNodeIdentity(nodeHandle);
1562 
1563     if (identity > 0)
1564       return makeNodeHandle(_parent(identity));
1565     else
1566       return DTM.NULL;
1567   }
1568 
1569   /**
1570    * Find the Document node handle for the document currently under construction.
1571    * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle) instead;
1572    * this version of the operation is primarily intended for use during negotiation
1573    * with the DTM Manager.
1574    *
1575    *  @return int Node handle of document, which should always be valid.
1576    */
1577   public int getDocument()
1578   {
1579     return m_dtmIdent.elementAt(0); // makeNodeHandle(0)
1580   }
1581 
1582   /**
1583    * Given a node handle, find the owning document node.  This has the exact
1584    * same semantics as the DOM Document method of the same name, in that if
1585    * the nodeHandle is a document node, it will return NULL.
1586    *
1587    * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1588    * binding layer. Included here as a convenience function and to
1589    * aid porting of DOM code to DTM.</p>
1590    *
1591    * @param nodeHandle the id of the node.
1592    * @return int Node handle of owning document, or -1 if the node was a Docment
1593    */
1594   public int getOwnerDocument(int nodeHandle)
1595   {
1596 
1597     if (DTM.DOCUMENT_NODE == getNodeType(nodeHandle))
1598             return DTM.NULL;
1599 
1600     return getDocumentRoot(nodeHandle);
1601   }
1602 
1603   /**
1604    * Given a node handle, find the owning document node.  Unlike the DOM,
1605    * this considers the owningDocument of a Document to be itself.
1606    *
1607    * @param nodeHandle the id of the node.
1608    * @return int Node handle of owning document, or the nodeHandle if it is
1609    *             a Document.
1610    */
1611   public int getDocumentRoot(int nodeHandle)
1612   {
1613     return getManager().getDTM(nodeHandle).getDocument();
1614   }
1615 
1616   /**
1617    * Get the string-value of a node as a String object
1618    * (see http://www.w3.org/TR/xpath#data-model
1619    * for the definition of a node's string-value).
1620    *
1621    * @param nodeHandle The node ID.
1622    *
1623    * @return A string object that represents the string-value of the given node.
1624    */
1625   public abstract XMLString getStringValue(int nodeHandle);
1626 
1627   /**
1628    * Get number of character array chunks in
1629    * the string-value of a node.
1630    * (see http://www.w3.org/TR/xpath#data-model
1631    * for the definition of a node's string-value).
1632    * Note that a single text node may have multiple text chunks.
1633    *
1634    * @param nodeHandle The node ID.
1635    *
1636    * @return number of character array chunks in
1637    *         the string-value of a node.
1638    */
1639   public int getStringValueChunkCount(int nodeHandle)
1640   {
1641 
1642     // %TBD%
1643     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//("getStringValueChunkCount not yet supported!");
1644 
1645     return 0;
1646   }
1647 
1648   /**
1649    * Get a character array chunk in the string-value of a node.
1650    * (see http://www.w3.org/TR/xpath#data-model
1651    * for the definition of a node's string-value).
1652    * Note that a single text node may have multiple text chunks.
1653    *
1654    * @param nodeHandle The node ID.
1655    * @param chunkIndex Which chunk to get.
1656    * @param startAndLen An array of 2 where the start position and length of
1657    *                    the chunk will be returned.
1658    *
1659    * @return The character array reference where the chunk occurs.
1660    */
1661   public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1662                                     int[] startAndLen)
1663   {
1664 
1665     // %TBD%
1666     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"getStringValueChunk not yet supported!");
1667 
1668     return null;
1669   }
1670 
1671   /**
1672    * Given a node handle, return an ID that represents the node's expanded name.
1673    *
1674    * @param nodeHandle The handle to the node in question.
1675    *
1676    * @return the expanded-name id of the node.
1677    */
1678   public int getExpandedTypeID(int nodeHandle)
1679   {
1680     // %REVIEW% This _should_ only be null if someone asked the wrong DTM about the node...
1681     // which one would hope would never happen...
1682     int id=makeNodeIdentity(nodeHandle);
1683     if(id==NULL)
1684       return NULL;
1685     return _exptype(id);
1686   }
1687 
1688   /**
1689    * Given an expanded name, return an ID.  If the expanded-name does not
1690    * exist in the internal tables, the entry will be created, and the ID will
1691    * be returned.  Any additional nodes that are created that have this
1692    * expanded name will use this ID.
1693    *
1694    * @param type The simple type, i.e. one of ELEMENT, ATTRIBUTE, etc.
1695    *
1696    * @param namespace The namespace URI, which may be null, may be an empty
1697    *                  string (which will be the same as null), or may be a
1698    *                  namespace URI.
1699    * @param localName The local name string, which must be a valid
1700    *                  <a href="http://www.w3.org/TR/REC-xml-names/">NCName</a>.
1701    *
1702    * @return the expanded-name id of the node.
1703    */
1704   public int getExpandedTypeID(String namespace, String localName, int type)
1705   {
1706 
1707     ExpandedNameTable ent = m_expandedNameTable;
1708 
1709     return ent.getExpandedTypeID(namespace, localName, type);
1710   }
1711 
1712   /**
1713    * Given an expanded-name ID, return the local name part.
1714    *
1715    * @param expandedNameID an ID that represents an expanded-name.
1716    * @return String Local name of this node.
1717    */
1718   public String getLocalNameFromExpandedNameID(int expandedNameID)
1719   {
1720     return m_expandedNameTable.getLocalName(expandedNameID);
1721   }
1722 
1723   /**
1724    * Given an expanded-name ID, return the namespace URI part.
1725    *
1726    * @param expandedNameID an ID that represents an expanded-name.
1727    * @return String URI value of this node's namespace, or null if no
1728    * namespace was resolved.
1729    */
1730   public String getNamespaceFromExpandedNameID(int expandedNameID)
1731   {
1732     return m_expandedNameTable.getNamespace(expandedNameID);
1733   }
1734 
1735   /**
1736    * Returns the namespace type of a specific node
1737    * @param nodeHandle the id of the node.
1738    * @return the ID of the namespace.
1739    */
1740   public int getNamespaceType(final int nodeHandle)
1741   {
1742 
1743     int identity = makeNodeIdentity(nodeHandle);
1744     int expandedNameID = _exptype(identity);
1745 
1746     return m_expandedNameTable.getNamespaceID(expandedNameID);
1747   }
1748 
1749   /**
1750    * Given a node handle, return its DOM-style node name. This will
1751    * include names such as #text or #document.
1752    *
1753    * @param nodeHandle the id of the node.
1754    * @return String Name of this node, which may be an empty string.
1755    * %REVIEW% Document when empty string is possible...
1756    * %REVIEW-COMMENT% It should never be empty, should it?
1757    */
1758   public abstract String getNodeName(int nodeHandle);
1759 
1760   /**
1761    * Given a node handle, return the XPath node name.  This should be
1762    * the name as described by the XPath data model, NOT the DOM-style
1763    * name.
1764    *
1765    * @param nodeHandle the id of the node.
1766    * @return String Name of this node, which may be an empty string.
1767    */
1768   public String getNodeNameX(int nodeHandle)
1769   {
1770 
1771     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMDefaultBase abstract method */
1772     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
1773 
1774     return null;
1775   }
1776 
1777   /**
1778    * Given a node handle, return its XPath-style localname.
1779    * (As defined in Namespaces, this is the portion of the name after any
1780    * colon character).
1781    *
1782    * @param nodeHandle the id of the node.
1783    * @return String Local name of this node.
1784    */
1785   public abstract String getLocalName(int nodeHandle);
1786 
1787   /**
1788    * Given a namespace handle, return the prefix that the namespace decl is
1789    * mapping.
1790    * Given a node handle, return the prefix used to map to the namespace.
1791    *
1792    * <p> %REVIEW% Are you sure you want "" for no prefix?  </p>
1793    * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb  </p>
1794    *
1795    * @param nodeHandle the id of the node.
1796    * @return String prefix of this node's name, or "" if no explicit
1797    * namespace prefix was given.
1798    */
1799   public abstract String getPrefix(int nodeHandle);
1800 
1801   /**
1802    * Given a node handle, return its DOM-style namespace URI
1803    * (As defined in Namespaces, this is the declared URI which this node's
1804    * prefix -- or default in lieu thereof -- was mapped to.)
1805    *
1806    * <p>%REVIEW% Null or ""? -sb</p>
1807    *
1808    * @param nodeHandle the id of the node.
1809    * @return String URI value of this node's namespace, or null if no
1810    * namespace was resolved.
1811    */
1812   public abstract String getNamespaceURI(int nodeHandle);
1813 
1814   /**
1815    * Given a node handle, return its node value. This is mostly
1816    * as defined by the DOM, but may ignore some conveniences.
1817    * <p>
1818    *
1819    * @param nodeHandle The node id.
1820    * @return String Value of this node, or null if not
1821    * meaningful for this node type.
1822    */
1823   public abstract String getNodeValue(int nodeHandle);
1824 
1825   /**
1826    * Given a node handle, return its DOM-style node type.
1827    * <p>
1828    * %REVIEW% Generally, returning short is false economy. Return int?
1829    * %REVIEW% Make assumption that node has already arrived.  Is OK?
1830    *
1831    * @param nodeHandle The node id.
1832    * @return int Node type, as per the DOM's Node._NODE constants.
1833    */
1834   public short getNodeType(int nodeHandle)
1835   {
1836         if (nodeHandle == DTM.NULL)
1837         return DTM.NULL;
1838     return m_expandedNameTable.getType(_exptype(makeNodeIdentity(nodeHandle)));
1839   }
1840 
1841   /**
1842    * Get the depth level of this node in the tree (equals 1 for
1843    * a parentless node).
1844    *
1845    * @param nodeHandle The node id.
1846    * @return the number of ancestors, plus one
1847    * @xsl.usage internal
1848    */
1849   public short getLevel(int nodeHandle)
1850   {
1851     // Apparently, the axis walker stuff requires levels to count from 1.
1852     int identity = makeNodeIdentity(nodeHandle);
1853     return (short) (_level(identity) + 1);
1854   }
1855 
1856   /**
1857    * Get the identity of this node in the tree
1858    *
1859    * @param nodeHandle The node handle.
1860    * @return the node identity
1861    * @xsl.usage internal
1862    */
1863   public int getNodeIdent(int nodeHandle)
1864   {
1865     /*if (nodeHandle != DTM.NULL)
1866       return nodeHandle & m_mask;
1867     else
1868       return DTM.NULL;*/
1869 
1870       return makeNodeIdentity(nodeHandle);
1871   }
1872 
1873   /**
1874    * Get the handle of this node in the tree
1875    *
1876    * @param nodeId The node identity.
1877    * @return the node handle
1878    * @xsl.usage internal
1879    */
1880   public int getNodeHandle(int nodeId)
1881   {
1882     /*if (nodeId != DTM.NULL)
1883       return nodeId | m_dtmIdent;
1884     else
1885       return DTM.NULL;*/
1886 
1887       return makeNodeHandle(nodeId);
1888   }
1889 
1890   // ============== Document query functions ==============
1891 
1892   /**
1893    * Tests whether DTM DOM implementation implements a specific feature and
1894    * that feature is supported by this node.
1895    *
1896    * @param feature The name of the feature to test.
1897    * @param version This is the version number of the feature to test.
1898    *   If the version is not
1899    *   specified, supporting any version of the feature will cause the
1900    *   method to return <code>true</code>.
1901    * @return Returns <code>true</code> if the specified feature is
1902    *   supported on this node, <code>false</code> otherwise.
1903    */
1904   public boolean isSupported(String feature, String version)
1905   {
1906 
1907     // %TBD%
1908     return false;
1909   }
1910 
1911   /**
1912    * Return the base URI of the document entity. If it is not known
1913    * (because the document was parsed from a socket connection or from
1914    * standard input, for example), the value of this property is unknown.
1915    *
1916    * @return the document base URI String object or null if unknown.
1917    */
1918   public String getDocumentBaseURI()
1919   {
1920     return m_documentBaseURI;
1921   }
1922 
1923   /**
1924    * Set the base URI of the document entity.
1925    *
1926    * @param baseURI the document base URI String object or null if unknown.
1927    */
1928   public void setDocumentBaseURI(String baseURI)
1929   {
1930     m_documentBaseURI = baseURI;
1931   }
1932 
1933   /**
1934    * Return the system identifier of the document entity. If
1935    * it is not known, the value of this property is unknown.
1936    *
1937    * @param nodeHandle The node id, which can be any valid node handle.
1938    * @return the system identifier String object or null if unknown.
1939    */
1940   public String getDocumentSystemIdentifier(int nodeHandle)
1941   {
1942 
1943     // %REVIEW%  OK? -sb
1944     return m_documentBaseURI;
1945   }
1946 
1947   /**
1948    * Return the name of the character encoding scheme
1949    *        in which the document entity is expressed.
1950    *
1951    * @param nodeHandle The node id, which can be any valid node handle.
1952    * @return the document encoding String object.
1953    * @xsl.usage internal
1954    */
1955   public String getDocumentEncoding(int nodeHandle)
1956   {
1957 
1958     // %REVIEW%  OK??  -sb
1959     return "UTF-8";
1960   }
1961 
1962   /**
1963    * Return an indication of the standalone status of the document,
1964    *        either "yes" or "no". This property is derived from the optional
1965    *        standalone document declaration in the XML declaration at the
1966    *        beginning of the document entity, and has no value if there is no
1967    *        standalone document declaration.
1968    *
1969    * @param nodeHandle The node id, which can be any valid node handle.
1970    * @return the document standalone String object, either "yes", "no", or null.
1971    */
1972   public String getDocumentStandalone(int nodeHandle)
1973   {
1974     return null;
1975   }
1976 
1977   /**
1978    * Return a string representing the XML version of the document. This
1979    * property is derived from the XML declaration optionally present at the
1980    * beginning of the document entity, and has no value if there is no XML
1981    * declaration.
1982    *
1983    * @param documentHandle The document handle
1984    *
1985    * @return the document version String object.
1986    */
1987   public String getDocumentVersion(int documentHandle)
1988   {
1989     return null;
1990   }
1991 
1992   /**
1993    * Return an indication of
1994    * whether the processor has read the complete DTD. Its value is a
1995    * boolean. If it is false, then certain properties (indicated in their
1996    * descriptions below) may be unknown. If it is true, those properties
1997    * are never unknown.
1998    *
1999    * @return <code>true</code> if all declarations were processed;
2000    *         <code>false</code> otherwise.
2001    */
2002   public boolean getDocumentAllDeclarationsProcessed()
2003   {
2004 
2005     // %REVIEW% OK?
2006     return true;
2007   }
2008 
2009   /**
2010    *   A document type declaration information item has the following properties:
2011    *
2012    *     1. [system identifier] The system identifier of the external subset, if
2013    *        it exists. Otherwise this property has no value.
2014    *
2015    * @return the system identifier String object, or null if there is none.
2016    */
2017   public abstract String getDocumentTypeDeclarationSystemIdentifier();
2018 
2019   /**
2020    * Return the public identifier of the external subset,
2021    * normalized as described in 4.2.2 External Entities [XML]. If there is
2022    * no external subset or if it has no public identifier, this property
2023    * has no value.
2024    *
2025    * @return the public identifier String object, or null if there is none.
2026    */
2027   public abstract String getDocumentTypeDeclarationPublicIdentifier();
2028 
2029   /**
2030    * Returns the <code>Element</code> whose <code>ID</code> is given by
2031    * <code>elementId</code>. If no such element exists, returns
2032    * <code>DTM.NULL</code>. Behavior is not defined if more than one element
2033    * has this <code>ID</code>. Attributes (including those
2034    * with the name "ID") are not of type ID unless so defined by DTD/Schema
2035    * information available to the DTM implementation.
2036    * Implementations that do not know whether attributes are of type ID or
2037    * not are expected to return <code>DTM.NULL</code>.
2038    *
2039    * <p>%REVIEW% Presumably IDs are still scoped to a single document,
2040    * and this operation searches only within a single document, right?
2041    * Wouldn't want collisions between DTMs in the same process.</p>
2042    *
2043    * @param elementId The unique <code>id</code> value for an element.
2044    * @return The handle of the matching element.
2045    */
2046   public abstract int getElementById(String elementId);
2047 
2048   /**
2049    * The getUnparsedEntityURI function returns the URI of the unparsed
2050    * entity with the specified name in the same document as the context
2051    * node (see [3.3 Unparsed Entities]). It returns the empty string if
2052    * there is no such entity.
2053    * <p>
2054    * XML processors may choose to use the System Identifier (if one
2055    * is provided) to resolve the entity, rather than the URI in the
2056    * Public Identifier. The details are dependent on the processor, and
2057    * we would have to support some form of plug-in resolver to handle
2058    * this properly. Currently, we simply return the System Identifier if
2059    * present, and hope that it a usable URI or that our caller can
2060    * map it to one.
2061    * TODO: Resolve Public Identifiers... or consider changing function name.
2062    * <p>
2063    * If we find a relative URI
2064    * reference, XML expects it to be resolved in terms of the base URI
2065    * of the document. The DOM doesn't do that for us, and it isn't
2066    * entirely clear whether that should be done here; currently that's
2067    * pushed up to a higher level of our application. (Note that DOM Level
2068    * 1 didn't store the document's base URI.)
2069    * TODO: Consider resolving Relative URIs.
2070    * <p>
2071    * (The DOM's statement that "An XML processor may choose to
2072    * completely expand entities before the structure model is passed
2073    * to the DOM" refers only to parsed entities, not unparsed, and hence
2074    * doesn't affect this function.)
2075    *
2076    * @param name A string containing the Entity Name of the unparsed
2077    * entity.
2078    *
2079    * @return String containing the URI of the Unparsed Entity, or an
2080    * empty string if no such entity exists.
2081    */
2082   public abstract String getUnparsedEntityURI(String name);
2083 
2084   // ============== Boolean methods ================
2085 
2086   /**
2087    * Return true if the xsl:strip-space or xsl:preserve-space was processed
2088    * during construction of the DTM document.
2089    *
2090    * @return true if this DTM supports prestripping.
2091    */
2092   public boolean supportsPreStripping()
2093   {
2094     return true;
2095   }
2096 
2097   /**
2098    * Figure out whether nodeHandle2 should be considered as being later
2099    * in the document than nodeHandle1, in Document Order as defined
2100    * by the XPath model. This may not agree with the ordering defined
2101    * by other XML applications.
2102    * <p>
2103    * There are some cases where ordering isn't defined, and neither are
2104    * the results of this function -- though we'll generally return false.
2105    *
2106    * @param nodeHandle1 Node handle to perform position comparison on.
2107    * @param nodeHandle2 Second Node handle to perform position comparison on .
2108    *
2109    * @return true if node1 comes before node2, otherwise return false.
2110    * You can think of this as
2111    * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
2112    */
2113   public boolean isNodeAfter(int nodeHandle1, int nodeHandle2)
2114   {
2115                 // These return NULL if the node doesn't belong to this document.
2116     int index1 = makeNodeIdentity(nodeHandle1);
2117     int index2 = makeNodeIdentity(nodeHandle2);
2118 
2119     return index1!=NULL && index2!=NULL && index1 <= index2;
2120   }
2121 
2122   /**
2123    *     2. [element content whitespace] A boolean indicating whether the
2124    *        character is white space appearing within element content (see [XML],
2125    *        2.10 "White Space Handling"). Note that validating XML processors are
2126    *        required by XML 1.0 to provide this information. If there is no
2127    *        declaration for the containing element, this property has no value for
2128    *        white space characters. If no declaration has been read, but the [all
2129    *        declarations processed] property of the document information item is
2130    *        false (so there may be an unread declaration), then the value of this
2131    *        property is unknown for white space characters. It is always false for
2132    *        characters that are not white space.
2133    *
2134    * @param nodeHandle the node ID.
2135    * @return <code>true</code> if the character data is whitespace;
2136    *         <code>false</code> otherwise.
2137    */
2138   public boolean isCharacterElementContentWhitespace(int nodeHandle)
2139   {
2140 
2141     // %TBD%
2142     return false;
2143   }
2144 
2145   /**
2146    *    10. [all declarations processed] This property is not strictly speaking
2147    *        part of the infoset of the document. Rather it is an indication of
2148    *        whether the processor has read the complete DTD. Its value is a
2149    *        boolean. If it is false, then certain properties (indicated in their
2150    *        descriptions below) may be unknown. If it is true, those properties
2151    *        are never unknown.
2152    *
2153    * @param documentHandle A node handle that must identify a document.
2154    * @return <code>true</code> if all declarations were processed;
2155    *         <code>false</code> otherwise.
2156    */
2157   public boolean isDocumentAllDeclarationsProcessed(int documentHandle)
2158   {
2159     return true;
2160   }
2161 
2162   /**
2163    *     5. [specified] A flag indicating whether this attribute was actually
2164    *        specified in the start-tag of its element, or was defaulted from the
2165    *        DTD.
2166    *
2167    * @param attributeHandle The attribute handle in question.
2168    *
2169    * @return <code>true</code> if the attribute was specified;
2170    *         <code>false</code> if it was defaulted.
2171    */
2172   public abstract boolean isAttributeSpecified(int attributeHandle);
2173 
2174   // ========== Direct SAX Dispatch, for optimization purposes ========
2175 
2176   /**
2177    * Directly call the
2178    * characters method on the passed ContentHandler for the
2179    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2180    * for the definition of a node's string-value). Multiple calls to the
2181    * ContentHandler's characters methods may well occur for a single call to
2182    * this method.
2183    *
2184    * @param nodeHandle The node ID.
2185    * @param ch A non-null reference to a ContentHandler.
2186    * @param normalize true if the content should be normalized according to
2187    * the rules for the XPath
2188    * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
2189    * function.
2190    *
2191    * @throws org.xml.sax.SAXException
2192    */
2193   public abstract void dispatchCharactersEvents(
2194     int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
2195       throws org.xml.sax.SAXException;
2196 
2197   /**
2198    * Directly create SAX parser events from a subtree.
2199    *
2200    * @param nodeHandle The node ID.
2201    * @param ch A non-null reference to a ContentHandler.
2202    *
2203    * @throws org.xml.sax.SAXException
2204    */
2205   public abstract void dispatchToEvents(
2206     int nodeHandle, org.xml.sax.ContentHandler ch)
2207       throws org.xml.sax.SAXException;
2208 
2209   /**
2210    * Return an DOM node for the given node.
2211    *
2212    * @param nodeHandle The node ID.
2213    *
2214    * @return A node representation of the DTM node.
2215    */
2216   public org.w3c.dom.Node getNode(int nodeHandle)
2217   {
2218     return new DTMNodeProxy(this, nodeHandle);
2219   }
2220 
2221   // ==== Construction methods (may not be supported by some implementations!) =====
2222 
2223   /**
2224    * Append a child to the end of the document. Please note that the node
2225    * is always cloned if it is owned by another document.
2226    *
2227    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2228    * Does it become the last child of the Document? Of the root element?</p>
2229    *
2230    * @param newChild Must be a valid new node handle.
2231    * @param clone true if the child should be cloned into the document.
2232    * @param cloneDepth if the clone argument is true, specifies that the
2233    *                   clone should include all it's children.
2234    */
2235   public void appendChild(int newChild, boolean clone, boolean cloneDepth)
2236   {
2237     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendChild not yet supported!");
2238   }
2239 
2240   /**
2241    * Append a text node child that will be constructed from a string,
2242    * to the end of the document.
2243    *
2244    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2245    * Does it become the last child of the Document? Of the root element?</p>
2246    *
2247    * @param str Non-null reverence to a string.
2248    */
2249   public void appendTextChild(String str)
2250   {
2251     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendTextChild not yet supported!");
2252   }
2253 
2254   /**
2255    * Simple error for asserts and the like.
2256    *
2257    * @param msg Error message to report.
2258    */
2259   protected void error(String msg)
2260   {
2261     throw new DTMException(msg);
2262   }
2263 
2264   /**
2265    * Find out whether or not to strip whispace nodes.
2266    *
2267    *
2268    * @return whether or not to strip whispace nodes.
2269    */
2270   protected boolean getShouldStripWhitespace()
2271   {
2272     return m_shouldStripWS;
2273   }
2274 
2275   /**
2276    * Set whether to strip whitespaces and push in current value of
2277    * m_shouldStripWS in m_shouldStripWhitespaceStack.
2278    *
2279    * @param shouldStrip Flag indicating whether to strip whitespace nodes
2280    */
2281   protected void pushShouldStripWhitespace(boolean shouldStrip)
2282   {
2283 
2284     m_shouldStripWS = shouldStrip;
2285 
2286     if (null != m_shouldStripWhitespaceStack)
2287       m_shouldStripWhitespaceStack.push(shouldStrip);
2288   }
2289 
2290   /**
2291    * Set whether to strip whitespaces at this point by popping out
2292    * m_shouldStripWhitespaceStack.
2293    *
2294    */
2295   protected void popShouldStripWhitespace()
2296   {
2297     if (null != m_shouldStripWhitespaceStack)
2298       m_shouldStripWS = m_shouldStripWhitespaceStack.popAndTop();
2299   }
2300 
2301   /**
2302    * Set whether to strip whitespaces and set the top of the stack to
2303    * the current value of m_shouldStripWS.
2304    *
2305    *
2306    * @param shouldStrip Flag indicating whether to strip whitespace nodes
2307    */
2308   protected void setShouldStripWhitespace(boolean shouldStrip)
2309   {
2310 
2311     m_shouldStripWS = shouldStrip;
2312 
2313     if (null != m_shouldStripWhitespaceStack)
2314       m_shouldStripWhitespaceStack.setTop(shouldStrip);
2315   }
2316 
2317   /**
2318    * A dummy routine to satisify the abstract interface. If the DTM
2319    * implememtation that extends the default base requires notification
2320    * of registration, they can override this method.
2321    */
2322    public void documentRegistration()
2323    {
2324    }
2325 
2326   /**
2327    * A dummy routine to satisify the abstract interface. If the DTM
2328    * implememtation that extends the default base requires notification
2329    * when the document is being released, they can override this method
2330    */
2331    public void documentRelease()
2332    {
2333    }
2334 
2335    /**
2336     * Migrate a DTM built with an old DTMManager to a new DTMManager.
2337     * After the migration, the new DTMManager will treat the DTM as
2338     * one that is built by itself.
2339     * This is used to support DTM sharing between multiple transformations.
2340     * @param mgr the DTMManager
2341     */
2342    public void migrateTo(DTMManager mgr)
2343    {
2344      m_mgr = mgr;
2345      if(mgr instanceof DTMManagerDefault)
2346        m_mgrDefault=(DTMManagerDefault)mgr;
2347    }
2348 
2349          /** Query which DTMManager this DTM is currently being handled by.
2350           *
2351           * %REVEW% Should this become part of the base DTM API?
2352           *
2353           * @return a DTMManager, or null if this is a "stand-alone" DTM.
2354           */
2355          public DTMManager getManager()
2356          {
2357                  return m_mgr;
2358          }
2359 
2360          /** Query which DTMIDs this DTM is currently using within the DTMManager.
2361           *
2362           * %REVEW% Should this become part of the base DTM API?
2363           *
2364           * @return an IntVector, or null if this is a "stand-alone" DTM.
2365           */
2366          public SuballocatedIntVector getDTMIDs()
2367          {
2368                  if(m_mgr==null) return null;
2369                  return m_dtmIdent;
2370          }
2371 }