content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id: VariableStack.java,v 1.2.4.1 2005/09/10 18:16:22 jeffsuttor Exp $
   */
  package jaxp.sun.org.apache.xpath.internal;
  
  import jaxp.xml.transform.TransformerException;
  
  import jaxp.sun.org.apache.xalan.internal.res.XSLMessages;
  
  import jaxp.sun.org.apache.xml.internal.utils.QName;
  import jaxp.sun.org.apache.xpath.internal.objects.XObject;
  import jaxp.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  
  /**
   * Defines a class to keep track of a stack for
   * template arguments and variables.
   *
   * <p>This has been changed from the previous incarnations of this
   * class to be fairly low level.</p>
   * @xsl.usage internal
   */
  public class VariableStack implements Cloneable
  {
    /**
     * limitation for 1K
     */
    public static final int CLEARLIMITATION= 1024;
  
    /**
     * Constructor for a variable stack.
     */
    public VariableStack()
    {
      reset();
    }
  
    /**
     * Returns a clone of this variable stack.
     *
     * @return  a clone of this variable stack.
     *
     * @throws CloneNotSupportedException
     */
    public synchronized Object clone() throws CloneNotSupportedException
    {
  
      VariableStack vs = (VariableStack) super.clone();
  
      // I *think* I can get away with a shallow clone here?
      vs._stackFrames = (XObject[]) _stackFrames.clone();
      vs._links = (int[]) _links.clone();
  
      return vs;
    }
  
    /**
     * The stack frame where all variables and params will be kept.
     * @serial
     */
    XObject[] _stackFrames = new XObject[XPathContext.RECURSIONLIMIT * 2];
  
    /**
     * The top of the stack frame (<code>_stackFrames</code>).
     * @serial
     */
    int _frameTop;
  
    /**
     * The bottom index of the current frame (relative to <code>_stackFrames</code>).
     * @serial
     */
    private int _currentFrameBottom;
  
    /**
     * The stack of frame positions.  I call 'em links because of distant
     * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
     * Motorola 68000 assembler</a> memories.  :-)
     * @serial
     */
    int[] _links = new int[XPathContext.RECURSIONLIMIT];
  
    /**
     * The top of the links stack.
     */
    int _linksTop;
  
    /**
     * Get the element at the given index, regardless of stackframe.
     *
     * @param i index from zero.
     *
     * @return The item at the given index.
     */
    public XObject elementAt(final int i)
    {
      return _stackFrames[i];
    }
  
    /**
     * Get size of the stack.
     *
     * @return the total size of the execution stack.
     */
    public int size()
    {
      return _frameTop;
    }
  
    /**
     * Reset the stack to a start position.
     *
     * @return the total size of the execution stack.
     */
    public void reset()
    {
  
      _frameTop = 0;
      _linksTop = 0;
  
      // Adding one here to the stack of frame positions will allow us always
      // to look one under without having to check if we're at zero.
      // (As long as the caller doesn't screw up link/unlink.)
      _links[_linksTop++] = 0;
      _stackFrames = new XObject[_stackFrames.length];
    }
  
    /**
     * Set the current stack frame.
     *
     * @param sf The new stack frame position.
     */
    public void setStackFrame(int sf)
    {
      _currentFrameBottom = sf;
    }
  
    /**
     * Get the position from where the search should start,
     * which is either the searchStart property, or the top
     * of the stack if that value is -1.
     *
     * @return The current stack frame position.
     */
    public int getStackFrame()
    {
      return _currentFrameBottom;
    }
  
    /**
     * Allocates memory (called a stackframe) on the stack; used to store
     * local variables and parameter arguments.
     *
     * <p>I use the link/unlink concept because of distant
     * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
     * Motorola 68000 assembler</a> memories.</p>
     *
     * @param size The size of the stack frame allocation.  This ammount should
     * normally be the maximum number of variables that you can have allocated
     * at one time in the new stack frame.
     *
     * @return The bottom of the stack frame, from where local variable addressing
     * should start from.
     */
    public int link(final int size)
    {
  
      _currentFrameBottom = _frameTop;
      _frameTop += size;
  
      if (_frameTop >= _stackFrames.length)
      {
        XObject newsf[] = new XObject[_stackFrames.length + XPathContext.RECURSIONLIMIT + size];
  
        System.arraycopy(_stackFrames, 0, newsf, 0, _stackFrames.length);
  
        _stackFrames = newsf;
      }
  
      if (_linksTop + 1 >= _links.length)
      {
        int newlinks[] = new int[_links.length + (CLEARLIMITATION * 2)];
  
        System.arraycopy(_links, 0, newlinks, 0, _links.length);
  
        _links = newlinks;
      }
  
      _links[_linksTop++] = _currentFrameBottom;
  
      return _currentFrameBottom;
    }
  
    /**
     * Free up the stack frame that was last allocated with
     * {@link #link(int size)}.
     */
    public  void unlink()
    {
      _frameTop = _links[--_linksTop];
      _currentFrameBottom = _links[_linksTop - 1];
    }
  
    /**
     * Free up the stack frame that was last allocated with
     * {@link #link(int size)}.
     * @param currentFrame The current frame to set to
     * after the unlink.
     */
    public  void unlink(int currentFrame)
    {
      _frameTop = _links[--_linksTop];
      _currentFrameBottom = currentFrame;
    }
  
    /**
     * Set a local variable or parameter in the current stack frame.
     *
     *
     * @param index Local variable index relative to the current stack
     * frame bottom.
     *
     * @param val The value of the variable that is being set.
     */
    public void setLocalVariable(int index, XObject val)
    {
      _stackFrames[index + _currentFrameBottom] = val;
    }
  
    /**
     * Set a local variable or parameter in the specified stack frame.
     *
     *
     * @param index Local variable index relative to the current stack
     * frame bottom.
     * NEEDSDOC @param stackFrame
     *
     * @param val The value of the variable that is being set.
     */
    public void setLocalVariable(int index, XObject val, int stackFrame)
    {
      _stackFrames[index + stackFrame] = val;
    }
  
    /**
     * Get a local variable or parameter in the current stack frame.
     *
     *
     * @param xctxt The XPath context, which must be passed in order to
     * lazy evaluate variables.
     *
     * @param index Local variable index relative to the current stack
     * frame bottom.
     *
     * @return The value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getLocalVariable(XPathContext xctxt, int index)
            throws TransformerException
    {
  
      index += _currentFrameBottom;
  
      XObject val = _stackFrames[index];
  
      if(null == val)
        throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
                       xctxt.getSAXLocator());
        // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  
      // Lazy execution of variables.
      if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
        return (_stackFrames[index] = val.execute(xctxt));
  
      return val;
    }
  
    /**
     * Get a local variable or parameter in the current stack frame.
     *
     *
     * @param index Local variable index relative to the given
     * frame bottom.
     * NEEDSDOC @param frame
     *
     * @return The value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getLocalVariable(int index, int frame)
            throws TransformerException
    {
  
      index += frame;
  
      XObject val = _stackFrames[index];
  
      return val;
    }
  
    /**
     * Get a local variable or parameter in the current stack frame.
     *
     *
     * @param xctxt The XPath context, which must be passed in order to
     * lazy evaluate variables.
     *
     * @param index Local variable index relative to the current stack
     * frame bottom.
     *
     * @return The value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
            throws TransformerException
    {
  
      index += _currentFrameBottom;
  
      XObject val = _stackFrames[index];
  
      if(null == val)
        throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
                       xctxt.getSAXLocator());
        // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  
      // Lazy execution of variables.
      if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
        return (_stackFrames[index] = val.execute(xctxt));
  
      return destructiveOK ? val : val.getFresh();
    }
  
    /**
     * Tell if a local variable has been set or not.
     *
     * @param index Local variable index relative to the current stack
     * frame bottom.
     *
     * @return true if the value at the index is not null.
     *
     * @throws TransformerException
     */
    public boolean isLocalSet(int index) throws TransformerException
    {
      return (_stackFrames[index + _currentFrameBottom] != null);
    }
  
    /** NEEDSDOC Field m_nulls          */
    private static XObject[] m_nulls = new XObject[CLEARLIMITATION];
  
    /**
     * Use this to clear the variables in a section of the stack.  This is
     * used to clear the parameter section of the stack, so that default param
     * values can tell if they've already been set.  It is important to note that
     * this function has a 1K limitation.
     *
     * @param start The start position, relative to the current local stack frame.
     * @param len The number of slots to be cleared.
     */
    public void clearLocalSlots(int start, int len)
    {
  
      start += _currentFrameBottom;
  
      System.arraycopy(m_nulls, 0, _stackFrames, start, len);
    }
  
    /**
     * Set a global variable or parameter in the global stack frame.
     *
     *
     * @param index Local variable index relative to the global stack frame
     * bottom.
     *
     * @param val The value of the variable that is being set.
     */
    public void setGlobalVariable(final int index, final XObject val)
    {
      _stackFrames[index] = val;
    }
  
    /**
     * Get a global variable or parameter from the global stack frame.
     *
     *
     * @param xctxt The XPath context, which must be passed in order to
     * lazy evaluate variables.
     *
     * @param index Global variable index relative to the global stack
     * frame bottom.
     *
     * @return The value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getGlobalVariable(XPathContext xctxt, final int index)
            throws TransformerException
    {
  
      XObject val = _stackFrames[index];
  
      // Lazy execution of variables.
      if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
        return (_stackFrames[index] = val.execute(xctxt));
  
      return val;
    }
  
    /**
     * Get a global variable or parameter from the global stack frame.
     *
     *
     * @param xctxt The XPath context, which must be passed in order to
     * lazy evaluate variables.
     *
     * @param index Global variable index relative to the global stack
     * frame bottom.
     *
     * @return The value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
            throws TransformerException
    {
  
      XObject val = _stackFrames[index];
  
      // Lazy execution of variables.
      if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
        return (_stackFrames[index] = val.execute(xctxt));
  
      return destructiveOK ? val : val.getFresh();
    }
  
    /**
     * Get a variable based on it's qualified name.
     * This is for external use only.
     *
     * @param xctxt The XPath context, which must be passed in order to
     * lazy evaluate variables.
     *
     * @param qname The qualified name of the variable.
     *
     * @return The evaluated value of the variable.
     *
     * @throws TransformerException
     */
    public XObject getVariableOrParam(
            XPathContext xctxt, QName qname)
              throws TransformerException
    {
  
      // J2SE does not support Xalan interpretive
          /*
      com.sun.org.apache.xml.internal.utils.PrefixResolver prefixResolver =
        xctxt.getNamespaceContext();
  
      // Get the current ElemTemplateElement, which must be pushed in as the
      // prefix resolver, and then walk backwards in document order, searching
      // for an xsl:param element or xsl:variable element that matches our
      // qname.  If we reach the top level, use the StylesheetRoot's composed
      // list of top level variables and parameters.
  
      if (prefixResolver instanceof com.sun.org.apache.xalan.internal.templates.ElemTemplateElement)
      {
  
        com.sun.org.apache.xalan.internal.templates.ElemVariable vvar;
  
        com.sun.org.apache.xalan.internal.templates.ElemTemplateElement prev =
          (com.sun.org.apache.xalan.internal.templates.ElemTemplateElement) prefixResolver;
  
        if (!(prev instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet))
        {
          while ( !(prev.getParentNode() instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet) )
          {
            com.sun.org.apache.xalan.internal.templates.ElemTemplateElement savedprev = prev;
  
            while (null != (prev = prev.getPreviousSiblingElem()))
            {
              if (prev instanceof com.sun.org.apache.xalan.internal.templates.ElemVariable)
              {
                vvar = (com.sun.org.apache.xalan.internal.templates.ElemVariable) prev;
  
                if (vvar.getName().equals(qname))
                  return getLocalVariable(xctxt, vvar.getIndex());
              }
            }
            prev = savedprev.getParentElem();
          }
        }
  
        vvar = prev.getStylesheetRoot().getVariableOrParamComposed(qname);
        if (null != vvar)
          return getGlobalVariable(xctxt, vvar.getIndex());
      }
      */
  
      throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{qname.toString()})); //"Variable not resolvable: " + qname);
    }
  }  // end VariableStack
  