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.axes;
  22 
  23 import com.sun.org.apache.xml.internal.dtm.Axis;
  24 import com.sun.org.apache.xml.internal.dtm.DTM;
  25 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  26 import com.sun.org.apache.xml.internal.utils.QName;
  27 import com.sun.org.apache.xpath.internal.Expression;
  28 import com.sun.org.apache.xpath.internal.ExpressionOwner;
  29 import com.sun.org.apache.xpath.internal.XPathContext;
  30 import com.sun.org.apache.xpath.internal.XPathVisitor;
  31 import com.sun.org.apache.xpath.internal.compiler.Compiler;
  32 import com.sun.org.apache.xpath.internal.compiler.OpCodes;
  33 import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  34 import java.util.List;
  35 
  36 /**
  37  * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
  38  * op codes.
  39  * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a>
  40  * @LastModified: Oct 2017
  41  */
  42 public class FilterExprWalker extends AxesWalker
  43 {
  44     static final long serialVersionUID = 5457182471424488375L;
  45 
  46   /**
  47    * Construct a FilterExprWalker using a LocPathIterator.
  48    *
  49    * @param locPathIterator non-null reference to the parent iterator.
  50    */
  51   public FilterExprWalker(WalkingIterator locPathIterator)
  52   {
  53     super(locPathIterator, Axis.FILTEREDLIST);
  54   }
  55 
  56   /**
  57    * Init a FilterExprWalker.
  58    *
  59    * @param compiler non-null reference to the Compiler that is constructing.
  60    * @param opPos positive opcode position for this step.
  61    * @param stepType The type of step.
  62    *
  63    * @throws javax.xml.transform.TransformerException
  64    */
  65   @SuppressWarnings("fallthrough")
  66   public void init(Compiler compiler, int opPos, int stepType)
  67           throws javax.xml.transform.TransformerException
  68   {
  69 
  70     super.init(compiler, opPos, stepType);
  71 
  72     // Smooth over an anomily in the opcode map...
  73     switch (stepType)
  74     {
  75     case OpCodes.OP_FUNCTION :
  76     case OpCodes.OP_EXTFUNCTION :
  77         m_mustHardReset = true;
  78     case OpCodes.OP_GROUP :
  79     case OpCodes.OP_VARIABLE :
  80       m_expr = compiler.compile(opPos);
  81       m_expr.exprSetParent(this);
  82       //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof com.sun.org.apache.xalan.internal.templates.FuncKey))
  83       if(m_expr instanceof com.sun.org.apache.xpath.internal.operations.Variable)
  84       {
  85         // hack/temp workaround
  86         m_canDetachNodeset = false;
  87       }
  88       break;
  89     default :
  90       m_expr = compiler.compile(opPos + 2);
  91       m_expr.exprSetParent(this);
  92     }
  93 //    if(m_expr instanceof WalkingIterator)
  94 //    {
  95 //      WalkingIterator wi = (WalkingIterator)m_expr;
  96 //      if(wi.getFirstWalker() instanceof FilterExprWalker)
  97 //      {
  98 //              FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
  99 //              if(null == fw.getNextWalker())
 100 //              {
 101 //                      m_expr = fw.m_expr;
 102 //                      m_expr.exprSetParent(this);
 103 //              }
 104 //      }
 105 //
 106 //    }
 107   }
 108 
 109   /**
 110    * Detaches the walker from the set which it iterated over, releasing
 111    * any computational resources and placing the iterator in the INVALID
 112    * state.
 113    */
 114   public void detach()
 115   {
 116         super.detach();
 117         if (m_canDetachNodeset)
 118         {
 119           m_exprObj.detach();
 120         }
 121         m_exprObj = null;
 122   }
 123 
 124   /**
 125    *  Set the root node of the TreeWalker.
 126    *
 127    * @param root non-null reference to the root, or starting point of
 128    *        the query.
 129    */
 130   public void setRoot(int root)
 131   {
 132 
 133     super.setRoot(root);
 134 
 135         m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root,
 136                           m_lpi.getXPathContext(), m_lpi.getPrefixResolver(),
 137                           m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
 138 
 139   }
 140 
 141   /**
 142    * Get a cloned FilterExprWalker.
 143    *
 144    * @return A new FilterExprWalker that can be used without mutating this one.
 145    *
 146    * @throws CloneNotSupportedException
 147    */
 148   public Object clone() throws CloneNotSupportedException
 149   {
 150 
 151     FilterExprWalker clone = (FilterExprWalker) super.clone();
 152 
 153     // clone.m_expr = (Expression)((Expression)m_expr).clone();
 154     if (null != m_exprObj)
 155       clone.m_exprObj = (XNodeSet) m_exprObj.clone();
 156 
 157     return clone;
 158   }
 159 
 160   /**
 161    * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
 162    * don't need to, and shouldn't, do a node test.
 163    * @param n  The node to check to see if it passes the filter or not.
 164    * @return  a constant to determine whether the node is accepted,
 165    *   rejected, or skipped, as defined  above .
 166    */
 167   public short acceptNode(int n)
 168   {
 169 
 170     try
 171     {
 172       if (getPredicateCount() > 0)
 173       {
 174         countProximityPosition(0);
 175 
 176         if (!executePredicates(n, m_lpi.getXPathContext()))
 177           return DTMIterator.FILTER_SKIP;
 178       }
 179 
 180       return DTMIterator.FILTER_ACCEPT;
 181     }
 182     catch (javax.xml.transform.TransformerException se)
 183     {
 184       throw new RuntimeException(se.getMessage());
 185     }
 186   }
 187 
 188   /**
 189    *  Moves the <code>TreeWalker</code> to the next visible node in document
 190    * order relative to the current node, and returns the new node. If the
 191    * current node has no next node,  or if the search for nextNode attempts
 192    * to step upward from the TreeWalker's root node, returns
 193    * <code>null</code> , and retains the current node.
 194    * @return  The new node, or <code>null</code> if the current node has no
 195    *   next node  in the TreeWalker's logical view.
 196    */
 197   public int getNextNode()
 198   {
 199 
 200     if (null != m_exprObj)
 201     {
 202        int next = m_exprObj.nextNode();
 203        return next;
 204     }
 205     else
 206       return DTM.NULL;
 207   }
 208 
 209   /**
 210    * Get the index of the last node that can be itterated to.
 211    *
 212    *
 213    * @param xctxt XPath runtime context.
 214    *
 215    * @return the index of the last node that can be itterated to.
 216    */
 217   public int getLastPos(XPathContext xctxt)
 218   {
 219     return m_exprObj.getLength();
 220   }
 221 
 222   /** The contained expression. Should be non-null.
 223    *  @serial   */
 224   private Expression m_expr;
 225 
 226   /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
 227   transient private XNodeSet m_exprObj;
 228 
 229   private boolean m_mustHardReset = false;
 230   private boolean m_canDetachNodeset = true;
 231 
 232   /**
 233    * This function is used to fixup variables from QNames to stack frame
 234    * indexes at stylesheet build time.
 235    * @param vars List of QNames that correspond to variables.  This list
 236    * should be searched backwards for the first qualified name that
 237    * corresponds to the variable reference qname.  The position of the
 238    * QName in the vector from the start of the vector will be its position
 239    * in the stack frame (but variables above the globalsTop value will need
 240    * to be offset to the current stack frame).
 241    */
 242   public void fixupVariables(List<QName> vars, int globalsSize)
 243   {
 244     super.fixupVariables(vars, globalsSize);
 245     m_expr.fixupVariables(vars, globalsSize);
 246   }
 247 
 248   /**
 249    * Get the inner contained expression of this filter.
 250    */
 251   public Expression getInnerExpression()
 252   {
 253         return m_expr;
 254   }
 255 
 256   /**
 257    * Set the inner contained expression of this filter.
 258    */
 259   public void setInnerExpression(Expression expr)
 260   {
 261         expr.exprSetParent(this);
 262         m_expr = expr;
 263   }
 264 
 265 
 266   /**
 267    * Get the analysis bits for this walker, as defined in the WalkerFactory.
 268    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
 269    */
 270   public int getAnalysisBits()
 271   {
 272       if (null != m_expr && m_expr instanceof PathComponent)
 273       {
 274         return ((PathComponent) m_expr).getAnalysisBits();
 275       }
 276       return WalkerFactory.BIT_FILTER;
 277   }
 278 
 279   /**
 280    * Returns true if all the nodes in the iteration well be returned in document
 281    * order.
 282    * Warning: This can only be called after setRoot has been called!
 283    *
 284    * @return true as a default.
 285    */
 286   public boolean isDocOrdered()
 287   {
 288     return m_exprObj.isDocOrdered();
 289   }
 290 
 291   /**
 292    * Returns the axis being iterated, if it is known.
 293    *
 294    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
 295    * types.
 296    */
 297   public int getAxis()
 298   {
 299     return m_exprObj.getAxis();
 300   }
 301 
 302   class filterExprOwner implements ExpressionOwner
 303   {
 304       /**
 305      * @see ExpressionOwner#getExpression()
 306      */
 307     public Expression getExpression()
 308     {
 309       return m_expr;
 310     }
 311 
 312     /**
 313      * @see ExpressionOwner#setExpression(Expression)
 314      */
 315     public void setExpression(Expression exp)
 316     {
 317         exp.exprSetParent(FilterExprWalker.this);
 318         m_expr = exp;
 319     }
 320   }
 321 
 322         /**
 323          * This will traverse the heararchy, calling the visitor for
 324          * each member.  If the called visitor method returns
 325          * false, the subtree should not be called.
 326          *
 327          * @param visitor The visitor whose appropriate method will be called.
 328          */
 329         public void callPredicateVisitors(XPathVisitor visitor)
 330         {
 331           m_expr.callVisitors(new filterExprOwner(), visitor);
 332 
 333           super.callPredicateVisitors(visitor);
 334         }
 335 
 336 
 337     /**
 338      * @see Expression#deepEquals(Expression)
 339      */
 340     public boolean deepEquals(Expression expr)
 341     {
 342       if (!super.deepEquals(expr))
 343                 return false;
 344 
 345       FilterExprWalker walker = (FilterExprWalker)expr;
 346       if(!m_expr.deepEquals(walker.m_expr))
 347         return false;
 348 
 349       return true;
 350     }
 351 
 352 
 353 
 354 }