/* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xalan" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, Lotus * Development Corporation., http://www.lotus.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.xpath.compiler; import java.util.Vector; import org.apache.xml.utils.QName; import org.apache.xpath.patterns.NodeTest; /** * This class represents the data structure basics of the XPath * object. */ public class OpMap { /** * The current pattern string, for diagnostics purposes */ protected String m_currentPattern; /** * Return the expression as a string for diagnostics. * * @return The expression string. */ public String toString() { return m_currentPattern; } /** * Return the expression as a string for diagnostics. * * @return The expression string. */ public String getPatternString() { return m_currentPattern; } /** * The max size that the token queue can grow to. */ static final int MAXTOKENQUEUESIZE = 500; /** * TokenStack is the queue of used tokens. The current token is the token at the * end of the m_tokenQueue. The idea is that the queue can be marked and a sequence * of tokens can be reused. */ public Object[] m_tokenQueue = new Object[MAXTOKENQUEUESIZE]; /** * Get the XPath as a list of tokens. * * @return an array of string tokens. */ public Object[] getTokenQueue() { return m_tokenQueue; } /** * Get the XPath as a list of tokens. * * @param pos index into token queue. * * @return The token, normally a string. */ public Object getToken(int pos) { return m_tokenQueue[pos]; } /** * The current size of the token queue. */ public int m_tokenQueueSize = 0; /** * Get size of the token queue. * * @return The size of the token queue. */ public int getTokenQueueSize() { return m_tokenQueueSize; } /** * An operations map is used instead of a proper parse tree. It contains * operations codes and indexes into the m_tokenQueue. * I use an array instead of a full parse tree in order to cut down * on the number of objects created. */ public int m_opMap[] = null; /** * Get the opcode list that describes the XPath operations. It contains * operations codes and indexes into the m_tokenQueue. * I use an array instead of a full parse tree in order to cut down * on the number of objects created. * * @return An array of integers that is the opcode list that describes the XPath operations. */ public int[] getOpMap() { return m_opMap; } // Position indexes /** * The length is always the opcode position + 1. * Length is always expressed as the opcode+length bytes, * so it is always 2 or greater. */ public static final int MAPINDEX_LENGTH = 1; /** * Replace the large arrays * with a small array. */ void shrink() { int map[] = m_opMap; int n = m_opMap[MAPINDEX_LENGTH]; ; m_opMap = new int[n + 4]; int i; for (i = 0; i < n; i++) { m_opMap[i] = map[i]; } m_opMap[i] = 0; m_opMap[i + 1] = 0; m_opMap[i + 2] = 0; Object[] tokens = m_tokenQueue; n = m_tokenQueueSize; m_tokenQueue = new Object[n + 4]; for (i = 0; i < n; i++) { m_tokenQueue[i] = tokens[i]; } m_tokenQueue[i] = null; m_tokenQueue[i + 1] = null; m_tokenQueue[i + 2] = null; } /** * Given an operation position, return the current op. * * @param opPos index into op map. * @return the op that corresponds to the opPos argument. */ public int getOp(int opPos) { return m_opMap[opPos]; } /** * Given an operation position, return the end position, i.e. the * beginning of the next operation. * * @param opPos An op position of an operation for which there is a size * entry following. * @return position of next operation in m_opMap. */ public int getNextOpPos(int opPos) { return opPos + m_opMap[opPos + 1]; } /** * Given a location step position, return the end position, i.e. the * beginning of the next step. * * @param opPos the position of a location step. * @return the position of the next location step. */ public int getNextStepPos(int opPos) { int stepType = getOp(opPos); if ((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES)) { return getNextOpPos(opPos); } else if ((stepType >= OpCodes.FIRST_NODESET_OP) && (stepType <= OpCodes.LAST_NODESET_OP)) { int newOpPos = getNextOpPos(opPos); while (OpCodes.OP_PREDICATE == getOp(newOpPos)) { newOpPos = getNextOpPos(newOpPos); } stepType = getOp(newOpPos); if (!((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES))) { return OpCodes.ENDOP; } return newOpPos; } else { throw new RuntimeException( "Programmer's assertion in getNextStepPos: unknown stepType: " + stepType); } } /** * Given an operation position, return the end position, i.e. the * beginning of the next operation. * * @param opMap The operations map. * @param opPos index to operation, for which there is a size entry following. * @return position of next operation in m_opMap. */ public static int getNextOpPos(int[] opMap, int opPos) { return opPos + opMap[opPos + 1]; } /** * Given an FROM_stepType position, return the position of the * first predicate, if there is one, or else this will point * to the end of the FROM_stepType. * Example: * int posOfPredicate = xpath.getNextOpPos(stepPos); * boolean hasPredicates = * OpCodes.OP_PREDICATE == xpath.getOp(posOfPredicate); * * @param opPos position of FROM_stepType op. * @return position of predicate in FROM_stepType structure. */ public int getFirstPredicateOpPos(int opPos) { int stepType = m_opMap[opPos]; if ((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES)) { return opPos + m_opMap[opPos + 2]; } else if ((stepType >= OpCodes.FIRST_NODESET_OP) && (stepType <= OpCodes.LAST_NODESET_OP)) { return opPos + m_opMap[opPos + 1]; } else { throw new RuntimeException( "Programmer's assertion in getNextStepPos: unknown stepType: " + stepType); } } /** * Go to the first child of a given operation. * * @param opPos position of operation. * * @return The position of the first child of the operation. */ public static int getFirstChildPos(int opPos) { return opPos + 2; } /** * Get the length of an operation. * * @param opPos The position of the operation in the op map. * * @return The size of the operation. */ public int getArgLength(int opPos) { return m_opMap[opPos + MAPINDEX_LENGTH]; } /** * Given a location step, get the length of that step. * * @param opPos Position of location step in op map. * * @return The length of the step. */ public int getArgLengthOfStep(int opPos) { return m_opMap[opPos + MAPINDEX_LENGTH + 1] - 3; } /** * Get the first child position of a given location step. * * @param opPos Position of location step in the location map. * * @return The first child position of the step. */ public static int getFirstChildPosOfStep(int opPos) { return opPos + 3; } /** * Get the test type of the step, i.e. NODETYPE_XXX value. * * @param opPosOfStep The position of the FROM_XXX step. * * @return NODETYPE_XXX value. */ public int getStepTestType(int opPosOfStep) { return m_opMap[opPosOfStep + 3]; // skip past op, len, len without predicates } /** * Get the namespace of the step. * * @param opPosOfStep The position of the FROM_XXX step. * * @return The step's namespace, NodeTest.WILD, or null for null namespace. */ public String getStepNS(int opPosOfStep) { int argLenOfStep = getArgLengthOfStep(opPosOfStep); // System.out.println("getStepNS.argLenOfStep: "+argLenOfStep); if (argLenOfStep == 3) { int index = m_opMap[opPosOfStep + 4]; if (index >= 0) return (String) m_tokenQueue[index]; else if (OpCodes.ELEMWILDCARD == index) return NodeTest.WILD; else return null; } else return null; } /** * Get the local name of the step. * @param opPosOfStep The position of the FROM_XXX step. * * @return OpCodes.EMPTY, OpCodes.ELEMWILDCARD, or the local name. */ public String getStepLocalName(int opPosOfStep) { int argLenOfStep = getArgLengthOfStep(opPosOfStep); // System.out.println("getStepLocalName.argLenOfStep: "+argLenOfStep); int index; switch (argLenOfStep) { case 0 : index = OpCodes.EMPTY; break; case 1 : index = OpCodes.ELEMWILDCARD; break; case 2 : index = m_opMap[opPosOfStep + 4]; break; case 3 : index = m_opMap[opPosOfStep + 5]; break; default : index = OpCodes.EMPTY; break; // Should assert error } // int index = (argLenOfStep == 3) ? m_opMap[opPosOfStep+5] // : ((argLenOfStep == 1) ? -3 : -2); if (index >= 0) return (String) m_tokenQueue[index].toString(); else if (OpCodes.ELEMWILDCARD == index) return NodeTest.WILD; else return null; } }