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 }