1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 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.functions;
  23 
  24 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  25 import com.sun.org.apache.xml.internal.utils.QName;
  26 import com.sun.org.apache.xpath.internal.Expression;
  27 import com.sun.org.apache.xpath.internal.ExpressionOwner;
  28 import com.sun.org.apache.xpath.internal.XPathVisitor;
  29 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  30 import java.util.List;
  31 
  32 /**
  33  * Base class for functions that accept an undetermined number of multiple
  34  * arguments.
  35  * @xsl.usage advanced
  36  */
  37 public class FunctionMultiArgs extends Function3Args
  38 {
  39     static final long serialVersionUID = 7117257746138417181L;
  40 
  41   /** Argument expressions that are at index 3 or greater.
  42    *  @serial */
  43   Expression[] m_args;
  44 
  45   /**
  46    * Return an expression array containing arguments at index 3 or greater.
  47    *
  48    * @return An array that contains the arguments at index 3 or greater.
  49    */
  50   public Expression[] getArgs()
  51   {
  52     return m_args;
  53   }
  54 
  55   /**
  56    * Set an argument expression for a function.  This method is called by the
  57    * XPath compiler.
  58    *
  59    * @param arg non-null expression that represents the argument.
  60    * @param argNum The argument number index.
  61    *
  62    * @throws WrongNumberArgsException If a derived class determines that the
  63    * number of arguments is incorrect.
  64    */
  65   public void setArg(Expression arg, int argNum)
  66           throws WrongNumberArgsException
  67   {
  68 
  69     if (argNum < 3)
  70       super.setArg(arg, argNum);
  71     else
  72     {
  73       if (null == m_args)
  74       {
  75         m_args = new Expression[1];
  76         m_args[0] = arg;
  77       }
  78       else
  79       {
  80 
  81         // Slow but space conservative.
  82         Expression[] args = new Expression[m_args.length + 1];
  83 
  84         System.arraycopy(m_args, 0, args, 0, m_args.length);
  85 
  86         args[m_args.length] = arg;
  87         m_args = args;
  88       }
  89       arg.exprSetParent(this);
  90     }
  91   }
  92 
  93   /**
  94    * This function is used to fixup variables from QNames to stack frame
  95    * indexes at stylesheet build time.
  96    * @param vars List of QNames that correspond to variables.  This list
  97    * should be searched backwards for the first qualified name that
  98    * corresponds to the variable reference qname.  The position of the
  99    * QName in the vector from the start of the vector will be its position
 100    * in the stack frame (but variables above the globalsTop value will need
 101    * to be offset to the current stack frame).
 102    */
 103   public void fixupVariables(List<QName> vars, int globalsSize)
 104   {
 105     super.fixupVariables(vars, globalsSize);
 106     if(null != m_args)
 107     {
 108       for (int i = 0; i < m_args.length; i++)
 109       {
 110         m_args[i].fixupVariables(vars, globalsSize);
 111       }
 112     }
 113   }
 114 
 115   /**
 116    * Check that the number of arguments passed to this function is correct.
 117    *
 118    *
 119    * @param argNum The number of arguments that is being passed to the function.
 120    *
 121    * @throws WrongNumberArgsException
 122    */
 123   public void checkNumberArgs(int argNum) throws WrongNumberArgsException{}
 124 
 125   /**
 126    * Constructs and throws a WrongNumberArgException with the appropriate
 127    * message for this function object.  This class supports an arbitrary
 128    * number of arguments, so this method must never be called.
 129    *
 130    * @throws WrongNumberArgsException
 131    */
 132   protected void reportWrongNumberArgs() throws WrongNumberArgsException {
 133     String fMsg = XSLMessages.createXPATHMessage(
 134         XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
 135         new Object[]{ "Programmer's assertion:  the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." });
 136 
 137     throw new RuntimeException(fMsg);
 138   }
 139 
 140   /**
 141    * Tell if this expression or it's subexpressions can traverse outside
 142    * the current subtree.
 143    *
 144    * @return true if traversal outside the context node's subtree can occur.
 145    */
 146   public boolean canTraverseOutsideSubtree()
 147   {
 148 
 149     if (super.canTraverseOutsideSubtree())
 150       return true;
 151     else
 152     {
 153       int n = m_args.length;
 154 
 155       for (int i = 0; i < n; i++)
 156       {
 157         if (m_args[i].canTraverseOutsideSubtree())
 158           return true;
 159       }
 160 
 161       return false;
 162     }
 163   }
 164 
 165   class ArgMultiOwner implements ExpressionOwner
 166   {
 167         int m_argIndex;
 168 
 169         ArgMultiOwner(int index)
 170         {
 171                 m_argIndex = index;
 172         }
 173 
 174     /**
 175      * @see ExpressionOwner#getExpression()
 176      */
 177     public Expression getExpression()
 178     {
 179       return m_args[m_argIndex];
 180     }
 181 
 182 
 183     /**
 184      * @see ExpressionOwner#setExpression(Expression)
 185      */
 186     public void setExpression(Expression exp)
 187     {
 188         exp.exprSetParent(FunctionMultiArgs.this);
 189         m_args[m_argIndex] = exp;
 190     }
 191   }
 192 
 193 
 194     /**
 195      * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
 196      */
 197     public void callArgVisitors(XPathVisitor visitor)
 198     {
 199       super.callArgVisitors(visitor);
 200       if (null != m_args)
 201       {
 202         int n = m_args.length;
 203         for (int i = 0; i < n; i++)
 204         {
 205           m_args[i].callVisitors(new ArgMultiOwner(i), visitor);
 206         }
 207       }
 208     }
 209 
 210     /**
 211      * @see Expression#deepEquals(Expression)
 212      */
 213     public boolean deepEquals(Expression expr)
 214     {
 215       if (!super.deepEquals(expr))
 216             return false;
 217 
 218       FunctionMultiArgs fma = (FunctionMultiArgs) expr;
 219       if (null != m_args)
 220       {
 221         int n = m_args.length;
 222         if ((null == fma) || (fma.m_args.length != n))
 223               return false;
 224 
 225         for (int i = 0; i < n; i++)
 226         {
 227           if (!m_args[i].deepEquals(fma.m_args[i]))
 228                 return false;
 229         }
 230 
 231       }
 232       else if (null != fma.m_args)
 233       {
 234           return false;
 235       }
 236 
 237       return true;
 238     }
 239 }