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