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