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    */
getDTMManager()110    public DTMManager getDTMManager()
111    {
112      return m_dtmManager;
113    }
114 
115   /**
116    * Set the state of the secure processing feature
117    */
setSecureProcessing(boolean flag)118   public void setSecureProcessing(boolean flag)
119   {
120     m_isSecureProcessing = flag;
121   }
122 
123   /**
124    * Return the state of the secure processing feature
125    */
isSecureProcessing()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    */
getDTM(javax.xml.transform.Source source, boolean unique, DTMWSFilter wsfilter, boolean incremental, boolean doIndexing)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    */
getDTM(int nodeHandle)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    */
getDTMHandleFromNode(org.w3c.dom.Node node)181   public int getDTMHandleFromNode(org.w3c.dom.Node node)
182   {
183     return m_dtmManager.getDTMHandleFromNode(node);
184   }
185 //
186 //
187   /**
188    * %TBD% Doc
189    */
getDTMIdentity(DTM dtm)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    */
createDocumentFragment()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    */
release(DTM dtm, boolean shouldHardDelete)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    */
createDTMIterator(Object xpathCompiler, int pos)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    */
createDTMIterator(String xpathString, PrefixResolver presolver)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    */
createDTMIterator(int whatToShow, DTMFilter filter, boolean entityReferenceExpansion)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    */
createDTMIterator(int node)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    */
XPathContext()306   public XPathContext()
307   {
308     this(false);
309   }
310 
XPathContext(boolean overrideDefaultParser)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    */
XPathContext(Object owner)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 
init(boolean overrideDefaultParser)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    */
reset()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    */
setSAXLocator(SourceLocator location)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    */
pushSAXLocator(SourceLocator location)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    */
pushSAXLocatorNull()410   public void pushSAXLocatorNull()
411   {
412     m_saxLocations.push(null);
413   }
414 
415 
416   /**
417    * Pop the current locater.
418    */
popSAXLocator()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    */
getSAXLocator()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    */
getOwnerObject()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    */
getVarStack()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    */
setVarStack(VariableStack varStack)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    */
getErrorListener()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    */
setErrorListener(ErrorListener listener)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    */
getURIResolver()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    */
setURIResolver(URIResolver resolver)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    */
getPrimaryReader()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    */
setPrimaryReader(XMLReader reader)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 
getContextNodeListsStack()604   public Stack<DTMIterator> getContextNodeListsStack() { return m_contextNodeLists; }
setContextNodeListsStack(Stack<DTMIterator> s)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    */
getContextNodeList()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    */
pushContextNodeList(DTMIterator nl)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    */
popContextNodeList()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 
getCurrentNodeStack()660   public IntStack getCurrentNodeStack() {return m_currentNodes; }
setCurrentNodeStack(IntStack nv)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    */
getCurrentNode()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    */
pushCurrentNodeAndExpression(int cn, int en)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    */
popCurrentNodeAndExpression()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    */
pushExpressionState(int cn, int en, PrefixResolver nc)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    */
popExpressionState()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    */
pushCurrentNode(int n)725   public final void pushCurrentNode(int n)
726   {
727     m_currentNodes.push(n);
728   }
729 
730   /**
731    * Pop the current context node.
732    */
popCurrentNode()733   public final void popCurrentNode()
734   {
735     m_currentNodes.quickPop(1);
736   }
737 
738   /**
739    * Set the current predicate root.
740    */
pushPredicateRoot(int n)741   public final void pushPredicateRoot(int n)
742   {
743     m_predicateRoots.push(n);
744   }
745 
746   /**
747    * Pop the current predicate root.
748    */
popPredicateRoot()749   public final void popPredicateRoot()
750   {
751     m_predicateRoots.popQuick();
752   }
753 
754   /**
755    * Get the current predicate root.
756    */
getPredicateRoot()757   public final int getPredicateRoot()
758   {
759     return m_predicateRoots.peepOrNull();
760   }
761 
762   /**
763    * Set the current location path iterator root.
764    */
pushIteratorRoot(int n)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    */
popIteratorRoot()773   public final void popIteratorRoot()
774   {
775     m_iteratorRoots.popQuick();
776   }
777 
778   /**
779    * Get the current location path iterator root.
780    */
getIteratorRoot()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 
getCurrentExpressionNodeStack()796   public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; }
setCurrentExpressionNodeStack(IntStack nv)797   public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; }
798 
799   private IntStack m_predicatePos = new IntStack();
800 
getPredicatePos()801   public final int getPredicatePos()
802   {
803     return m_predicatePos.peek();
804   }
805 
pushPredicatePos(int n)806   public final void pushPredicatePos(int n)
807   {
808     m_predicatePos.push(n);
809   }
810 
popPredicatePos()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    */
getCurrentExpressionNode()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    */
pushCurrentExpressionNode(int n)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    */
popCurrentExpressionNode()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    */
getNamespaceContext()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    */
setNamespaceContext(PrefixResolver pr)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    */
pushNamespaceContext(PrefixResolver pr)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    */
pushNamespaceContextNull()885   public final void pushNamespaceContextNull()
886   {
887     m_prefixResolvers.push(null);
888   }
889 
890   /**
891    * Pop the current namespace context for the xpath.
892    */
popNamespaceContext()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 
getAxesIteratorStackStacks()907   public Stack<SubContextList> getAxesIteratorStackStacks() { return m_axesIteratorStack; }
setAxesIteratorStackStacks(Stack<SubContextList> s)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    */
pushSubContextList(SubContextList iter)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    */
popSubContextList()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    */
getSubContextList()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 
getCurrentNodeList()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    */
getContextNode()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    */
getContextNodes()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    */
getExpressionContext()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      */
getXPathContext()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      */
getDTMManager()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      */
getContextNode()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      */
getContextNodes()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      */
getErrorListener()1051     public ErrorListener getErrorListener()
1052     {
1053       return XPathContext.this.getErrorListener();
1054     }
1055     /**
1056      * Return the state of the services mechanism feature.
1057      */
overrideDefaultParser()1058     public boolean overrideDefaultParser() {
1059         return m_overrideDefaultParser;
1060     }
1061 
1062     /**
1063      * Set the state of the services mechanism feature.
1064      */
setOverrideDefaultParser(boolean flag)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      */
toNumber(org.w3c.dom.Node n)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      */
toString(org.w3c.dom.Node n)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 
getVariableOrParam(com.sun.org.apache.xml.internal.utils.QName qname)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    */
getGlobalRTFDTM()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    */
getRTFDTM()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    * */
pushRTFContext()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    * */
popRTFContext()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    */
getDTMXRTreeFrag(int dtmIdentity)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    */
releaseDTMXRTreeFrags()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 }
1298