1 /*
2  * Copyright (c) 2017, 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 javax.xml.transform.TransformerException;
24 
25 import com.sun.org.apache.xalan.internal.res.XSLMessages;
26 import com.sun.org.apache.xpath.internal.objects.XObject;
27 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
28 
29 /**
30  * Defines a class to keep track of a stack for
31  * template arguments and variables.
32  *
33  * <p>This has been changed from the previous incarnations of this
34  * class to be fairly low level.</p>
35  * @xsl.usage internal
36  * @LastModified: Nov 2017
37  */
38 public class VariableStack implements Cloneable
39 {
40   /**
41    * limitation for 1K
42    */
43   public static final int CLEARLIMITATION= 1024;
44 
45   /**
46    * Constructor for a variable stack.
47    */
VariableStack()48   public VariableStack()
49   {
50     reset();
51   }
52 
53   /**
54    * Returns a clone of this variable stack.
55    *
56    * @return  a clone of this variable stack.
57    *
58    * @throws CloneNotSupportedException
59    */
clone()60   public synchronized Object clone() throws CloneNotSupportedException
61   {
62 
63     VariableStack vs = (VariableStack) super.clone();
64 
65     // I *think* I can get away with a shallow clone here?
66     vs._stackFrames = _stackFrames.clone();
67     vs._links = _links.clone();
68 
69     return vs;
70   }
71 
72   /**
73    * The stack frame where all variables and params will be kept.
74    * @serial
75    */
76   XObject[] _stackFrames = new XObject[XPathContext.RECURSIONLIMIT * 2];
77 
78   /**
79    * The top of the stack frame (<code>_stackFrames</code>).
80    * @serial
81    */
82   int _frameTop;
83 
84   /**
85    * The bottom index of the current frame (relative to <code>_stackFrames</code>).
86    * @serial
87    */
88   private int _currentFrameBottom;
89 
90   /**
91    * The stack of frame positions.  I call 'em links because of distant
92    * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
93    * Motorola 68000 assembler</a> memories.  :-)
94    * @serial
95    */
96   int[] _links = new int[XPathContext.RECURSIONLIMIT];
97 
98   /**
99    * The top of the links stack.
100    */
101   int _linksTop;
102 
103   /**
104    * Get the element at the given index, regardless of stackframe.
105    *
106    * @param i index from zero.
107    *
108    * @return The item at the given index.
109    */
elementAt(final int i)110   public XObject elementAt(final int i)
111   {
112     return _stackFrames[i];
113   }
114 
115   /**
116    * Get size of the stack.
117    *
118    * @return the total size of the execution stack.
119    */
size()120   public int size()
121   {
122     return _frameTop;
123   }
124 
125   /**
126    * Reset the stack to a start position.
127    *
128    * @return the total size of the execution stack.
129    */
reset()130   public void reset()
131   {
132 
133     _frameTop = 0;
134     _linksTop = 0;
135 
136     // Adding one here to the stack of frame positions will allow us always
137     // to look one under without having to check if we're at zero.
138     // (As long as the caller doesn't screw up link/unlink.)
139     _links[_linksTop++] = 0;
140     _stackFrames = new XObject[_stackFrames.length];
141   }
142 
143   /**
144    * Set the current stack frame.
145    *
146    * @param sf The new stack frame position.
147    */
setStackFrame(int sf)148   public void setStackFrame(int sf)
149   {
150     _currentFrameBottom = sf;
151   }
152 
153   /**
154    * Get the position from where the search should start,
155    * which is either the searchStart property, or the top
156    * of the stack if that value is -1.
157    *
158    * @return The current stack frame position.
159    */
getStackFrame()160   public int getStackFrame()
161   {
162     return _currentFrameBottom;
163   }
164 
165   /**
166    * Allocates memory (called a stackframe) on the stack; used to store
167    * local variables and parameter arguments.
168    *
169    * <p>I use the link/unlink concept because of distant
170    * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
171    * Motorola 68000 assembler</a> memories.</p>
172    *
173    * @param size The size of the stack frame allocation.  This ammount should
174    * normally be the maximum number of variables that you can have allocated
175    * at one time in the new stack frame.
176    *
177    * @return The bottom of the stack frame, from where local variable addressing
178    * should start from.
179    */
link(final int size)180   public int link(final int size)
181   {
182 
183     _currentFrameBottom = _frameTop;
184     _frameTop += size;
185 
186     if (_frameTop >= _stackFrames.length)
187     {
188       XObject newsf[] = new XObject[_stackFrames.length + XPathContext.RECURSIONLIMIT + size];
189 
190       System.arraycopy(_stackFrames, 0, newsf, 0, _stackFrames.length);
191 
192       _stackFrames = newsf;
193     }
194 
195     if (_linksTop + 1 >= _links.length)
196     {
197       int newlinks[] = new int[_links.length + (CLEARLIMITATION * 2)];
198 
199       System.arraycopy(_links, 0, newlinks, 0, _links.length);
200 
201       _links = newlinks;
202     }
203 
204     _links[_linksTop++] = _currentFrameBottom;
205 
206     return _currentFrameBottom;
207   }
208 
209   /**
210    * Free up the stack frame that was last allocated with
211    * {@link #link(int size)}.
212    */
unlink()213   public  void unlink()
214   {
215     _frameTop = _links[--_linksTop];
216     _currentFrameBottom = _links[_linksTop - 1];
217   }
218 
219   /**
220    * Free up the stack frame that was last allocated with
221    * {@link #link(int size)}.
222    * @param currentFrame The current frame to set to
223    * after the unlink.
224    */
unlink(int currentFrame)225   public  void unlink(int currentFrame)
226   {
227     _frameTop = _links[--_linksTop];
228     _currentFrameBottom = currentFrame;
229   }
230 
231   /**
232    * Set a local variable or parameter in the current stack frame.
233    *
234    *
235    * @param index Local variable index relative to the current stack
236    * frame bottom.
237    *
238    * @param val The value of the variable that is being set.
239    */
setLocalVariable(int index, XObject val)240   public void setLocalVariable(int index, XObject val)
241   {
242     _stackFrames[index + _currentFrameBottom] = val;
243   }
244 
245   /**
246    * Set a local variable or parameter in the specified stack frame.
247    *
248    *
249    * @param index Local variable index relative to the current stack
250    * frame bottom.
251    * NEEDSDOC @param stackFrame
252    *
253    * @param val The value of the variable that is being set.
254    */
setLocalVariable(int index, XObject val, int stackFrame)255   public void setLocalVariable(int index, XObject val, int stackFrame)
256   {
257     _stackFrames[index + stackFrame] = val;
258   }
259 
260   /**
261    * Get a local variable or parameter in the current stack frame.
262    *
263    *
264    * @param xctxt The XPath context, which must be passed in order to
265    * lazy evaluate variables.
266    *
267    * @param index Local variable index relative to the current stack
268    * frame bottom.
269    *
270    * @return The value of the variable.
271    *
272    * @throws TransformerException
273    */
getLocalVariable(XPathContext xctxt, int index)274   public XObject getLocalVariable(XPathContext xctxt, int index)
275           throws TransformerException
276   {
277 
278     index += _currentFrameBottom;
279 
280     XObject val = _stackFrames[index];
281 
282     if(null == val)
283       throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
284                      xctxt.getSAXLocator());
285       // "Variable accessed before it is bound!", xctxt.getSAXLocator());
286 
287     // Lazy execution of variables.
288     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
289       return (_stackFrames[index] = val.execute(xctxt));
290 
291     return val;
292   }
293 
294   /**
295    * Get a local variable or parameter in the current stack frame.
296    *
297    *
298    * @param index Local variable index relative to the given
299    * frame bottom.
300    * NEEDSDOC @param frame
301    *
302    * @return The value of the variable.
303    *
304    * @throws TransformerException
305    */
getLocalVariable(int index, int frame)306   public XObject getLocalVariable(int index, int frame)
307           throws TransformerException
308   {
309 
310     index += frame;
311 
312     XObject val = _stackFrames[index];
313 
314     return val;
315   }
316 
317   /**
318    * Get a local variable or parameter in the current stack frame.
319    *
320    *
321    * @param xctxt The XPath context, which must be passed in order to
322    * lazy evaluate variables.
323    *
324    * @param index Local variable index relative to the current stack
325    * frame bottom.
326    *
327    * @return The value of the variable.
328    *
329    * @throws TransformerException
330    */
getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)331   public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
332           throws TransformerException
333   {
334 
335     index += _currentFrameBottom;
336 
337     XObject val = _stackFrames[index];
338 
339     if(null == val)
340       throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
341                      xctxt.getSAXLocator());
342       // "Variable accessed before it is bound!", xctxt.getSAXLocator());
343 
344     // Lazy execution of variables.
345     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
346       return (_stackFrames[index] = val.execute(xctxt));
347 
348     return destructiveOK ? val : val.getFresh();
349   }
350 
351   /**
352    * Tell if a local variable has been set or not.
353    *
354    * @param index Local variable index relative to the current stack
355    * frame bottom.
356    *
357    * @return true if the value at the index is not null.
358    *
359    * @throws TransformerException
360    */
isLocalSet(int index)361   public boolean isLocalSet(int index) throws TransformerException
362   {
363     return (_stackFrames[index + _currentFrameBottom] != null);
364   }
365 
366   /** NEEDSDOC Field m_nulls          */
367   private static XObject[] m_nulls = new XObject[CLEARLIMITATION];
368 
369   /**
370    * Use this to clear the variables in a section of the stack.  This is
371    * used to clear the parameter section of the stack, so that default param
372    * values can tell if they've already been set.  It is important to note that
373    * this function has a 1K limitation.
374    *
375    * @param start The start position, relative to the current local stack frame.
376    * @param len The number of slots to be cleared.
377    */
clearLocalSlots(int start, int len)378   public void clearLocalSlots(int start, int len)
379   {
380 
381     start += _currentFrameBottom;
382 
383     System.arraycopy(m_nulls, 0, _stackFrames, start, len);
384   }
385 
386   /**
387    * Set a global variable or parameter in the global stack frame.
388    *
389    *
390    * @param index Local variable index relative to the global stack frame
391    * bottom.
392    *
393    * @param val The value of the variable that is being set.
394    */
setGlobalVariable(final int index, final XObject val)395   public void setGlobalVariable(final int index, final XObject val)
396   {
397     _stackFrames[index] = val;
398   }
399 
400   /**
401    * Get a global variable or parameter from the global stack frame.
402    *
403    *
404    * @param xctxt The XPath context, which must be passed in order to
405    * lazy evaluate variables.
406    *
407    * @param index Global variable index relative to the global stack
408    * frame bottom.
409    *
410    * @return The value of the variable.
411    *
412    * @throws TransformerException
413    */
getGlobalVariable(XPathContext xctxt, final int index)414   public XObject getGlobalVariable(XPathContext xctxt, final int index)
415           throws TransformerException
416   {
417 
418     XObject val = _stackFrames[index];
419 
420     // Lazy execution of variables.
421     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
422       return (_stackFrames[index] = val.execute(xctxt));
423 
424     return val;
425   }
426 
427   /**
428    * Get a global variable or parameter from the global stack frame.
429    *
430    *
431    * @param xctxt The XPath context, which must be passed in order to
432    * lazy evaluate variables.
433    *
434    * @param index Global variable index relative to the global stack
435    * frame bottom.
436    *
437    * @return The value of the variable.
438    *
439    * @throws TransformerException
440    */
getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)441   public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
442           throws TransformerException
443   {
444 
445     XObject val = _stackFrames[index];
446 
447     // Lazy execution of variables.
448     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
449       return (_stackFrames[index] = val.execute(xctxt));
450 
451     return destructiveOK ? val : val.getFresh();
452   }
453 
454   /**
455    * Get a variable based on it's qualified name.
456    * This is for external use only.
457    *
458    * @param xctxt The XPath context, which must be passed in order to
459    * lazy evaluate variables.
460    *
461    * @param qname The qualified name of the variable.
462    *
463    * @return The evaluated value of the variable.
464    *
465    * @throws javax.xml.transform.TransformerException
466    */
getVariableOrParam( XPathContext xctxt, com.sun.org.apache.xml.internal.utils.QName qname)467   public XObject getVariableOrParam(
468           XPathContext xctxt, com.sun.org.apache.xml.internal.utils.QName qname)
469             throws javax.xml.transform.TransformerException
470   {
471 
472     // J2SE does not support Xalan interpretive
473         /*
474     com.sun.org.apache.xml.internal.utils.PrefixResolver prefixResolver =
475       xctxt.getNamespaceContext();
476 
477     // Get the current ElemTemplateElement, which must be pushed in as the
478     // prefix resolver, and then walk backwards in document order, searching
479     // for an xsl:param element or xsl:variable element that matches our
480     // qname.  If we reach the top level, use the StylesheetRoot's composed
481     // list of top level variables and parameters.
482 
483     if (prefixResolver instanceof com.sun.org.apache.xalan.internal.templates.ElemTemplateElement)
484     {
485 
486       com.sun.org.apache.xalan.internal.templates.ElemVariable vvar;
487 
488       com.sun.org.apache.xalan.internal.templates.ElemTemplateElement prev =
489         (com.sun.org.apache.xalan.internal.templates.ElemTemplateElement) prefixResolver;
490 
491       if (!(prev instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet))
492       {
493         while ( !(prev.getParentNode() instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet) )
494         {
495           com.sun.org.apache.xalan.internal.templates.ElemTemplateElement savedprev = prev;
496 
497           while (null != (prev = prev.getPreviousSiblingElem()))
498           {
499             if (prev instanceof com.sun.org.apache.xalan.internal.templates.ElemVariable)
500             {
501               vvar = (com.sun.org.apache.xalan.internal.templates.ElemVariable) prev;
502 
503               if (vvar.getName().equals(qname))
504                 return getLocalVariable(xctxt, vvar.getIndex());
505             }
506           }
507           prev = savedprev.getParentElem();
508         }
509       }
510 
511       vvar = prev.getStylesheetRoot().getVariableOrParamComposed(qname);
512       if (null != vvar)
513         return getGlobalVariable(xctxt, vvar.getIndex());
514     }
515     */
516 
517     throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{qname.toString()})); //"Variable not resolvable: " + qname);
518   }
519 }  // end VariableStack
520