1 /*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 * @LastModified: Nov 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.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 m_tokenQueue.elementAt(index).toString();
450 else if (OpCodes.ELEMWILDCARD == index)
451 return NodeTest.WILD;
452 else
453 return null;
454 }
455
456 }
--- EOF ---