1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xpath;
  58. import org.apache.xpath.XPathContext;
  59. import org.apache.xpath.objects.XObject;
  60. import org.apache.xpath.res.XPATHErrorResources;
  61. import org.apache.xalan.res.XSLMessages;
  62. import javax.xml.transform.TransformerException;
  63. /**
  64. * <meta name="usage" content="internal"/>
  65. * Defines a class to keep track of a stack for
  66. * template arguments and variables.
  67. *
  68. * <p>This has been changed from the previous incarnations of this
  69. * class to be fairly low level.</p>
  70. */
  71. public class VariableStack implements Cloneable
  72. {
  73. /**
  74. * Constructor for a variable stack.
  75. */
  76. public VariableStack()
  77. {
  78. reset();
  79. }
  80. /**
  81. * Returns a clone of this variable stack.
  82. *
  83. * @return a clone of this variable stack.
  84. *
  85. * @throws CloneNotSupportedException
  86. */
  87. public synchronized Object clone() throws CloneNotSupportedException
  88. {
  89. VariableStack vs = (VariableStack) super.clone();
  90. // I *think* I can get away with a shallow clone here?
  91. vs._stackFrames = (XObject[]) _stackFrames.clone();
  92. vs._links = (int[]) _links.clone();
  93. return vs;
  94. }
  95. /**
  96. * The stack frame where all variables and params will be kept.
  97. * @serial
  98. */
  99. XObject[] _stackFrames = new XObject[XPathContext.RECURSIONLIMIT * 2];
  100. /**
  101. * The top of the stack frame (<code>_stackFrames</code>).
  102. * @serial
  103. */
  104. int _frameTop;
  105. /**
  106. * The bottom index of the current frame (relative to <code>_stackFrames</code>).
  107. * @serial
  108. */
  109. private int _currentFrameBottom;
  110. /**
  111. * The stack of frame positions. I call 'em links because of distant
  112. * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
  113. * Motorola 68000 assembler</a> memories. :-)
  114. * @serial
  115. */
  116. int[] _links = new int[XPathContext.RECURSIONLIMIT];
  117. /**
  118. * The top of the links stack.
  119. */
  120. int _linksTop;
  121. /**
  122. * Get the element at the given index, regardless of stackframe.
  123. *
  124. * @param i index from zero.
  125. *
  126. * @return The item at the given index.
  127. */
  128. public XObject elementAt(final int i)
  129. {
  130. return _stackFrames[i];
  131. }
  132. /**
  133. * Get size of the stack.
  134. *
  135. * @return the total size of the execution stack.
  136. */
  137. public int size()
  138. {
  139. return _frameTop;
  140. }
  141. /**
  142. * Reset the stack to a start position.
  143. *
  144. * @return the total size of the execution stack.
  145. */
  146. public void reset()
  147. {
  148. _frameTop = 0;
  149. _linksTop = 0;
  150. // Adding one here to the stack of frame positions will allow us always
  151. // to look one under without having to check if we're at zero.
  152. // (As long as the caller doesn't screw up link/unlink.)
  153. _links[_linksTop++] = 0;
  154. _stackFrames = new XObject[_stackFrames.length];
  155. }
  156. /**
  157. * Set the current stack frame.
  158. *
  159. * @param sf The new stack frame position.
  160. */
  161. public void setStackFrame(int sf)
  162. {
  163. _currentFrameBottom = sf;
  164. }
  165. /**
  166. * Get the position from where the search should start,
  167. * which is either the searchStart property, or the top
  168. * of the stack if that value is -1.
  169. *
  170. * @return The current stack frame position.
  171. */
  172. public int getStackFrame()
  173. {
  174. return _currentFrameBottom;
  175. }
  176. /**
  177. * Allocates memory (called a stackframe) on the stack; used to store
  178. * local variables and parameter arguments.
  179. *
  180. * <p>I use the link/unlink concept because of distant
  181. * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
  182. * Motorola 68000 assembler</a> memories.</p>
  183. *
  184. * @param size The size of the stack frame allocation. This ammount should
  185. * normally be the maximum number of variables that you can have allocated
  186. * at one time in the new stack frame.
  187. *
  188. * @return The bottom of the stack frame, from where local variable addressing
  189. * should start from.
  190. */
  191. public int link(final int size)
  192. {
  193. _currentFrameBottom = _frameTop;
  194. _frameTop += size;
  195. if (_frameTop >= _stackFrames.length)
  196. {
  197. XObject newsf[] = new XObject[_stackFrames.length + (1024 * 4) + size];
  198. System.arraycopy(_stackFrames, 0, newsf, 0, _stackFrames.length);
  199. _stackFrames = newsf;
  200. }
  201. if (_linksTop + 1 >= _links.length)
  202. {
  203. int newlinks[] = new int[_links.length + (1024 * 2)];
  204. System.arraycopy(_links, 0, newlinks, 0, _links.length);
  205. _links = newlinks;
  206. }
  207. _links[_linksTop++] = _currentFrameBottom;
  208. return _currentFrameBottom;
  209. }
  210. /**
  211. * Free up the stack frame that was last allocated with
  212. * {@link link(int size)}.
  213. */
  214. public void unlink()
  215. {
  216. _frameTop = _links[--_linksTop];
  217. _currentFrameBottom = _links[_linksTop - 1];
  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. * Set a local variable or parameter in the current stack frame.
  232. *
  233. *
  234. * @param index Local variable index relative to the current stack
  235. * frame bottom.
  236. *
  237. * @param val The value of the variable that is being set.
  238. */
  239. public void setLocalVariable(int index, XObject val)
  240. {
  241. _stackFrames[index + _currentFrameBottom] = val;
  242. }
  243. /**
  244. * Set a local variable or parameter in the specified stack frame.
  245. *
  246. *
  247. * @param index Local variable index relative to the current stack
  248. * frame bottom.
  249. * NEEDSDOC @param stackFrame
  250. *
  251. * @param val The value of the variable that is being set.
  252. */
  253. public void setLocalVariable(int index, XObject val, int stackFrame)
  254. {
  255. _stackFrames[index + stackFrame] = val;
  256. }
  257. /**
  258. * Get a local variable or parameter in the current stack frame.
  259. *
  260. *
  261. * @param xctxt The XPath context, which must be passed in order to
  262. * lazy evaluate variables.
  263. *
  264. * @param index Local variable index relative to the current stack
  265. * frame bottom.
  266. *
  267. * @return The value of the variable.
  268. *
  269. * @throws TransformerException
  270. */
  271. public XObject getLocalVariable(XPathContext xctxt, int index)
  272. throws TransformerException
  273. {
  274. index += _currentFrameBottom;
  275. XObject val = _stackFrames[index];
  276. if(null == val)
  277. throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
  278. xctxt.getSAXLocator());
  279. // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  280. // Lazy execution of variables.
  281. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  282. return (_stackFrames[index] = val.execute(xctxt));
  283. return val;
  284. }
  285. /**
  286. * Get a local variable or parameter in the current stack frame.
  287. *
  288. *
  289. * @param index Local variable index relative to the given
  290. * frame bottom.
  291. * NEEDSDOC @param frame
  292. *
  293. * @return The value of the variable.
  294. *
  295. * @throws TransformerException
  296. */
  297. public XObject getLocalVariable(int index, int frame)
  298. throws TransformerException
  299. {
  300. index += frame;
  301. XObject val = _stackFrames[index];
  302. return val;
  303. }
  304. /**
  305. * Get a local variable or parameter in the current stack frame.
  306. *
  307. *
  308. * @param xctxt The XPath context, which must be passed in order to
  309. * lazy evaluate variables.
  310. *
  311. * @param index Local variable index relative to the current stack
  312. * frame bottom.
  313. *
  314. * @return The value of the variable.
  315. *
  316. * @throws TransformerException
  317. */
  318. public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
  319. throws TransformerException
  320. {
  321. index += _currentFrameBottom;
  322. XObject val = _stackFrames[index];
  323. if(null == val)
  324. throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
  325. xctxt.getSAXLocator());
  326. // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  327. // Lazy execution of variables.
  328. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  329. return (_stackFrames[index] = val.execute(xctxt));
  330. return destructiveOK ? val : val.getFresh();
  331. }
  332. /**
  333. * Tell if a local variable has been set or not.
  334. *
  335. * @param index Local variable index relative to the current stack
  336. * frame bottom.
  337. *
  338. * @return true if the value at the index is not null.
  339. *
  340. * @throws TransformerException
  341. */
  342. public boolean isLocalSet(int index) throws TransformerException
  343. {
  344. return (_stackFrames[index + _currentFrameBottom] != null);
  345. }
  346. /** NEEDSDOC Field m_nulls */
  347. private static XObject[] m_nulls = new XObject[1024];
  348. /**
  349. * Use this to clear the variables in a section of the stack. This is
  350. * used to clear the parameter section of the stack, so that default param
  351. * values can tell if they've already been set. It is important to note that
  352. * this function has a 1K limitation.
  353. *
  354. * @param start The start position, relative to the current local stack frame.
  355. * @param len The number of slots to be cleared.
  356. */
  357. public void clearLocalSlots(int start, int len)
  358. {
  359. start += _currentFrameBottom;
  360. System.arraycopy(m_nulls, 0, _stackFrames, start, len);
  361. }
  362. /**
  363. * Set a global variable or parameter in the global stack frame.
  364. *
  365. *
  366. * @param index Local variable index relative to the global stack frame
  367. * bottom.
  368. *
  369. * @param val The value of the variable that is being set.
  370. */
  371. public void setGlobalVariable(final int index, final XObject val)
  372. {
  373. _stackFrames[index] = val;
  374. }
  375. /**
  376. * Get a global variable or parameter from the global stack frame.
  377. *
  378. *
  379. * @param xctxt The XPath context, which must be passed in order to
  380. * lazy evaluate variables.
  381. *
  382. * @param index Global variable index relative to the global stack
  383. * frame bottom.
  384. *
  385. * @return The value of the variable.
  386. *
  387. * @throws TransformerException
  388. */
  389. public XObject getGlobalVariable(XPathContext xctxt, final int index)
  390. throws TransformerException
  391. {
  392. XObject val = _stackFrames[index];
  393. // Lazy execution of variables.
  394. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  395. return (_stackFrames[index] = val.execute(xctxt));
  396. return val;
  397. }
  398. /**
  399. * Get a global variable or parameter from the global stack frame.
  400. *
  401. *
  402. * @param xctxt The XPath context, which must be passed in order to
  403. * lazy evaluate variables.
  404. *
  405. * @param index Global variable index relative to the global stack
  406. * frame bottom.
  407. *
  408. * @return The value of the variable.
  409. *
  410. * @throws TransformerException
  411. */
  412. public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
  413. throws TransformerException
  414. {
  415. XObject val = _stackFrames[index];
  416. // Lazy execution of variables.
  417. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  418. return (_stackFrames[index] = val.execute(xctxt));
  419. return destructiveOK ? val : val.getFresh();
  420. }
  421. /**
  422. * Get a variable based on it's qualified name.
  423. * This is for external use only.
  424. *
  425. * @param xctxt The XPath context, which must be passed in order to
  426. * lazy evaluate variables.
  427. *
  428. * @param qname The qualified name of the variable.
  429. *
  430. * @return The evaluated value of the variable.
  431. *
  432. * @throws javax.xml.transform.TransformerException
  433. */
  434. public XObject getVariableOrParam(
  435. XPathContext xctxt, org.apache.xml.utils.QName qname)
  436. throws javax.xml.transform.TransformerException
  437. {
  438. org.apache.xml.utils.PrefixResolver prefixResolver =
  439. xctxt.getNamespaceContext();
  440. // Get the current ElemTemplateElement, which must be pushed in as the
  441. // prefix resolver, and then walk backwards in document order, searching
  442. // for an xsl:param element or xsl:variable element that matches our
  443. // qname. If we reach the top level, use the StylesheetRoot's composed
  444. // list of top level variables and parameters.
  445. if (prefixResolver instanceof org.apache.xalan.templates.ElemTemplateElement)
  446. {
  447. org.apache.xalan.templates.ElemVariable vvar;
  448. org.apache.xalan.templates.ElemTemplateElement prev =
  449. (org.apache.xalan.templates.ElemTemplateElement) prefixResolver;
  450. if (!(prev instanceof org.apache.xalan.templates.Stylesheet))
  451. {
  452. while ( !(prev.getParentNode() instanceof org.apache.xalan.templates.Stylesheet) )
  453. {
  454. org.apache.xalan.templates.ElemTemplateElement savedprev = prev;
  455. while (null != (prev = prev.getPreviousSiblingElem()))
  456. {
  457. if (prev instanceof org.apache.xalan.templates.ElemVariable)
  458. {
  459. vvar = (org.apache.xalan.templates.ElemVariable) prev;
  460. if (vvar.getName().equals(qname))
  461. return getLocalVariable(xctxt, vvar.getIndex());
  462. }
  463. }
  464. prev = savedprev.getParentElem();
  465. }
  466. }
  467. vvar = prev.getStylesheetRoot().getVariableOrParamComposed(qname);
  468. if (null != vvar)
  469. return getGlobalVariable(xctxt, vvar.getIndex());
  470. }
  471. throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{qname.toString()})); //"Variable not resolvable: " + qname);
  472. }
  473. } // end VariableStack