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 */ 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