1 /*
   2  * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xpath.internal;
  22 
  23 import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
  24 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  25 import com.sun.org.apache.xml.internal.dtm.Axis;
  26 import com.sun.org.apache.xml.internal.dtm.DTM;
  27 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  28 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  29 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  30 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  31 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
  32 import com.sun.org.apache.xml.internal.utils.IntStack;
  33 import com.sun.org.apache.xml.internal.utils.NodeVector;
  34 import com.sun.org.apache.xml.internal.utils.ObjectStack;
  35 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  36 import com.sun.org.apache.xml.internal.utils.XMLString;
  37 import com.sun.org.apache.xpath.internal.axes.SubContextList;
  38 import com.sun.org.apache.xpath.internal.objects.DTMXRTreeFrag;
  39 import com.sun.org.apache.xpath.internal.objects.XObject;
  40 import com.sun.org.apache.xpath.internal.objects.XString;
  41 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  42 import java.lang.reflect.Method;
  43 import java.util.ArrayList;
  44 import java.util.HashMap;
  45 import java.util.Iterator;
  46 import java.util.List;
  47 import java.util.Map;
  48 import java.util.Stack;
  49 import javax.xml.transform.ErrorListener;
  50 import javax.xml.transform.SourceLocator;
  51 import javax.xml.transform.URIResolver;
  52 import org.xml.sax.XMLReader;
  53 
  54 /**
  55  * Default class for the runtime execution context for XPath.
  56  *
  57  * <p>This class extends DTMManager but does not directly implement it.</p>
  58  * @xsl.usage advanced
  59  * @LastModified: Jan 2019
  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_overrideDefaultParser;
  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(false);
 309   }
 310 
 311   public XPathContext(boolean overrideDefaultParser) {
 312       init(overrideDefaultParser);
 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(false);
 328   }
 329 
 330   private void init(boolean overrideDefaultParser) {
 331     m_prefixResolvers.push(null);
 332     m_currentNodes.push(DTM.NULL);
 333     m_currentExpressionNodes.push(DTM.NULL);
 334     m_saxLocations.push(null);
 335     m_overrideDefaultParser = overrideDefaultParser;
 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   // =================================================
 486 
 487   /** The ErrorListener where errors and warnings are to be reported.   */
 488   private ErrorListener m_errorListener;
 489 
 490   /** A default ErrorListener in case our m_errorListener was not specified and our
 491    *  owner either does not have an ErrorListener or has a null one.
 492    */
 493   private ErrorListener m_defaultErrorListener;
 494 
 495   /**
 496    * Get the ErrorListener where errors and warnings are to be reported.
 497    *
 498    * @return A non-null ErrorListener reference.
 499    */
 500   public final ErrorListener getErrorListener()
 501   {
 502 
 503     if (null != m_errorListener)
 504         return m_errorListener;
 505 
 506     ErrorListener retval = null;
 507 
 508     try {
 509       if (null != m_ownerGetErrorListener)
 510         retval = (ErrorListener) m_ownerGetErrorListener.invoke(m_owner, new Object[] {});
 511     }
 512     catch (Exception e) {}
 513 
 514     if (null == retval)
 515     {
 516       if (null == m_defaultErrorListener)
 517         m_defaultErrorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler();
 518       retval = m_defaultErrorListener;
 519     }
 520 
 521     return retval;
 522   }
 523 
 524   /**
 525    * Set the ErrorListener where errors and warnings are to be reported.
 526    *
 527    * @param listener A non-null ErrorListener reference.
 528    */
 529   public void setErrorListener(ErrorListener listener) throws IllegalArgumentException
 530   {
 531     if (listener == null)
 532       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
 533     m_errorListener = listener;
 534   }
 535 
 536 
 537   // =================================================
 538 
 539   /** The TrAX URI Resolver for resolving URIs from the document(...)
 540    *  function to source tree nodes.  */
 541   private URIResolver m_uriResolver;
 542 
 543   /**
 544    * Get the URIResolver associated with this execution context.
 545    *
 546    * @return a URI resolver, which may be null.
 547    */
 548   public final URIResolver getURIResolver()
 549   {
 550     return m_uriResolver;
 551   }
 552 
 553   /**
 554    * Set the URIResolver associated with this execution context.
 555    *
 556    * @param resolver the URIResolver to be associated with this
 557    *        execution context, may be null to clear an already set resolver.
 558    */
 559   public void setURIResolver(URIResolver resolver)
 560   {
 561     m_uriResolver = resolver;
 562   }
 563 
 564   // =================================================
 565 
 566   /** The reader of the primary source tree.    */
 567   public XMLReader m_primaryReader;
 568 
 569   /**
 570    * Get primary XMLReader associated with this execution context.
 571    *
 572    * @return The reader of the primary source tree.
 573    */
 574   public final XMLReader getPrimaryReader()
 575   {
 576     return m_primaryReader;
 577   }
 578 
 579   /**
 580    * Set primary XMLReader associated with this execution context.
 581    *
 582    * @param reader The reader of the primary source tree.
 583    */
 584   public void setPrimaryReader(XMLReader reader)
 585   {
 586     m_primaryReader = reader;
 587   }
 588 
 589   // =================================================
 590 
 591 
 592   /** Misnamed string manager for XPath messages.  */
 593   // private static XSLMessages m_XSLMessages = new XSLMessages();
 594 
 595   //==========================================================
 596   // SECTION: Execution context state tracking
 597   //==========================================================
 598 
 599   /**
 600    * The current context node list.
 601    */
 602   private Stack<DTMIterator> m_contextNodeLists = new Stack<>();
 603 
 604   public Stack<DTMIterator> getContextNodeListsStack() { return m_contextNodeLists; }
 605   public void setContextNodeListsStack(Stack<DTMIterator> s) { m_contextNodeLists = s; }
 606 
 607   /**
 608    * Get the current context node list.
 609    *
 610    * @return  the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 611    * also referred to here as a <term>context node list</term>.
 612    */
 613   public final DTMIterator getContextNodeList()
 614   {
 615 
 616     if (m_contextNodeLists.size() > 0)
 617       return m_contextNodeLists.peek();
 618     else
 619       return null;
 620   }
 621 
 622   /**
 623    * Set the current context node list.
 624    *
 625    * @param nl the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 626    * also referred to here as a <term>context node list</term>.
 627    * @xsl.usage internal
 628    */
 629   public final void pushContextNodeList(DTMIterator nl)
 630   {
 631     m_contextNodeLists.push(nl);
 632   }
 633 
 634   /**
 635    * Pop the current context node list.
 636    * @xsl.usage internal
 637    */
 638   public final void popContextNodeList()
 639   {
 640         if(m_contextNodeLists.isEmpty())
 641           System.err.println("Warning: popContextNodeList when stack is empty!");
 642         else
 643       m_contextNodeLists.pop();
 644   }
 645 
 646   /**
 647    * The amount to use for stacks that record information during the
 648    * recursive execution.
 649    */
 650   public static final int RECURSIONLIMIT = (1024*4);
 651 
 652   /** The stack of <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a> objects.
 653    *  Not to be confused with the current node list.  %REVIEW% Note that there
 654    *  are no bounds check and resize for this stack, so if it is blown, it's all
 655    *  over.  */
 656   private IntStack m_currentNodes = new IntStack(RECURSIONLIMIT);
 657 
 658 //  private NodeVector m_currentNodes = new NodeVector();
 659 
 660   public IntStack getCurrentNodeStack() {return m_currentNodes; }
 661   public void setCurrentNodeStack(IntStack nv) { m_currentNodes = nv; }
 662 
 663   /**
 664    * Get the current context node.
 665    *
 666    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 667    */
 668   public final int getCurrentNode()
 669   {
 670     return m_currentNodes.peek();
 671   }
 672 
 673   /**
 674    * Set the current context node and expression node.
 675    *
 676    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 677    * @param en the sub-expression context node.
 678    */
 679   public final void pushCurrentNodeAndExpression(int cn, int en)
 680   {
 681     m_currentNodes.push(cn);
 682     m_currentExpressionNodes.push(cn);
 683   }
 684 
 685   /**
 686    * Set the current context node.
 687    */
 688   public final void popCurrentNodeAndExpression()
 689   {
 690     m_currentNodes.quickPop(1);
 691     m_currentExpressionNodes.quickPop(1);
 692   }
 693 
 694   /**
 695    * Push the current context node, expression node, and prefix resolver.
 696    *
 697    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 698    * @param en the sub-expression context node.
 699    * @param nc the namespace context (prefix resolver.
 700    */
 701   public final void pushExpressionState(int cn, int en, PrefixResolver nc)
 702   {
 703     m_currentNodes.push(cn);
 704     m_currentExpressionNodes.push(cn);
 705     m_prefixResolvers.push(nc);
 706   }
 707 
 708   /**
 709    * Pop the current context node, expression node, and prefix resolver.
 710    */
 711   public final void popExpressionState()
 712   {
 713     m_currentNodes.quickPop(1);
 714     m_currentExpressionNodes.quickPop(1);
 715     m_prefixResolvers.pop();
 716   }
 717 
 718 
 719 
 720   /**
 721    * Set the current context node.
 722    *
 723    * @param n the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 724    */
 725   public final void pushCurrentNode(int n)
 726   {
 727     m_currentNodes.push(n);
 728   }
 729 
 730   /**
 731    * Pop the current context node.
 732    */
 733   public final void popCurrentNode()
 734   {
 735     m_currentNodes.quickPop(1);
 736   }
 737 
 738   /**
 739    * Set the current predicate root.
 740    */
 741   public final void pushPredicateRoot(int n)
 742   {
 743     m_predicateRoots.push(n);
 744   }
 745 
 746   /**
 747    * Pop the current predicate root.
 748    */
 749   public final void popPredicateRoot()
 750   {
 751     m_predicateRoots.popQuick();
 752   }
 753 
 754   /**
 755    * Get the current predicate root.
 756    */
 757   public final int getPredicateRoot()
 758   {
 759     return m_predicateRoots.peepOrNull();
 760   }
 761 
 762   /**
 763    * Set the current location path iterator root.
 764    */
 765   public final void pushIteratorRoot(int n)
 766   {
 767     m_iteratorRoots.push(n);
 768   }
 769 
 770   /**
 771    * Pop the current location path iterator root.
 772    */
 773   public final void popIteratorRoot()
 774   {
 775     m_iteratorRoots.popQuick();
 776   }
 777 
 778   /**
 779    * Get the current location path iterator root.
 780    */
 781   public final int getIteratorRoot()
 782   {
 783     return m_iteratorRoots.peepOrNull();
 784   }
 785 
 786   /** A stack of the current sub-expression nodes.  */
 787   private NodeVector m_iteratorRoots = new NodeVector();
 788 
 789   /** A stack of the current sub-expression nodes.  */
 790   private NodeVector m_predicateRoots = new NodeVector();
 791 
 792   /** A stack of the current sub-expression nodes.  */
 793   private IntStack m_currentExpressionNodes = new IntStack(RECURSIONLIMIT);
 794 
 795 
 796   public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; }
 797   public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; }
 798 
 799   private IntStack m_predicatePos = new IntStack();
 800 
 801   public final int getPredicatePos()
 802   {
 803     return m_predicatePos.peek();
 804   }
 805 
 806   public final void pushPredicatePos(int n)
 807   {
 808     m_predicatePos.push(n);
 809   }
 810 
 811   public final void popPredicatePos()
 812   {
 813     m_predicatePos.pop();
 814   }
 815 
 816   /**
 817    * Get the current node that is the expression's context (i.e. for current() support).
 818    *
 819    * @return The current sub-expression node.
 820    */
 821   public final int getCurrentExpressionNode()
 822   {
 823     return m_currentExpressionNodes.peek();
 824   }
 825 
 826   /**
 827    * Set the current node that is the expression's context (i.e. for current() support).
 828    *
 829    * @param n The sub-expression node to be current.
 830    */
 831   public final void pushCurrentExpressionNode(int n)
 832   {
 833     m_currentExpressionNodes.push(n);
 834   }
 835 
 836   /**
 837    * Pop the current node that is the expression's context
 838    * (i.e. for current() support).
 839    */
 840   public final void popCurrentExpressionNode()
 841   {
 842     m_currentExpressionNodes.quickPop(1);
 843   }
 844 
 845   private ObjectStack m_prefixResolvers
 846                                    = new ObjectStack(RECURSIONLIMIT);
 847 
 848   /**
 849    * Get the current namespace context for the xpath.
 850    *
 851    * @return the current prefix resolver for resolving prefixes to
 852    *         namespace URLs.
 853    */
 854   public final PrefixResolver getNamespaceContext()
 855   {
 856     return (PrefixResolver) m_prefixResolvers.peek();
 857   }
 858 
 859   /**
 860    * Get the current namespace context for the xpath.
 861    *
 862    * @param pr the prefix resolver to be used for resolving prefixes to
 863    *         namespace URLs.
 864    */
 865   public final void setNamespaceContext(PrefixResolver pr)
 866   {
 867     m_prefixResolvers.setTop(pr);
 868   }
 869 
 870   /**
 871    * Push a current namespace context for the xpath.
 872    *
 873    * @param pr the prefix resolver to be used for resolving prefixes to
 874    *         namespace URLs.
 875    */
 876   public final void pushNamespaceContext(PrefixResolver pr)
 877   {
 878     m_prefixResolvers.push(pr);
 879   }
 880 
 881   /**
 882    * Just increment the namespace contest stack, so that setNamespaceContext
 883    * can be used on the slot.
 884    */
 885   public final void pushNamespaceContextNull()
 886   {
 887     m_prefixResolvers.push(null);
 888   }
 889 
 890   /**
 891    * Pop the current namespace context for the xpath.
 892    */
 893   public final void popNamespaceContext()
 894   {
 895     m_prefixResolvers.pop();
 896   }
 897 
 898   //==========================================================
 899   // SECTION: Current TreeWalker contexts (for internal use)
 900   //==========================================================
 901 
 902   /**
 903    * Stack of AxesIterators.
 904    */
 905   private Stack<SubContextList> m_axesIteratorStack = new Stack<>();
 906 
 907   public Stack<SubContextList> getAxesIteratorStackStacks() { return m_axesIteratorStack; }
 908   public void setAxesIteratorStackStacks(Stack<SubContextList> s) { m_axesIteratorStack = s; }
 909 
 910   /**
 911    * Push a TreeWalker on the stack.
 912    *
 913    * @param iter A sub-context AxesWalker.
 914    * @xsl.usage internal
 915    */
 916   public final void pushSubContextList(SubContextList iter)
 917   {
 918     m_axesIteratorStack.push(iter);
 919   }
 920 
 921   /**
 922    * Pop the last pushed axes iterator.
 923    * @xsl.usage internal
 924    */
 925   public final void popSubContextList()
 926   {
 927     m_axesIteratorStack.pop();
 928   }
 929 
 930   /**
 931    * Get the current axes iterator, or return null if none.
 932    *
 933    * @return the sub-context node list.
 934    * @xsl.usage internal
 935    */
 936   public SubContextList getSubContextList()
 937   {
 938     return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.peek();
 939   }
 940 
 941   /**
 942    * Get the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>
 943    * as defined by the XSLT spec.
 944    *
 945    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>.
 946    * @xsl.usage internal
 947    */
 948 
 949   public com.sun.org.apache.xpath.internal.axes.SubContextList getCurrentNodeList()
 950   {
 951     return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.get(0);
 952   }
 953   //==========================================================
 954   // SECTION: Implementation of ExpressionContext interface
 955   //==========================================================
 956 
 957   /**
 958    * Get the current context node.
 959    * @return The current context node.
 960    */
 961   public final int getContextNode()
 962   {
 963     return this.getCurrentNode();
 964   }
 965 
 966   /**
 967    * Get the current context node list.
 968    * @return An iterator for the current context list, as
 969    * defined in XSLT.
 970    */
 971   public final DTMIterator getContextNodes()
 972   {
 973 
 974     try
 975     {
 976       DTMIterator cnl = getContextNodeList();
 977 
 978       if (null != cnl)
 979         return cnl.cloneWithReset();
 980       else
 981         return null;  // for now... this might ought to be an empty iterator.
 982     }
 983     catch (CloneNotSupportedException cnse)
 984     {
 985       return null;  // error reporting?
 986     }
 987   }
 988 
 989   XPathExpressionContext expressionContext = new XPathExpressionContext();
 990 
 991   /**
 992    * The the expression context for extensions for this context.
 993    *
 994    * @return An object that implements the ExpressionContext.
 995    */
 996   public ExpressionContext getExpressionContext()
 997   {
 998     return expressionContext;
 999   }
1000 
1001   public class XPathExpressionContext implements ExpressionContext
1002   {
1003     /**
1004      * Return the XPathContext associated with this XPathExpressionContext.
1005      * Extensions should use this judiciously and only when special processing
1006      * requirements cannot be met another way.  Consider requesting an enhancement
1007      * to the ExpressionContext interface to avoid having to call this method.
1008      * @return the XPathContext associated with this XPathExpressionContext.
1009      */
1010      public XPathContext getXPathContext()
1011      {
1012        return XPathContext.this;
1013      }
1014 
1015     /**
1016      * Return the DTMManager object.  Though XPathContext context extends
1017      * the DTMManager, it really is a proxy for the real DTMManager.  If a
1018      * caller needs to make a lot of calls to the DTMManager, it is faster
1019      * if it gets the real one from this function.
1020      */
1021      public DTMManager getDTMManager()
1022      {
1023        return m_dtmManager;
1024      }
1025 
1026     /**
1027      * Get the current context node.
1028      * @return The current context node.
1029      */
1030     public org.w3c.dom.Node getContextNode()
1031     {
1032       int context = getCurrentNode();
1033 
1034       return getDTM(context).getNode(context);
1035     }
1036 
1037     /**
1038      * Get the current context node list.
1039      * @return An iterator for the current context list, as
1040      * defined in XSLT.
1041      */
1042     public org.w3c.dom.traversal.NodeIterator getContextNodes()
1043     {
1044       return new com.sun.org.apache.xml.internal.dtm.ref.DTMNodeIterator(getContextNodeList());
1045     }
1046 
1047     /**
1048      * Get the error listener.
1049      * @return The registered error listener.
1050      */
1051     public ErrorListener getErrorListener()
1052     {
1053       return XPathContext.this.getErrorListener();
1054     }
1055     /**
1056      * Return the state of the services mechanism feature.
1057      */
1058     public boolean overrideDefaultParser() {
1059         return m_overrideDefaultParser;
1060     }
1061 
1062     /**
1063      * Set the state of the services mechanism feature.
1064      */
1065     public void setOverrideDefaultParser(boolean flag) {
1066         m_overrideDefaultParser = flag;
1067     }
1068 
1069     /**
1070      * Get the value of a node as a number.
1071      * @param n Node to be converted to a number.  May be null.
1072      * @return value of n as a number.
1073      */
1074     public double toNumber(org.w3c.dom.Node n)
1075     {
1076       // %REVIEW% You can't get much uglier than this...
1077       int nodeHandle = getDTMHandleFromNode(n);
1078       DTM dtm = getDTM(nodeHandle);
1079       XString xobj = (XString)dtm.getStringValue(nodeHandle);
1080       return xobj.num();
1081     }
1082 
1083     /**
1084      * Get the value of a node as a string.
1085      * @param n Node to be converted to a string.  May be null.
1086      * @return value of n as a string, or an empty string if n is null.
1087      */
1088     public String toString(org.w3c.dom.Node n)
1089     {
1090       // %REVIEW% You can't get much uglier than this...
1091       int nodeHandle = getDTMHandleFromNode(n);
1092       DTM dtm = getDTM(nodeHandle);
1093       XMLString strVal = dtm.getStringValue(nodeHandle);
1094       return strVal.toString();
1095     }
1096 
1097     /**
1098      * Get a variable based on it's qualified name.
1099      * @param qname The qualified name of the variable.
1100      * @return The evaluated value of the variable.
1101      * @throws javax.xml.transform.TransformerException
1102      */
1103 
1104     public final XObject getVariableOrParam(com.sun.org.apache.xml.internal.utils.QName qname)
1105               throws javax.xml.transform.TransformerException
1106     {
1107       return m_variableStacks.getVariableOrParam(XPathContext.this, qname);
1108     }
1109 
1110   }
1111 
1112  /**
1113    * Get a DTM to be used as a container for a global Result Tree
1114    * Fragment. This will always be an instance of (derived from? equivalent to?)
1115    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1116    * output to it. It may be a single DTM containing for multiple fragments,
1117    * if the implementation supports that.
1118    *
1119    * Note: The distinction between this method and getRTFDTM() is that the latter
1120    * allocates space from the dynamic variable stack (m_rtfdtm_stack), which may
1121    * be pruned away again as the templates which defined those variables are exited.
1122    * Global variables may be bound late (see XUnresolvedVariable), and never want to
1123    * be discarded, hence we need to allocate them separately and don't actually need
1124    * a stack to track them.
1125    *
1126    * @return a non-null DTM reference.
1127    */
1128   public DTM getGlobalRTFDTM()
1129   {
1130         // We probably should _NOT_ be applying whitespace filtering at this stage!
1131         //
1132         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1133         // and generate an instance of DTM which can contain multiple documents
1134         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1135         // I didn't want to change the manager API at this time, or expose
1136         // too many dependencies on its internals. (Ideally, I'd like to move
1137         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1138         // specify the subclass here.)
1139 
1140         // If it doesn't exist, or if the one already existing is in the middle of
1141         // being constructed, we need to obtain a new DTM to write into. I'm not sure
1142         // the latter will ever arise, but I'd rather be just a bit paranoid..
1143         if( m_global_rtfdtm==null || m_global_rtfdtm.isTreeIncomplete() )
1144         {
1145                 m_global_rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1146         }
1147     return m_global_rtfdtm;
1148   }
1149 
1150 
1151 
1152 
1153   /**
1154    * Get a DTM to be used as a container for a dynamic Result Tree
1155    * Fragment. This will always be an instance of (derived from? equivalent to?)
1156    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1157    * output to it. It may be a single DTM containing for multiple fragments,
1158    * if the implementation supports that.
1159    *
1160    * @return a non-null DTM reference.
1161    */
1162   public DTM getRTFDTM()
1163   {
1164         SAX2RTFDTM rtfdtm;
1165 
1166         // We probably should _NOT_ be applying whitespace filtering at this stage!
1167         //
1168         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1169         // and generate an instance of DTM which can contain multiple documents
1170         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1171         // I didn't want to change the manager API at this time, or expose
1172         // too many dependencies on its internals. (Ideally, I'd like to move
1173         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1174         // specify the subclass here.)
1175 
1176         if(m_rtfdtm_stack==null)
1177         {
1178             m_rtfdtm_stack=new ArrayList<>();
1179             rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1180             m_rtfdtm_stack.add(rtfdtm);
1181             ++m_which_rtfdtm;
1182         }
1183         else if(m_which_rtfdtm<0)
1184         {
1185             rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(++m_which_rtfdtm);
1186         }
1187         else
1188         {
1189             rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm);
1190 
1191             // It might already be under construction -- the classic example would be
1192             // an xsl:variable which uses xsl:call-template as part of its value. To
1193             // handle this recursion, we have to start a new RTF DTM, pushing the old
1194             // one onto a stack so we can return to it. This is not as uncommon a case
1195             // as we might wish, unfortunately, as some folks insist on coding XSLT
1196             // as if it were a procedural language...
1197             if(rtfdtm.isTreeIncomplete())
1198             {
1199                 if(++m_which_rtfdtm < m_rtfdtm_stack.size())
1200                     rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm);
1201                 else
1202                 {
1203                     rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1204                     m_rtfdtm_stack.add(rtfdtm);
1205                 }
1206             }
1207         }
1208 
1209     return rtfdtm;
1210   }
1211 
1212   /** Push the RTFDTM's context mark, to allows discarding RTFs added after this
1213    * point. (If it doesn't exist we don't push, since we might still be able to
1214    * get away with not creating it. That requires that excessive pops be harmless.)
1215    * */
1216   public void pushRTFContext()
1217   {
1218         m_last_pushed_rtfdtm.push(m_which_rtfdtm);
1219         if(null!=m_rtfdtm_stack)
1220                 ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark();
1221   }
1222 
1223   /** Pop the RTFDTM's context mark. This discards any RTFs added after the last
1224    * mark was set.
1225    *
1226    * If there is no RTF DTM, there's nothing to pop so this
1227    * becomes a no-op. If pushes were issued before this was called, we count on
1228    * the fact that popRewindMark is defined such that overpopping just resets
1229    * to empty.
1230    *
1231    * Complicating factor: We need to handle the case of popping back to a previous
1232    * RTF DTM, if one of the weird produce-an-RTF-to-build-an-RTF cases arose.
1233    * Basically: If pop says this DTM is now empty, then return to the previous
1234    * if one exists, in whatever state we left it in. UGLY, but hopefully the
1235    * situation which forces us to consider this will arise exceedingly rarely.
1236    * */
1237   public void popRTFContext()
1238   {
1239         int previous=m_last_pushed_rtfdtm.pop();
1240         if(null==m_rtfdtm_stack)
1241                 return;
1242 
1243         if(m_which_rtfdtm==previous)
1244         {
1245                 if(previous>=0) // guard against none-active
1246                 {
1247                         boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(previous))).popRewindMark();
1248                 }
1249         }
1250         else while(m_which_rtfdtm!=previous)
1251         {
1252                 // Empty each DTM before popping, so it's ready for reuse
1253                 // _DON'T_ pop the previous, since it's still open (which is why we
1254                 // stacked up more of these) and did not receive a mark.
1255                 boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(m_which_rtfdtm))).popRewindMark();
1256                 --m_which_rtfdtm;
1257         }
1258   }
1259 
1260   /**
1261    * Gets DTMXRTreeFrag object if one has already been created.
1262    * Creates new DTMXRTreeFrag object and adds to m_DTMXRTreeFrags  HashMap,
1263    * otherwise.
1264    * @param dtmIdentity
1265    * @return DTMXRTreeFrag
1266    */
1267   public DTMXRTreeFrag getDTMXRTreeFrag(int dtmIdentity){
1268     if(m_DTMXRTreeFrags == null){
1269       m_DTMXRTreeFrags = new HashMap<>();
1270     }
1271 
1272     if(m_DTMXRTreeFrags.containsKey(dtmIdentity)){
1273        return m_DTMXRTreeFrags.get(dtmIdentity);
1274     }else{
1275       final DTMXRTreeFrag frag = new DTMXRTreeFrag(dtmIdentity,this);
1276       m_DTMXRTreeFrags.put(dtmIdentity,frag);
1277       return frag ;
1278     }
1279   }
1280 
1281   /**
1282    * Cleans DTMXRTreeFrag objects by removing references
1283    * to DTM and XPathContext objects.
1284    */
1285   private final void releaseDTMXRTreeFrags(){
1286     if(m_DTMXRTreeFrags == null){
1287       return;
1288     }
1289     final Iterator<DTMXRTreeFrag> iter = (m_DTMXRTreeFrags.values()).iterator();
1290     while(iter.hasNext()){
1291       DTMXRTreeFrag frag = iter.next();
1292       frag.destruct();
1293       iter.remove();
1294     }
1295     m_DTMXRTreeFrags = null;
1296  }
1297 }