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.xpath.internal;
  23 
  24 import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
  25 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  26 import com.sun.org.apache.xml.internal.dtm.Axis;
  27 import com.sun.org.apache.xml.internal.dtm.DTM;
  28 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  29 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  30 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  31 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  32 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
  33 import com.sun.org.apache.xml.internal.utils.IntStack;
  34 import com.sun.org.apache.xml.internal.utils.NodeVector;
  35 import com.sun.org.apache.xml.internal.utils.ObjectStack;
  36 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  37 import com.sun.org.apache.xml.internal.utils.XMLString;
  38 import com.sun.org.apache.xpath.internal.axes.SubContextList;
  39 import com.sun.org.apache.xpath.internal.objects.DTMXRTreeFrag;
  40 import com.sun.org.apache.xpath.internal.objects.XObject;
  41 import com.sun.org.apache.xpath.internal.objects.XString;
  42 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  43 import java.lang.reflect.Method;
  44 import java.util.ArrayList;
  45 import java.util.HashMap;
  46 import java.util.Iterator;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Stack;
  50 import javax.xml.transform.ErrorListener;
  51 import javax.xml.transform.SourceLocator;
  52 import javax.xml.transform.URIResolver;
  53 import org.xml.sax.XMLReader;
  54 
  55 /**
  56  * Default class for the runtime execution context for XPath.
  57  *
  58  * <p>This class extends DTMManager but does not directly implement it.</p>
  59  * @xsl.usage advanced

  60  */
  61 public class XPathContext extends DTMManager // implements ExpressionContext
  62 {
  63         IntStack m_last_pushed_rtfdtm=new IntStack();
  64   /**
  65    * Stack of cached "reusable" DTMs for Result Tree Fragments.
  66    * This is a kluge to handle the problem of starting an RTF before
  67    * the old one is complete.
  68    *
  69    * %REVIEW% I'm using a Vector rather than Stack so we can reuse
  70    * the DTMs if the problem occurs multiple times. I'm not sure that's
  71    * really a net win versus discarding the DTM and starting a new one...
  72    * but the retained RTF DTM will have been tail-pruned so should be small.
  73    */
  74   private List<DTM> m_rtfdtm_stack=null;
  75   /** Index of currently active RTF DTM in m_rtfdtm_stack */
  76   private int m_which_rtfdtm=-1;
  77 
  78  /**
  79    * Most recent "reusable" DTM for Global Result Tree Fragments. No stack is
  80    * required since we're never going to pop these.
  81    */
  82   private SAX2RTFDTM m_global_rtfdtm=null;
  83 
  84   /**
  85    * HashMap of cached the DTMXRTreeFrag objects, which are identified by DTM IDs.
  86    * The object are just wrappers for DTMs which are used in  XRTreeFrag.
  87    */
  88   private Map<Integer, DTMXRTreeFrag> m_DTMXRTreeFrags = null;
  89 
  90   /**
  91    * state of the secure processing feature.
  92    */
  93   private boolean m_isSecureProcessing = false;
  94 
  95   private boolean m_useServicesMechanism = true;
  96 
  97   /**
  98    * Though XPathContext context extends
  99    * the DTMManager, it really is a proxy for this object, which
 100    * is the real DTMManager.
 101    */
 102   protected DTMManager m_dtmManager = null;
 103 
 104   /**
 105    * Return the DTMManager object.  Though XPathContext context extends
 106    * the DTMManager, it really is a proxy for the real DTMManager.  If a
 107    * caller needs to make a lot of calls to the DTMManager, it is faster
 108    * if it gets the real one from this function.
 109    */
 110    public DTMManager getDTMManager()
 111    {
 112      return m_dtmManager;
 113    }
 114 
 115   /**
 116    * Set the state of the secure processing feature
 117    */
 118   public void setSecureProcessing(boolean flag)
 119   {
 120     m_isSecureProcessing = flag;
 121   }
 122 
 123   /**
 124    * Return the state of the secure processing feature
 125    */
 126   public boolean isSecureProcessing()
 127   {
 128     return m_isSecureProcessing;
 129   }
 130 
 131   /**
 132    * Get an instance of a DTM, loaded with the content from the
 133    * specified source.  If the unique flag is true, a new instance will
 134    * always be returned.  Otherwise it is up to the DTMManager to return a
 135    * new instance or an instance that it already created and may be being used
 136    * by someone else.
 137    * (I think more parameters will need to be added for error handling, and entity
 138    * resolution).
 139    *
 140    * @param source the specification of the source object, which may be null,
 141    *               in which case it is assumed that node construction will take
 142    *               by some other means.
 143    * @param unique true if the returned DTM must be unique, probably because it
 144    * is going to be mutated.
 145    * @param wsfilter Enables filtering of whitespace nodes, and may be null.
 146    * @param incremental true if the construction should try and be incremental.
 147    * @param doIndexing true if the caller considers it worth it to use
 148    *                   indexing schemes.
 149    *
 150    * @return a non-null DTM reference.
 151    */
 152   public DTM getDTM(javax.xml.transform.Source source, boolean unique,
 153                     DTMWSFilter wsfilter,
 154                     boolean incremental,
 155                     boolean doIndexing)
 156   {
 157     return m_dtmManager.getDTM(source, unique, wsfilter,
 158                                incremental, doIndexing);
 159   }
 160 
 161   /**
 162    * Get an instance of a DTM that "owns" a node handle.
 163    *
 164    * @param nodeHandle the nodeHandle.
 165    *
 166    * @return a non-null DTM reference.
 167    */
 168   public DTM getDTM(int nodeHandle)
 169   {
 170     return m_dtmManager.getDTM(nodeHandle);
 171   }
 172 
 173   /**
 174    * Given a W3C DOM node, try and return a DTM handle.
 175    * Note: calling this may be non-optimal.
 176    *
 177    * @param node Non-null reference to a DOM node.
 178    *
 179    * @return a valid DTM handle.
 180    */
 181   public int getDTMHandleFromNode(org.w3c.dom.Node node)
 182   {
 183     return m_dtmManager.getDTMHandleFromNode(node);
 184   }
 185 //
 186 //
 187   /**
 188    * %TBD% Doc
 189    */
 190   public int getDTMIdentity(DTM dtm)
 191   {
 192     return m_dtmManager.getDTMIdentity(dtm);
 193   }
 194 //
 195   /**
 196    * Creates an empty <code>DocumentFragment</code> object.
 197    * @return A new <code>DocumentFragment handle</code>.
 198    */
 199   public DTM createDocumentFragment()
 200   {
 201     return m_dtmManager.createDocumentFragment();
 202   }
 203 //
 204   /**
 205    * Release a DTM either to a lru pool, or completely remove reference.
 206    * DTMs without system IDs are always hard deleted.
 207    * State: experimental.
 208    *
 209    * @param dtm The DTM to be released.
 210    * @param shouldHardDelete True if the DTM should be removed no matter what.
 211    * @return true if the DTM was removed, false if it was put back in a lru pool.
 212    */
 213   public boolean release(DTM dtm, boolean shouldHardDelete)
 214   {
 215     // %REVIEW% If it's a DTM which may contain multiple Result Tree
 216     // Fragments, we can't discard it unless we know not only that it
 217     // is empty, but that the XPathContext itself is going away. So do
 218     // _not_ accept the request. (May want to do it as part of
 219     // reset(), though.)
 220     if(m_rtfdtm_stack!=null && m_rtfdtm_stack.contains(dtm))
 221     {
 222       return false;
 223     }
 224 
 225     return m_dtmManager.release(dtm, shouldHardDelete);
 226   }
 227 
 228   /**
 229    * Create a new <code>DTMIterator</code> based on an XPath
 230    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 231    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 232    *
 233    * @param xpathCompiler ??? Somehow we need to pass in a subpart of the
 234    * expression.  I hate to do this with strings, since the larger expression
 235    * has already been parsed.
 236    *
 237    * @param pos The position in the expression.
 238    * @return The newly created <code>DTMIterator</code>.
 239    */
 240   public DTMIterator createDTMIterator(Object xpathCompiler, int pos)
 241   {
 242     return m_dtmManager.createDTMIterator(xpathCompiler, pos);
 243   }
 244 //
 245   /**
 246    * Create a new <code>DTMIterator</code> based on an XPath
 247    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 248    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 249    *
 250    * @param xpathString Must be a valid string expressing a
 251    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 252    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 253    *
 254    * @param presolver An object that can resolve prefixes to namespace URLs.
 255    *
 256    * @return The newly created <code>DTMIterator</code>.
 257    */
 258   public DTMIterator createDTMIterator(String xpathString,
 259           PrefixResolver presolver)
 260   {
 261     return m_dtmManager.createDTMIterator(xpathString, presolver);
 262   }
 263 //
 264   /**
 265    * Create a new <code>DTMIterator</code> based only on a whatToShow and
 266    * a DTMFilter.  The traversal semantics are defined as the descendant
 267    * access.
 268    *
 269    * @param whatToShow This flag specifies which node types may appear in
 270    *   the logical view of the tree presented by the iterator. See the
 271    *   description of <code>NodeFilter</code> for the set of possible
 272    *   <code>SHOW_</code> values.These flags can be combined using
 273    *   <code>OR</code>.
 274    * @param filter The <code>NodeFilter</code> to be used with this
 275    *   <code>TreeWalker</code>, or <code>null</code> to indicate no filter.
 276    * @param entityReferenceExpansion The value of this flag determines
 277    *   whether entity reference nodes are expanded.
 278    *
 279    * @return The newly created <code>NodeIterator</code>.
 280    */
 281   public DTMIterator createDTMIterator(int whatToShow,
 282           DTMFilter filter, boolean entityReferenceExpansion)
 283   {
 284     return m_dtmManager.createDTMIterator(whatToShow, filter, entityReferenceExpansion);
 285   }
 286 
 287   /**
 288    * Create a new <code>DTMIterator</code> that holds exactly one node.
 289    *
 290    * @param node The node handle that the DTMIterator will iterate to.
 291    *
 292    * @return The newly created <code>DTMIterator</code>.
 293    */
 294   public DTMIterator createDTMIterator(int node)
 295   {
 296     // DescendantIterator iter = new DescendantIterator();
 297     DTMIterator iter = new com.sun.org.apache.xpath.internal.axes.OneStepIteratorForward(Axis.SELF);
 298     iter.setRoot(node, this);
 299     return iter;
 300     // return m_dtmManager.createDTMIterator(node);
 301   }
 302 
 303   /**
 304    * Create an XPathContext instance.
 305    */
 306   public XPathContext()
 307   {
 308     this(true);
 309   }
 310 
 311   public XPathContext(boolean useServicesMechanism) {
 312       init(useServicesMechanism);
 313   }
 314   /**
 315    **This constructor doesn't seem to be used anywhere -- huizhe wang**
 316    * Create an XPathContext instance.
 317    * @param owner Value that can be retrieved via the getOwnerObject() method.
 318    * @see #getOwnerObject
 319    */
 320   public XPathContext(Object owner)
 321   {
 322     m_owner = owner;
 323     try {
 324       m_ownerGetErrorListener = m_owner.getClass().getMethod("getErrorListener", new Class<?>[] {});
 325     }
 326     catch (NoSuchMethodException nsme) {}
 327     init(true);
 328   }
 329 
 330   private void init(boolean useServicesMechanism) {
 331     m_prefixResolvers.push(null);
 332     m_currentNodes.push(DTM.NULL);
 333     m_currentExpressionNodes.push(DTM.NULL);
 334     m_saxLocations.push(null);
 335     m_useServicesMechanism = useServicesMechanism;
 336     m_dtmManager = DTMManager.newInstance(
 337                    com.sun.org.apache.xpath.internal.objects.XMLStringFactoryImpl.getFactory()
 338                    );
 339   }
 340 
 341   /**
 342    * Reset for new run.
 343    */
 344   public void reset()
 345   {
 346     releaseDTMXRTreeFrags();
 347     // These couldn't be disposed of earlier (see comments in release()); zap them now.
 348     if(m_rtfdtm_stack!=null) {
 349         for (DTM dtm : m_rtfdtm_stack) {
 350             m_dtmManager.release(dtm, true);
 351         }
 352     }
 353 
 354     m_rtfdtm_stack=null; // drop our references too
 355     m_which_rtfdtm=-1;
 356 
 357     if(m_global_rtfdtm!=null)
 358                         m_dtmManager.release(m_global_rtfdtm,true);
 359     m_global_rtfdtm=null;
 360 
 361 
 362     m_dtmManager = DTMManager.newInstance(
 363                    com.sun.org.apache.xpath.internal.objects.XMLStringFactoryImpl.getFactory()
 364                    );
 365 
 366     m_saxLocations.removeAllElements();
 367     m_axesIteratorStack.removeAllElements();
 368     m_contextNodeLists.removeAllElements();
 369     m_currentExpressionNodes.removeAllElements();
 370     m_currentNodes.removeAllElements();
 371     m_iteratorRoots.RemoveAllNoClear();
 372     m_predicatePos.removeAllElements();
 373     m_predicateRoots.RemoveAllNoClear();
 374     m_prefixResolvers.removeAllElements();
 375 
 376     m_prefixResolvers.push(null);
 377     m_currentNodes.push(DTM.NULL);
 378     m_currentExpressionNodes.push(DTM.NULL);
 379     m_saxLocations.push(null);
 380   }
 381 
 382   /** The current stylesheet locator. */
 383   ObjectStack m_saxLocations = new ObjectStack(RECURSIONLIMIT);
 384 
 385   /**
 386    * Set the current locater in the stylesheet.
 387    *
 388    * @param location The location within the stylesheet.
 389    */
 390   public void setSAXLocator(SourceLocator location)
 391   {
 392     m_saxLocations.setTop(location);
 393   }
 394 
 395   /**
 396    * Set the current locater in the stylesheet.
 397    *
 398    * @param location The location within the stylesheet.
 399    */
 400   public void pushSAXLocator(SourceLocator location)
 401   {
 402     m_saxLocations.push(location);
 403   }
 404 
 405   /**
 406    * Push a slot on the locations stack so that setSAXLocator can be
 407    * repeatedly called.
 408    *
 409    */
 410   public void pushSAXLocatorNull()
 411   {
 412     m_saxLocations.push(null);
 413   }
 414 
 415 
 416   /**
 417    * Pop the current locater.
 418    */
 419   public void popSAXLocator()
 420   {
 421     m_saxLocations.pop();
 422   }
 423 
 424   /**
 425    * Get the current locater in the stylesheet.
 426    *
 427    * @return The location within the stylesheet, or null if not known.
 428    */
 429   public SourceLocator getSAXLocator()
 430   {
 431     return (SourceLocator) m_saxLocations.peek();
 432   }
 433 
 434   /** The owner context of this XPathContext.  In the case of XSLT, this will be a
 435    *  Transformer object.
 436    */
 437   private Object m_owner;
 438 
 439   /** The owner context of this XPathContext.  In the case of XSLT, this will be a
 440    *  Transformer object.
 441    */
 442   private Method m_ownerGetErrorListener;
 443 
 444   /**
 445    * Get the "owner" context of this context, which should be,
 446    * in the case of XSLT, the Transformer object.  This is needed
 447    * so that XSLT functions can get the Transformer.
 448    * @return The owner object passed into the constructor, or null.
 449    */
 450   public Object getOwnerObject()
 451   {
 452     return m_owner;
 453   }
 454 
 455   // ================ VarStack ===================
 456 
 457   /**
 458    * The stack of Variable stacks.  A VariableStack will be
 459    * pushed onto this stack for each template invocation.
 460    */
 461   private VariableStack m_variableStacks = new VariableStack();
 462 
 463   /**
 464    * Get the variable stack, which is in charge of variables and
 465    * parameters.
 466    *
 467    * @return the variable stack, which should not be null.
 468    */
 469   public final VariableStack getVarStack()
 470   {
 471     return m_variableStacks;
 472   }
 473 
 474   /**
 475    * Get the variable stack, which is in charge of variables and
 476    * parameters.
 477    *
 478    * @param varStack non-null reference to the variable stack.
 479    */
 480   public final void setVarStack(VariableStack varStack)
 481   {
 482     m_variableStacks = varStack;
 483   }
 484 
 485   // ================ SourceTreeManager ===================
 486 
 487   /** The source tree manager, which associates Source objects to source
 488    *  tree nodes. */
 489   private SourceTreeManager m_sourceTreeManager = new SourceTreeManager();
 490 
 491   /**
 492    * Get the SourceTreeManager associated with this execution context.
 493    *
 494    * @return the SourceTreeManager associated with this execution context.
 495    */
 496   public final SourceTreeManager getSourceTreeManager()
 497   {
 498     return m_sourceTreeManager;
 499   }
 500 
 501   /**
 502    * Set the SourceTreeManager associated with this execution context.
 503    *
 504    * @param mgr the SourceTreeManager to be associated with this
 505    *        execution context.
 506    */
 507   public void setSourceTreeManager(SourceTreeManager mgr)
 508   {
 509     m_sourceTreeManager = mgr;
 510   }
 511 
 512   // =================================================
 513 
 514   /** The ErrorListener where errors and warnings are to be reported.   */
 515   private ErrorListener m_errorListener;
 516 
 517   /** A default ErrorListener in case our m_errorListener was not specified and our
 518    *  owner either does not have an ErrorListener or has a null one.
 519    */
 520   private ErrorListener m_defaultErrorListener;
 521 
 522   /**
 523    * Get the ErrorListener where errors and warnings are to be reported.
 524    *
 525    * @return A non-null ErrorListener reference.
 526    */
 527   public final ErrorListener getErrorListener()
 528   {
 529 
 530     if (null != m_errorListener)
 531         return m_errorListener;
 532 
 533     ErrorListener retval = null;
 534 
 535     try {
 536       if (null != m_ownerGetErrorListener)
 537         retval = (ErrorListener) m_ownerGetErrorListener.invoke(m_owner, new Object[] {});
 538     }
 539     catch (Exception e) {}
 540 
 541     if (null == retval)
 542     {
 543       if (null == m_defaultErrorListener)
 544         m_defaultErrorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler();
 545       retval = m_defaultErrorListener;
 546     }
 547 
 548     return retval;
 549   }
 550 
 551   /**
 552    * Set the ErrorListener where errors and warnings are to be reported.
 553    *
 554    * @param listener A non-null ErrorListener reference.
 555    */
 556   public void setErrorListener(ErrorListener listener) throws IllegalArgumentException
 557   {
 558     if (listener == null)
 559       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
 560     m_errorListener = listener;
 561   }
 562 
 563 
 564   // =================================================
 565 
 566   /** The TrAX URI Resolver for resolving URIs from the document(...)
 567    *  function to source tree nodes.  */
 568   private URIResolver m_uriResolver;
 569 
 570   /**
 571    * Get the URIResolver associated with this execution context.
 572    *
 573    * @return a URI resolver, which may be null.
 574    */
 575   public final URIResolver getURIResolver()
 576   {
 577     return m_uriResolver;
 578   }
 579 
 580   /**
 581    * Set the URIResolver associated with this execution context.
 582    *
 583    * @param resolver the URIResolver to be associated with this
 584    *        execution context, may be null to clear an already set resolver.
 585    */
 586   public void setURIResolver(URIResolver resolver)
 587   {
 588     m_uriResolver = resolver;
 589   }
 590 
 591   // =================================================
 592 
 593   /** The reader of the primary source tree.    */
 594   public XMLReader m_primaryReader;
 595 
 596   /**
 597    * Get primary XMLReader associated with this execution context.
 598    *
 599    * @return The reader of the primary source tree.
 600    */
 601   public final XMLReader getPrimaryReader()
 602   {
 603     return m_primaryReader;
 604   }
 605 
 606   /**
 607    * Set primary XMLReader associated with this execution context.
 608    *
 609    * @param reader The reader of the primary source tree.
 610    */
 611   public void setPrimaryReader(XMLReader reader)
 612   {
 613     m_primaryReader = reader;
 614   }
 615 
 616   // =================================================
 617 
 618 
 619   /** Misnamed string manager for XPath messages.  */
 620   // private static XSLMessages m_XSLMessages = new XSLMessages();
 621 
 622   //==========================================================
 623   // SECTION: Execution context state tracking
 624   //==========================================================
 625 
 626   /**
 627    * The current context node list.
 628    */
 629   private Stack<DTMIterator> m_contextNodeLists = new Stack<>();
 630 
 631   public Stack<DTMIterator> getContextNodeListsStack() { return m_contextNodeLists; }
 632   public void setContextNodeListsStack(Stack<DTMIterator> s) { m_contextNodeLists = s; }
 633 
 634   /**
 635    * Get the current context node list.
 636    *
 637    * @return  the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 638    * also referred to here as a <term>context node list</term>.
 639    */
 640   public final DTMIterator getContextNodeList()
 641   {
 642 
 643     if (m_contextNodeLists.size() > 0)
 644       return m_contextNodeLists.peek();
 645     else
 646       return null;
 647   }
 648 
 649   /**
 650    * Set the current context node list.
 651    *
 652    * @param nl the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 653    * also referred to here as a <term>context node list</term>.
 654    * @xsl.usage internal
 655    */
 656   public final void pushContextNodeList(DTMIterator nl)
 657   {
 658     m_contextNodeLists.push(nl);
 659   }
 660 
 661   /**
 662    * Pop the current context node list.
 663    * @xsl.usage internal
 664    */
 665   public final void popContextNodeList()
 666   {
 667         if(m_contextNodeLists.isEmpty())
 668           System.err.println("Warning: popContextNodeList when stack is empty!");
 669         else
 670       m_contextNodeLists.pop();
 671   }
 672 
 673   /**
 674    * The amount to use for stacks that record information during the
 675    * recursive execution.
 676    */
 677   public static final int RECURSIONLIMIT = (1024*4);
 678 
 679   /** The stack of <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a> objects.
 680    *  Not to be confused with the current node list.  %REVIEW% Note that there
 681    *  are no bounds check and resize for this stack, so if it is blown, it's all
 682    *  over.  */
 683   private IntStack m_currentNodes = new IntStack(RECURSIONLIMIT);
 684 
 685 //  private NodeVector m_currentNodes = new NodeVector();
 686 
 687   public IntStack getCurrentNodeStack() {return m_currentNodes; }
 688   public void setCurrentNodeStack(IntStack nv) { m_currentNodes = nv; }
 689 
 690   /**
 691    * Get the current context node.
 692    *
 693    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 694    */
 695   public final int getCurrentNode()
 696   {
 697     return m_currentNodes.peek();
 698   }
 699 
 700   /**
 701    * Set the current context node and expression node.
 702    *
 703    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 704    * @param en the sub-expression context node.
 705    */
 706   public final void pushCurrentNodeAndExpression(int cn, int en)
 707   {
 708     m_currentNodes.push(cn);
 709     m_currentExpressionNodes.push(cn);
 710   }
 711 
 712   /**
 713    * Set the current context node.
 714    */
 715   public final void popCurrentNodeAndExpression()
 716   {
 717     m_currentNodes.quickPop(1);
 718     m_currentExpressionNodes.quickPop(1);
 719   }
 720 
 721   /**
 722    * Push the current context node, expression node, and prefix resolver.
 723    *
 724    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 725    * @param en the sub-expression context node.
 726    * @param nc the namespace context (prefix resolver.
 727    */
 728   public final void pushExpressionState(int cn, int en, PrefixResolver nc)
 729   {
 730     m_currentNodes.push(cn);
 731     m_currentExpressionNodes.push(cn);
 732     m_prefixResolvers.push(nc);
 733   }
 734 
 735   /**
 736    * Pop the current context node, expression node, and prefix resolver.
 737    */
 738   public final void popExpressionState()
 739   {
 740     m_currentNodes.quickPop(1);
 741     m_currentExpressionNodes.quickPop(1);
 742     m_prefixResolvers.pop();
 743   }
 744 
 745 
 746 
 747   /**
 748    * Set the current context node.
 749    *
 750    * @param n the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 751    */
 752   public final void pushCurrentNode(int n)
 753   {
 754     m_currentNodes.push(n);
 755   }
 756 
 757   /**
 758    * Pop the current context node.
 759    */
 760   public final void popCurrentNode()
 761   {
 762     m_currentNodes.quickPop(1);
 763   }
 764 
 765   /**
 766    * Set the current predicate root.
 767    */
 768   public final void pushPredicateRoot(int n)
 769   {
 770     m_predicateRoots.push(n);
 771   }
 772 
 773   /**
 774    * Pop the current predicate root.
 775    */
 776   public final void popPredicateRoot()
 777   {
 778     m_predicateRoots.popQuick();
 779   }
 780 
 781   /**
 782    * Get the current predicate root.
 783    */
 784   public final int getPredicateRoot()
 785   {
 786     return m_predicateRoots.peepOrNull();
 787   }
 788 
 789   /**
 790    * Set the current location path iterator root.
 791    */
 792   public final void pushIteratorRoot(int n)
 793   {
 794     m_iteratorRoots.push(n);
 795   }
 796 
 797   /**
 798    * Pop the current location path iterator root.
 799    */
 800   public final void popIteratorRoot()
 801   {
 802     m_iteratorRoots.popQuick();
 803   }
 804 
 805   /**
 806    * Get the current location path iterator root.
 807    */
 808   public final int getIteratorRoot()
 809   {
 810     return m_iteratorRoots.peepOrNull();
 811   }
 812 
 813   /** A stack of the current sub-expression nodes.  */
 814   private NodeVector m_iteratorRoots = new NodeVector();
 815 
 816   /** A stack of the current sub-expression nodes.  */
 817   private NodeVector m_predicateRoots = new NodeVector();
 818 
 819   /** A stack of the current sub-expression nodes.  */
 820   private IntStack m_currentExpressionNodes = new IntStack(RECURSIONLIMIT);
 821 
 822 
 823   public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; }
 824   public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; }
 825 
 826   private IntStack m_predicatePos = new IntStack();
 827 
 828   public final int getPredicatePos()
 829   {
 830     return m_predicatePos.peek();
 831   }
 832 
 833   public final void pushPredicatePos(int n)
 834   {
 835     m_predicatePos.push(n);
 836   }
 837 
 838   public final void popPredicatePos()
 839   {
 840     m_predicatePos.pop();
 841   }
 842 
 843   /**
 844    * Get the current node that is the expression's context (i.e. for current() support).
 845    *
 846    * @return The current sub-expression node.
 847    */
 848   public final int getCurrentExpressionNode()
 849   {
 850     return m_currentExpressionNodes.peek();
 851   }
 852 
 853   /**
 854    * Set the current node that is the expression's context (i.e. for current() support).
 855    *
 856    * @param n The sub-expression node to be current.
 857    */
 858   public final void pushCurrentExpressionNode(int n)
 859   {
 860     m_currentExpressionNodes.push(n);
 861   }
 862 
 863   /**
 864    * Pop the current node that is the expression's context
 865    * (i.e. for current() support).
 866    */
 867   public final void popCurrentExpressionNode()
 868   {
 869     m_currentExpressionNodes.quickPop(1);
 870   }
 871 
 872   private ObjectStack m_prefixResolvers
 873                                    = new ObjectStack(RECURSIONLIMIT);
 874 
 875   /**
 876    * Get the current namespace context for the xpath.
 877    *
 878    * @return the current prefix resolver for resolving prefixes to
 879    *         namespace URLs.
 880    */
 881   public final PrefixResolver getNamespaceContext()
 882   {
 883     return (PrefixResolver) m_prefixResolvers.peek();
 884   }
 885 
 886   /**
 887    * Get the current namespace context for the xpath.
 888    *
 889    * @param pr the prefix resolver to be used for resolving prefixes to
 890    *         namespace URLs.
 891    */
 892   public final void setNamespaceContext(PrefixResolver pr)
 893   {
 894     m_prefixResolvers.setTop(pr);
 895   }
 896 
 897   /**
 898    * Push a current namespace context for the xpath.
 899    *
 900    * @param pr the prefix resolver to be used for resolving prefixes to
 901    *         namespace URLs.
 902    */
 903   public final void pushNamespaceContext(PrefixResolver pr)
 904   {
 905     m_prefixResolvers.push(pr);
 906   }
 907 
 908   /**
 909    * Just increment the namespace contest stack, so that setNamespaceContext
 910    * can be used on the slot.
 911    */
 912   public final void pushNamespaceContextNull()
 913   {
 914     m_prefixResolvers.push(null);
 915   }
 916 
 917   /**
 918    * Pop the current namespace context for the xpath.
 919    */
 920   public final void popNamespaceContext()
 921   {
 922     m_prefixResolvers.pop();
 923   }
 924 
 925   //==========================================================
 926   // SECTION: Current TreeWalker contexts (for internal use)
 927   //==========================================================
 928 
 929   /**
 930    * Stack of AxesIterators.
 931    */
 932   private Stack<SubContextList> m_axesIteratorStack = new Stack<>();
 933 
 934   public Stack<SubContextList> getAxesIteratorStackStacks() { return m_axesIteratorStack; }
 935   public void setAxesIteratorStackStacks(Stack<SubContextList> s) { m_axesIteratorStack = s; }
 936 
 937   /**
 938    * Push a TreeWalker on the stack.
 939    *
 940    * @param iter A sub-context AxesWalker.
 941    * @xsl.usage internal
 942    */
 943   public final void pushSubContextList(SubContextList iter)
 944   {
 945     m_axesIteratorStack.push(iter);
 946   }
 947 
 948   /**
 949    * Pop the last pushed axes iterator.
 950    * @xsl.usage internal
 951    */
 952   public final void popSubContextList()
 953   {
 954     m_axesIteratorStack.pop();
 955   }
 956 
 957   /**
 958    * Get the current axes iterator, or return null if none.
 959    *
 960    * @return the sub-context node list.
 961    * @xsl.usage internal
 962    */
 963   public SubContextList getSubContextList()
 964   {
 965     return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.peek();
 966   }
 967 
 968   /**
 969    * Get the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>
 970    * as defined by the XSLT spec.
 971    *
 972    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>.
 973    * @xsl.usage internal
 974    */
 975 
 976   public com.sun.org.apache.xpath.internal.axes.SubContextList getCurrentNodeList()
 977   {
 978     return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.get(0);
 979   }
 980   //==========================================================
 981   // SECTION: Implementation of ExpressionContext interface
 982   //==========================================================
 983 
 984   /**
 985    * Get the current context node.
 986    * @return The current context node.
 987    */
 988   public final int getContextNode()
 989   {
 990     return this.getCurrentNode();
 991   }
 992 
 993   /**
 994    * Get the current context node list.
 995    * @return An iterator for the current context list, as
 996    * defined in XSLT.
 997    */
 998   public final DTMIterator getContextNodes()
 999   {
1000 
1001     try
1002     {
1003       DTMIterator cnl = getContextNodeList();
1004 
1005       if (null != cnl)
1006         return cnl.cloneWithReset();
1007       else
1008         return null;  // for now... this might ought to be an empty iterator.
1009     }
1010     catch (CloneNotSupportedException cnse)
1011     {
1012       return null;  // error reporting?
1013     }
1014   }
1015 
1016   XPathExpressionContext expressionContext = new XPathExpressionContext();
1017 
1018   /**
1019    * The the expression context for extensions for this context.
1020    *
1021    * @return An object that implements the ExpressionContext.
1022    */
1023   public ExpressionContext getExpressionContext()
1024   {
1025     return expressionContext;
1026   }
1027 
1028   public class XPathExpressionContext implements ExpressionContext
1029   {
1030     /**
1031      * Return the XPathContext associated with this XPathExpressionContext.
1032      * Extensions should use this judiciously and only when special processing
1033      * requirements cannot be met another way.  Consider requesting an enhancement
1034      * to the ExpressionContext interface to avoid having to call this method.
1035      * @return the XPathContext associated with this XPathExpressionContext.
1036      */
1037      public XPathContext getXPathContext()
1038      {
1039        return XPathContext.this;
1040      }
1041 
1042     /**
1043      * Return the DTMManager object.  Though XPathContext context extends
1044      * the DTMManager, it really is a proxy for the real DTMManager.  If a
1045      * caller needs to make a lot of calls to the DTMManager, it is faster
1046      * if it gets the real one from this function.
1047      */
1048      public DTMManager getDTMManager()
1049      {
1050        return m_dtmManager;
1051      }
1052 
1053     /**
1054      * Get the current context node.
1055      * @return The current context node.
1056      */
1057     public org.w3c.dom.Node getContextNode()
1058     {
1059       int context = getCurrentNode();
1060 
1061       return getDTM(context).getNode(context);
1062     }
1063 
1064     /**
1065      * Get the current context node list.
1066      * @return An iterator for the current context list, as
1067      * defined in XSLT.
1068      */
1069     public org.w3c.dom.traversal.NodeIterator getContextNodes()
1070     {
1071       return new com.sun.org.apache.xml.internal.dtm.ref.DTMNodeIterator(getContextNodeList());
1072     }
1073 
1074     /**
1075      * Get the error listener.
1076      * @return The registered error listener.
1077      */
1078     public ErrorListener getErrorListener()
1079     {
1080       return XPathContext.this.getErrorListener();
1081     }
1082     /**
1083      * Return the state of the services mechanism feature.
1084      */
1085     public boolean useServicesMechnism() {
1086         return m_useServicesMechanism;
1087     }
1088 
1089     /**
1090      * Set the state of the services mechanism feature.
1091      */
1092     public void setServicesMechnism(boolean flag) {
1093         m_useServicesMechanism = flag;
1094     }
1095 
1096     /**
1097      * Get the value of a node as a number.
1098      * @param n Node to be converted to a number.  May be null.
1099      * @return value of n as a number.
1100      */
1101     public double toNumber(org.w3c.dom.Node n)
1102     {
1103       // %REVIEW% You can't get much uglier than this...
1104       int nodeHandle = getDTMHandleFromNode(n);
1105       DTM dtm = getDTM(nodeHandle);
1106       XString xobj = (XString)dtm.getStringValue(nodeHandle);
1107       return xobj.num();
1108     }
1109 
1110     /**
1111      * Get the value of a node as a string.
1112      * @param n Node to be converted to a string.  May be null.
1113      * @return value of n as a string, or an empty string if n is null.
1114      */
1115     public String toString(org.w3c.dom.Node n)
1116     {
1117       // %REVIEW% You can't get much uglier than this...
1118       int nodeHandle = getDTMHandleFromNode(n);
1119       DTM dtm = getDTM(nodeHandle);
1120       XMLString strVal = dtm.getStringValue(nodeHandle);
1121       return strVal.toString();
1122     }
1123 
1124     /**
1125      * Get a variable based on it's qualified name.
1126      * @param qname The qualified name of the variable.
1127      * @return The evaluated value of the variable.
1128      * @throws javax.xml.transform.TransformerException
1129      */
1130 
1131     public final XObject getVariableOrParam(com.sun.org.apache.xml.internal.utils.QName qname)
1132               throws javax.xml.transform.TransformerException
1133     {
1134       return m_variableStacks.getVariableOrParam(XPathContext.this, qname);
1135     }
1136 
1137   }
1138 
1139  /**
1140    * Get a DTM to be used as a container for a global Result Tree
1141    * Fragment. This will always be an instance of (derived from? equivalent to?)
1142    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1143    * output to it. It may be a single DTM containing for multiple fragments,
1144    * if the implementation supports that.
1145    *
1146    * Note: The distinction between this method and getRTFDTM() is that the latter
1147    * allocates space from the dynamic variable stack (m_rtfdtm_stack), which may
1148    * be pruned away again as the templates which defined those variables are exited.
1149    * Global variables may be bound late (see XUnresolvedVariable), and never want to
1150    * be discarded, hence we need to allocate them separately and don't actually need
1151    * a stack to track them.
1152    *
1153    * @return a non-null DTM reference.
1154    */
1155   public DTM getGlobalRTFDTM()
1156   {
1157         // We probably should _NOT_ be applying whitespace filtering at this stage!
1158         //
1159         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1160         // and generate an instance of DTM which can contain multiple documents
1161         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1162         // I didn't want to change the manager API at this time, or expose
1163         // too many dependencies on its internals. (Ideally, I'd like to move
1164         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1165         // specify the subclass here.)
1166 
1167         // If it doesn't exist, or if the one already existing is in the middle of
1168         // being constructed, we need to obtain a new DTM to write into. I'm not sure
1169         // the latter will ever arise, but I'd rather be just a bit paranoid..
1170         if( m_global_rtfdtm==null || m_global_rtfdtm.isTreeIncomplete() )
1171         {
1172                 m_global_rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1173         }
1174     return m_global_rtfdtm;
1175   }
1176 
1177 
1178 
1179 
1180   /**
1181    * Get a DTM to be used as a container for a dynamic Result Tree
1182    * Fragment. This will always be an instance of (derived from? equivalent to?)
1183    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1184    * output to it. It may be a single DTM containing for multiple fragments,
1185    * if the implementation supports that.
1186    *
1187    * @return a non-null DTM reference.
1188    */
1189   public DTM getRTFDTM()
1190   {
1191         SAX2RTFDTM rtfdtm;
1192 
1193         // We probably should _NOT_ be applying whitespace filtering at this stage!
1194         //
1195         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1196         // and generate an instance of DTM which can contain multiple documents
1197         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1198         // I didn't want to change the manager API at this time, or expose
1199         // too many dependencies on its internals. (Ideally, I'd like to move
1200         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1201         // specify the subclass here.)
1202 
1203         if(m_rtfdtm_stack==null)
1204         {
1205             m_rtfdtm_stack=new ArrayList<>();
1206             rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1207             m_rtfdtm_stack.add(rtfdtm);
1208             ++m_which_rtfdtm;
1209         }
1210         else if(m_which_rtfdtm<0)
1211         {
1212             rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(++m_which_rtfdtm);
1213         }
1214         else
1215         {
1216             rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm);
1217 
1218             // It might already be under construction -- the classic example would be
1219             // an xsl:variable which uses xsl:call-template as part of its value. To
1220             // handle this recursion, we have to start a new RTF DTM, pushing the old
1221             // one onto a stack so we can return to it. This is not as uncommon a case
1222             // as we might wish, unfortunately, as some folks insist on coding XSLT
1223             // as if it were a procedural language...
1224             if(rtfdtm.isTreeIncomplete())
1225             {
1226                 if(++m_which_rtfdtm < m_rtfdtm_stack.size())
1227                     rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm);
1228                 else
1229                 {
1230                     rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1231                     m_rtfdtm_stack.add(rtfdtm);
1232                 }
1233             }
1234         }
1235 
1236     return rtfdtm;
1237   }
1238 
1239   /** Push the RTFDTM's context mark, to allows discarding RTFs added after this
1240    * point. (If it doesn't exist we don't push, since we might still be able to
1241    * get away with not creating it. That requires that excessive pops be harmless.)
1242    * */
1243   public void pushRTFContext()
1244   {
1245         m_last_pushed_rtfdtm.push(m_which_rtfdtm);
1246         if(null!=m_rtfdtm_stack)
1247                 ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark();
1248   }
1249 
1250   /** Pop the RTFDTM's context mark. This discards any RTFs added after the last
1251    * mark was set.
1252    *
1253    * If there is no RTF DTM, there's nothing to pop so this
1254    * becomes a no-op. If pushes were issued before this was called, we count on
1255    * the fact that popRewindMark is defined such that overpopping just resets
1256    * to empty.
1257    *
1258    * Complicating factor: We need to handle the case of popping back to a previous
1259    * RTF DTM, if one of the weird produce-an-RTF-to-build-an-RTF cases arose.
1260    * Basically: If pop says this DTM is now empty, then return to the previous
1261    * if one exists, in whatever state we left it in. UGLY, but hopefully the
1262    * situation which forces us to consider this will arise exceedingly rarely.
1263    * */
1264   public void popRTFContext()
1265   {
1266         int previous=m_last_pushed_rtfdtm.pop();
1267         if(null==m_rtfdtm_stack)
1268                 return;
1269 
1270         if(m_which_rtfdtm==previous)
1271         {
1272                 if(previous>=0) // guard against none-active
1273                 {
1274                         boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(previous))).popRewindMark();
1275                 }
1276         }
1277         else while(m_which_rtfdtm!=previous)
1278         {
1279                 // Empty each DTM before popping, so it's ready for reuse
1280                 // _DON'T_ pop the previous, since it's still open (which is why we
1281                 // stacked up more of these) and did not receive a mark.
1282                 boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(m_which_rtfdtm))).popRewindMark();
1283                 --m_which_rtfdtm;
1284         }
1285   }
1286 
1287   /**
1288    * Gets DTMXRTreeFrag object if one has already been created.
1289    * Creates new DTMXRTreeFrag object and adds to m_DTMXRTreeFrags  HashMap,
1290    * otherwise.
1291    * @param dtmIdentity
1292    * @return DTMXRTreeFrag
1293    */
1294   public DTMXRTreeFrag getDTMXRTreeFrag(int dtmIdentity){
1295     if(m_DTMXRTreeFrags == null){
1296       m_DTMXRTreeFrags = new HashMap<>();
1297     }
1298 
1299     if(m_DTMXRTreeFrags.containsKey(dtmIdentity)){
1300        return m_DTMXRTreeFrags.get(dtmIdentity);
1301     }else{
1302       final DTMXRTreeFrag frag = new DTMXRTreeFrag(dtmIdentity,this);
1303       m_DTMXRTreeFrags.put(dtmIdentity,frag);
1304       return frag ;
1305     }
1306   }
1307 
1308   /**
1309    * Cleans DTMXRTreeFrag objects by removing references
1310    * to DTM and XPathContext objects.
1311    */
1312   private final void releaseDTMXRTreeFrags(){
1313     if(m_DTMXRTreeFrags == null){
1314       return;
1315     }
1316     final Iterator<DTMXRTreeFrag> iter = (m_DTMXRTreeFrags.values()).iterator();
1317     while(iter.hasNext()){
1318       DTMXRTreeFrag frag = iter.next();
1319       frag.destruct();
1320       iter.remove();
1321     }
1322     m_DTMXRTreeFrags = null;
1323  }
1324 }
--- EOF ---