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