1 /*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 * @LastModified: Nov 2017
4 */
5 /*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements. See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 package com.sun.org.apache.xpath.internal;
23
24 import javax.xml.transform.TransformerException;
25
26 import com.sun.org.apache.xalan.internal.res.XSLMessages;
27 import com.sun.org.apache.xpath.internal.objects.XObject;
28 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
29
30 /**
31 * Defines a class to keep track of a stack for
32 * template arguments and variables.
33 *
34 * <p>This has been changed from the previous incarnations of this
35 * class to be fairly low level.</p>
36 * @xsl.usage internal
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
--- EOF ---