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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 }