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.DTM;
  24 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  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.VariableStack;
  29 import com.sun.org.apache.xpath.internal.XPathVisitor;
  30 import com.sun.org.apache.xpath.internal.compiler.Compiler;
  31 import com.sun.org.apache.xpath.internal.compiler.OpMap;
  32 import java.util.List;
  33 
  34 /**
  35  * Location path iterator that uses Walkers.
  36  *
  37  * @LastModified: Oct 2017
  38  */
  39 
  40 public class WalkingIterator extends LocPathIterator implements ExpressionOwner
  41 {
  42     static final long serialVersionUID = 9110225941815665906L;
  43   /**
  44    * Create a WalkingIterator iterator, including creation
  45    * of step walkers from the opcode list, and call back
  46    * into the Compiler to create predicate expressions.
  47    *
  48    * @param compiler The Compiler which is creating
  49    * this expression.
  50    * @param opPos The position of this iterator in the
  51    * opcode list from the compiler.
  52    * @param shouldLoadWalkers True if walkers should be
  53    * loaded, or false if this is a derived iterator and
  54    * it doesn't wish to load child walkers.
  55    *
  56    * @throws javax.xml.transform.TransformerException
  57    */
  58   WalkingIterator(
  59           Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
  60             throws javax.xml.transform.TransformerException
  61   {
  62     super(compiler, opPos, analysis, shouldLoadWalkers);
  63 
  64     int firstStepPos = OpMap.getFirstChildPos(opPos);
  65 
  66     if (shouldLoadWalkers)
  67     {
  68       m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0);
  69       m_lastUsedWalker = m_firstWalker;
  70     }
  71   }
  72 
  73   /**
  74    * Create a WalkingIterator object.
  75    *
  76    * @param nscontext The namespace context for this iterator,
  77    * should be OK if null.
  78    */
  79   public WalkingIterator(PrefixResolver nscontext)
  80   {
  81 
  82     super(nscontext);
  83   }
  84 
  85 
  86   /**
  87    * Get the analysis bits for this walker, as defined in the WalkerFactory.
  88    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
  89    */
  90   public int getAnalysisBits()
  91   {
  92     int bits = 0;
  93     if (null != m_firstWalker)
  94     {
  95       AxesWalker walker = m_firstWalker;
  96 
  97       while (null != walker)
  98       {
  99         int bit = walker.getAnalysisBits();
 100         bits |= bit;
 101         walker = walker.getNextWalker();
 102       }
 103     }
 104     return bits;
 105   }
 106 
 107   /**
 108    * Get a cloned WalkingIterator that holds the same
 109    * position as this iterator.
 110    *
 111    * @return A clone of this iterator that holds the same node position.
 112    *
 113    * @throws CloneNotSupportedException
 114    */
 115   public Object clone() throws CloneNotSupportedException
 116   {
 117 
 118     WalkingIterator clone = (WalkingIterator) super.clone();
 119 
 120     //    clone.m_varStackPos = this.m_varStackPos;
 121     //    clone.m_varStackContext = this.m_varStackContext;
 122     if (null != m_firstWalker)
 123     {
 124       clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null);
 125     }
 126 
 127     return clone;
 128   }
 129 
 130   /**
 131    * Reset the iterator.
 132    */
 133   public void reset()
 134   {
 135 
 136     super.reset();
 137 
 138     if (null != m_firstWalker)
 139     {
 140       m_lastUsedWalker = m_firstWalker;
 141 
 142       m_firstWalker.setRoot(m_context);
 143     }
 144 
 145   }
 146 
 147   /**
 148    * Initialize the context values for this expression
 149    * after it is cloned.
 150    *
 151    * @param context The XPath runtime context for this
 152    * transformation.
 153    */
 154   public void setRoot(int context, Object environment)
 155   {
 156 
 157     super.setRoot(context, environment);
 158 
 159     if(null != m_firstWalker)
 160     {
 161       m_firstWalker.setRoot(context);
 162       m_lastUsedWalker = m_firstWalker;
 163     }
 164   }
 165 
 166   /**
 167    *  Returns the next node in the set and advances the position of the
 168    * iterator in the set. After a NodeIterator is created, the first call
 169    * to nextNode() returns the first node in the set.
 170    * @return  The next <code>Node</code> in the set being iterated over, or
 171    *   <code>null</code> if there are no more members in that set.
 172    */
 173   public int nextNode()
 174   {
 175         if(m_foundLast)
 176                 return DTM.NULL;
 177 
 178     // If the variable stack position is not -1, we'll have to
 179     // set our position in the variable stack, so our variable access
 180     // will be correct.  Iterators that are at the top level of the
 181     // expression need to reset the variable stack, while iterators
 182     // in predicates do not need to, and should not, since their execution
 183     // may be much later than top-level iterators.
 184     // m_varStackPos is set in setRoot, which is called
 185     // from the execute method.
 186     if (-1 == m_stackFrame)
 187     {
 188       return returnNextNode(m_firstWalker.nextNode());
 189     }
 190     else
 191     {
 192       VariableStack vars = m_execContext.getVarStack();
 193 
 194       // These three statements need to be combined into one operation.
 195       int savedStart = vars.getStackFrame();
 196 
 197       vars.setStackFrame(m_stackFrame);
 198 
 199       int n = returnNextNode(m_firstWalker.nextNode());
 200 
 201       // These two statements need to be combined into one operation.
 202       vars.setStackFrame(savedStart);
 203 
 204       return n;
 205     }
 206   }
 207 
 208 
 209   /**
 210    * Get the head of the walker list.
 211    *
 212    * @return The head of the walker list, or null
 213    * if this iterator does not implement walkers.
 214    * @xsl.usage advanced
 215    */
 216   public final AxesWalker getFirstWalker()
 217   {
 218     return m_firstWalker;
 219   }
 220 
 221   /**
 222    * Set the head of the walker list.
 223    *
 224    * @param walker Should be a valid AxesWalker.
 225    * @xsl.usage advanced
 226    */
 227   public final void setFirstWalker(AxesWalker walker)
 228   {
 229     m_firstWalker = walker;
 230   }
 231 
 232 
 233   /**
 234    * Set the last used walker.
 235    *
 236    * @param walker The last used walker, or null.
 237    * @xsl.usage advanced
 238    */
 239   public final void setLastUsedWalker(AxesWalker walker)
 240   {
 241     m_lastUsedWalker = walker;
 242   }
 243 
 244   /**
 245    * Get the last used walker.
 246    *
 247    * @return The last used walker, or null.
 248    * @xsl.usage advanced
 249    */
 250   public final AxesWalker getLastUsedWalker()
 251   {
 252     return m_lastUsedWalker;
 253   }
 254 
 255   /**
 256    *  Detaches the iterator from the set which it iterated over, releasing
 257    * any computational resources and placing the iterator in the INVALID
 258    * state. After<code>detach</code> has been invoked, calls to
 259    * <code>nextNode</code> or<code>previousNode</code> will raise the
 260    * exception INVALID_STATE_ERR.
 261    */
 262   public void detach()
 263   {
 264     if(m_allowDetach)
 265     {
 266                 AxesWalker walker = m_firstWalker;
 267             while (null != walker)
 268             {
 269               walker.detach();
 270               walker = walker.getNextWalker();
 271             }
 272 
 273             m_lastUsedWalker = null;
 274 
 275             // Always call the superclass detach last!
 276             super.detach();
 277     }
 278   }
 279 
 280   /**
 281    * This function is used to fixup variables from QNames to stack frame
 282    * indexes at stylesheet build time.
 283    * @param vars List of QNames that correspond to variables.  This list
 284    * should be searched backwards for the first qualified name that
 285    * corresponds to the variable reference qname.  The position of the
 286    * QName in the vector from the start of the vector will be its position
 287    * in the stack frame (but variables above the globalsTop value will need
 288    * to be offset to the current stack frame).
 289    */
 290   public void fixupVariables(List<QName> vars, int globalsSize)
 291   {
 292     m_predicateIndex = -1;
 293 
 294     AxesWalker walker = m_firstWalker;
 295 
 296     while (null != walker)
 297     {
 298       walker.fixupVariables(vars, globalsSize);
 299       walker = walker.getNextWalker();
 300     }
 301   }
 302 
 303   /**
 304    * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
 305    */
 306   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
 307   {
 308                 if(visitor.visitLocationPath(owner, this))
 309                 {
 310                         if(null != m_firstWalker)
 311                         {
 312                                 m_firstWalker.callVisitors(this, visitor);
 313                         }
 314                 }
 315   }
 316 
 317 
 318   /** The last used step walker in the walker list.
 319    *  @serial */
 320   protected AxesWalker m_lastUsedWalker;
 321 
 322   /** The head of the step walker list.
 323    *  @serial */
 324   protected AxesWalker m_firstWalker;
 325 
 326   /**
 327    * @see ExpressionOwner#getExpression()
 328    */
 329   public Expression getExpression()
 330   {
 331     return m_firstWalker;
 332   }
 333 
 334   /**
 335    * @see ExpressionOwner#setExpression(Expression)
 336    */
 337   public void setExpression(Expression exp)
 338   {
 339         exp.exprSetParent(this);
 340         m_firstWalker = (AxesWalker)exp;
 341   }
 342 
 343     /**
 344      * @see Expression#deepEquals(Expression)
 345      */
 346     public boolean deepEquals(Expression expr)
 347     {
 348       if (!super.deepEquals(expr))
 349                 return false;
 350 
 351       AxesWalker walker1 = m_firstWalker;
 352       AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker;
 353       while ((null != walker1) && (null != walker2))
 354       {
 355         if(!walker1.deepEquals(walker2))
 356                 return false;
 357         walker1 = walker1.getNextWalker();
 358         walker2 = walker2.getNextWalker();
 359       }
 360 
 361       if((null != walker1) || (null != walker2))
 362         return false;
 363 
 364       return true;
 365     }
 366 
 367 }