1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   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.compiler;
  23 
  24 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  25 import com.sun.org.apache.xml.internal.utils.ObjectVector;
  26 import com.sun.org.apache.xpath.internal.patterns.NodeTest;
  27 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  28 
  29 /**
  30  * This class represents the data structure basics of the XPath
  31  * object.
  32  */
  33 public class OpMap
  34 {
  35 
  36   /**
  37    * The current pattern string, for diagnostics purposes
  38    */
  39   protected String m_currentPattern;
  40 
  41   /**
  42    * Return the expression as a string for diagnostics.
  43    *
  44    * @return The expression string.
  45    */
  46   public String toString()
  47   {
  48     return m_currentPattern;
  49   }
  50 
  51   /**
  52    * Return the expression as a string for diagnostics.
  53    *
  54    * @return The expression string.
  55    */
  56   public String getPatternString()
  57   {
  58     return m_currentPattern;
  59   }
  60 
  61   /**
  62    * The starting size of the token queue.
  63    */
  64   static final int MAXTOKENQUEUESIZE = 500;
  65 
  66   /*
  67    * Amount to grow token queue when it becomes full
  68    */
  69   static final int BLOCKTOKENQUEUESIZE = 500;
  70 
  71   /**
  72    *  TokenStack is the queue of used tokens. The current token is the token at the
  73    * end of the m_tokenQueue. The idea is that the queue can be marked and a sequence
  74    * of tokens can be reused.
  75    */
  76   ObjectVector m_tokenQueue = new ObjectVector(MAXTOKENQUEUESIZE, BLOCKTOKENQUEUESIZE);
  77 
  78   /**
  79    * Get the XPath as a list of tokens.
  80    *
  81    * @return ObjectVector of tokens.
  82    */
  83   public ObjectVector getTokenQueue()
  84   {
  85     return m_tokenQueue;
  86   }
  87 
  88   /**
  89    * Get the XPath as a list of tokens.
  90    *
  91    * @param pos index into token queue.
  92    *
  93    * @return The token, normally a string.
  94    */
  95   public Object getToken(int pos)
  96   {
  97     return m_tokenQueue.elementAt(pos);
  98   }
  99 
 100   /**
 101    * The current size of the token queue.
 102    */
 103 //  public int m_tokenQueueSize = 0;
 104 
 105   /**
 106     * Get size of the token queue.
 107    *
 108    * @return The size of the token queue.
 109    */
 110   public int getTokenQueueSize()
 111   {
 112     return m_tokenQueue.size();
 113 
 114   }
 115 
 116   /**
 117    * An operations map is used instead of a proper parse tree.  It contains
 118    * operations codes and indexes into the m_tokenQueue.
 119    * I use an array instead of a full parse tree in order to cut down
 120    * on the number of objects created.
 121    */
 122   OpMapVector m_opMap = null;
 123 
 124   /**
 125     * Get the opcode list that describes the XPath operations.  It contains
 126    * operations codes and indexes into the m_tokenQueue.
 127    * I use an array instead of a full parse tree in order to cut down
 128    * on the number of objects created.
 129    *
 130    * @return An IntVector that is the opcode list that describes the XPath operations.
 131    */
 132   public OpMapVector getOpMap()
 133   {
 134     return m_opMap;
 135   }
 136 
 137   // Position indexes
 138 
 139   /**
 140    * The length is always the opcode position + 1.
 141    * Length is always expressed as the opcode+length bytes,
 142    * so it is always 2 or greater.
 143    */
 144   public static final int MAPINDEX_LENGTH = 1;
 145 
 146   /**
 147    * Replace the large arrays
 148    * with a small array.
 149    */
 150   void shrink()
 151   {
 152 
 153     int n = m_opMap.elementAt(MAPINDEX_LENGTH);
 154     m_opMap.setToSize(n + 4);
 155 
 156     m_opMap.setElementAt(0,n);
 157     m_opMap.setElementAt(0,n+1);
 158     m_opMap.setElementAt(0,n+2);
 159 
 160 
 161     n = m_tokenQueue.size();
 162     m_tokenQueue.setToSize(n + 4);
 163 
 164     m_tokenQueue.setElementAt(null,n);
 165     m_tokenQueue.setElementAt(null,n + 1);
 166     m_tokenQueue.setElementAt(null,n + 2);
 167   }
 168 
 169   /**
 170   * Given an operation position, return the current op.
 171    *
 172    * @param opPos index into op map.
 173    * @return the op that corresponds to the opPos argument.
 174    */
 175   public int getOp(int opPos)
 176   {
 177     return m_opMap.elementAt(opPos);
 178   }
 179 
 180   /**
 181   * Set the op at index to the given int.
 182    *
 183    * @param opPos index into op map.
 184    * @param value Value to set
 185    */
 186   public void setOp(int opPos, int value)
 187   {
 188      m_opMap.setElementAt(value,opPos);
 189   }
 190 
 191   /**
 192    * Given an operation position, return the end position, i.e. the
 193    * beginning of the next operation.
 194    *
 195    * @param opPos An op position of an operation for which there is a size
 196    *              entry following.
 197    * @return position of next operation in m_opMap.
 198    */
 199   public int getNextOpPos(int opPos)
 200   {
 201     return opPos + m_opMap.elementAt(opPos + 1);
 202   }
 203 
 204   /**
 205    * Given a location step position, return the end position, i.e. the
 206    * beginning of the next step.
 207    *
 208    * @param opPos the position of a location step.
 209    * @return the position of the next location step.
 210    */
 211   public int getNextStepPos(int opPos)
 212   {
 213 
 214     int stepType = getOp(opPos);
 215 
 216     if ((stepType >= OpCodes.AXES_START_TYPES)
 217             && (stepType <= OpCodes.AXES_END_TYPES))
 218     {
 219       return getNextOpPos(opPos);
 220     }
 221     else if ((stepType >= OpCodes.FIRST_NODESET_OP)
 222              && (stepType <= OpCodes.LAST_NODESET_OP))
 223     {
 224       int newOpPos = getNextOpPos(opPos);
 225 
 226       while (OpCodes.OP_PREDICATE == getOp(newOpPos))
 227       {
 228         newOpPos = getNextOpPos(newOpPos);
 229       }
 230 
 231       stepType = getOp(newOpPos);
 232 
 233       if (!((stepType >= OpCodes.AXES_START_TYPES)
 234             && (stepType <= OpCodes.AXES_END_TYPES)))
 235       {
 236         return OpCodes.ENDOP;
 237       }
 238 
 239       return newOpPos;
 240     }
 241     else
 242     {
 243       throw new RuntimeException(
 244         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_UNKNOWN_STEP, new Object[]{String.valueOf(stepType)}));
 245       //"Programmer's assertion in getNextStepPos: unknown stepType: " + stepType);
 246     }
 247   }
 248 
 249   /**
 250    * Given an operation position, return the end position, i.e. the
 251    * beginning of the next operation.
 252    *
 253    * @param opMap The operations map.
 254    * @param opPos index to operation, for which there is a size entry following.
 255    * @return position of next operation in m_opMap.
 256    */
 257   public static int getNextOpPos(int[] opMap, int opPos)
 258   {
 259     return opPos + opMap[opPos + 1];
 260   }
 261 
 262   /**
 263    * Given an FROM_stepType position, return the position of the
 264    * first predicate, if there is one, or else this will point
 265    * to the end of the FROM_stepType.
 266    * Example:
 267    *  int posOfPredicate = xpath.getNextOpPos(stepPos);
 268    *  boolean hasPredicates =
 269    *            OpCodes.OP_PREDICATE == xpath.getOp(posOfPredicate);
 270    *
 271    * @param opPos position of FROM_stepType op.
 272    * @return position of predicate in FROM_stepType structure.
 273    */
 274   public int getFirstPredicateOpPos(int opPos)
 275      throws javax.xml.transform.TransformerException
 276   {
 277 
 278     int stepType = m_opMap.elementAt(opPos);
 279 
 280     if ((stepType >= OpCodes.AXES_START_TYPES)
 281             && (stepType <= OpCodes.AXES_END_TYPES))
 282     {
 283       return opPos + m_opMap.elementAt(opPos + 2);
 284     }
 285     else if ((stepType >= OpCodes.FIRST_NODESET_OP)
 286              && (stepType <= OpCodes.LAST_NODESET_OP))
 287     {
 288       return opPos + m_opMap.elementAt(opPos + 1);
 289     }
 290     else if(-2 == stepType)
 291     {
 292       return -2;
 293     }
 294     else
 295     {
 296       error(com.sun.org.apache.xpath.internal.res.XPATHErrorResources.ER_UNKNOWN_OPCODE,
 297             new Object[]{ String.valueOf(stepType) });  //"ERROR! Unknown op code: "+m_opMap[opPos]);
 298       return -1;
 299     }
 300   }
 301 
 302   /**
 303    * Tell the user of an error, and probably throw an
 304    * exception.
 305    *
 306    * @param msg An error msgkey that corresponds to one of the constants found
 307    *            in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
 308    *            a key for a format string.
 309    * @param args An array of arguments represented in the format string, which
 310    *             may be null.
 311    *
 312    * @throws TransformerException if the current ErrorListoner determines to
 313    *                              throw an exception.
 314    */
 315   public void error(String msg, Object[] args) throws javax.xml.transform.TransformerException
 316   {
 317 
 318     java.lang.String fmsg = com.sun.org.apache.xalan.internal.res.XSLMessages.createXPATHMessage(msg, args);
 319 
 320 
 321     throw new javax.xml.transform.TransformerException(fmsg);
 322   }
 323 
 324 
 325   /**
 326    * Go to the first child of a given operation.
 327    *
 328    * @param opPos position of operation.
 329    *
 330    * @return The position of the first child of the operation.
 331    */
 332   public static int getFirstChildPos(int opPos)
 333   {
 334     return opPos + 2;
 335   }
 336 
 337   /**
 338    * Get the length of an operation.
 339    *
 340    * @param opPos The position of the operation in the op map.
 341    *
 342    * @return The size of the operation.
 343    */
 344   public int getArgLength(int opPos)
 345   {
 346     return m_opMap.elementAt(opPos + MAPINDEX_LENGTH);
 347   }
 348 
 349   /**
 350    * Given a location step, get the length of that step.
 351    *
 352    * @param opPos Position of location step in op map.
 353    *
 354    * @return The length of the step.
 355    */
 356   public int getArgLengthOfStep(int opPos)
 357   {
 358     return m_opMap.elementAt(opPos + MAPINDEX_LENGTH + 1) - 3;
 359   }
 360 
 361   /**
 362    * Get the first child position of a given location step.
 363    *
 364    * @param opPos Position of location step in the location map.
 365    *
 366    * @return The first child position of the step.
 367    */
 368   public static int getFirstChildPosOfStep(int opPos)
 369   {
 370     return opPos + 3;
 371   }
 372 
 373   /**
 374    * Get the test type of the step, i.e. NODETYPE_XXX value.
 375    *
 376    * @param opPosOfStep The position of the FROM_XXX step.
 377    *
 378    * @return NODETYPE_XXX value.
 379    */
 380   public int getStepTestType(int opPosOfStep)
 381   {
 382     return m_opMap.elementAt(opPosOfStep + 3);  // skip past op, len, len without predicates
 383   }
 384 
 385   /**
 386    * Get the namespace of the step.
 387    *
 388    * @param opPosOfStep The position of the FROM_XXX step.
 389    *
 390    * @return The step's namespace, NodeTest.WILD, or null for null namespace.
 391    */
 392   public String getStepNS(int opPosOfStep)
 393   {
 394 
 395     int argLenOfStep = getArgLengthOfStep(opPosOfStep);
 396 
 397     // System.out.println("getStepNS.argLenOfStep: "+argLenOfStep);
 398     if (argLenOfStep == 3)
 399     {
 400       int index = m_opMap.elementAt(opPosOfStep + 4);
 401 
 402       if (index >= 0)
 403         return (String) m_tokenQueue.elementAt(index);
 404       else if (OpCodes.ELEMWILDCARD == index)
 405         return NodeTest.WILD;
 406       else
 407         return null;
 408     }
 409     else
 410       return null;
 411   }
 412 
 413   /**
 414    * Get the local name of the step.
 415    * @param opPosOfStep The position of the FROM_XXX step.
 416    *
 417    * @return OpCodes.EMPTY, OpCodes.ELEMWILDCARD, or the local name.
 418    */
 419   public String getStepLocalName(int opPosOfStep)
 420   {
 421 
 422     int argLenOfStep = getArgLengthOfStep(opPosOfStep);
 423 
 424     // System.out.println("getStepLocalName.argLenOfStep: "+argLenOfStep);
 425     int index;
 426 
 427     switch (argLenOfStep)
 428     {
 429     case 0 :
 430       index = OpCodes.EMPTY;
 431       break;
 432     case 1 :
 433       index = OpCodes.ELEMWILDCARD;
 434       break;
 435     case 2 :
 436       index = m_opMap.elementAt(opPosOfStep + 4);
 437       break;
 438     case 3 :
 439       index = m_opMap.elementAt(opPosOfStep + 5);
 440       break;
 441     default :
 442       index = OpCodes.EMPTY;
 443       break;  // Should assert error
 444     }
 445 
 446     // int index = (argLenOfStep == 3) ? m_opMap[opPosOfStep+5]
 447     //                                  : ((argLenOfStep == 1) ? -3 : -2);
 448     if (index >= 0)
 449       return (String) m_tokenQueue.elementAt(index).toString();
 450     else if (OpCodes.ELEMWILDCARD == index)
 451       return NodeTest.WILD;
 452     else
 453       return null;
 454   }
 455 
 456 }