blob: f5dfe1a3839814f2dcca4bbaad390c1edc6f4bc7 [file] [log] [blame]
/*
* 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, International
* Business Machines, Inc., http://www.ibm.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* @author <a href="mailto:david_n_bertoni@lotus.com">David N. Bertoni</a>
*/
// Class header file.
#include "XPath.hpp"
#include <cassert>
#include <cfloat>
#include <Include/STLHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>
#include <PlatformSupport/PrefixResolver.hpp>
#include "FoundIndex.hpp"
#include "MutableNodeRefList.hpp"
#include "XalanQNameByReference.hpp"
#include "SimpleNodeLocator.hpp"
#include "XLocator.hpp"
#include "XPathException.hpp"
#include "XObject.hpp"
#include "XObjectFactory.hpp"
#include "XPathEnvSupport.hpp"
XPath::XPath(const Locator* theLocator) :
m_expression(),
m_locator(theLocator),
m_inStylesheet(false)
{
}
XPath::~XPath()
{
}
void
XPath::shrink()
{
m_expression.shrink();
}
void
XPath::installFunction(
const XalanDOMString& funcName,
const Function& func)
{
s_functions.InstallFunction(funcName,
func);
}
bool
XPath::uninstallFunction(const XalanDOMString& funcName)
{
return s_functions.UninstallFunction(funcName);
}
const XObjectPtr
XPath::execute(
XalanNode* context,
const PrefixResolver& prefixResolver,
XPathExecutionContext& executionContext) const
{
// Push and pop the PrefixResolver...
XPathExecutionContext::PrefixResolverSetAndRestore theResolverSetAndRestore(
executionContext,
&prefixResolver);
// Push and pop the current node...
XPathExecutionContext::CurrentNodeSetAndRestore theNodeSetAndRestore(
executionContext,
context);
return executeMore(context, 0, executionContext);
}
const XObjectPtr
XPath::executeMore(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
switch(m_expression.m_opMap[opPos])
{
case XPathExpression::eOP_XPATH:
return executeMore(context, opPos + 2, executionContext);
break;
case XPathExpression::eOP_MATCHPATTERN:
return matchPattern(context, opPos + 2, executionContext);
break;
case XPathExpression::eEMPTY:
opPos++;
break;
case XPathExpression::eOP_OR:
return Or(context, opPos, executionContext);
break;
case XPathExpression::eOP_AND:
return And(context, opPos, executionContext);
break;
case XPathExpression::eOP_NOTEQUALS:
return notequals(context, opPos, executionContext);
break;
case XPathExpression::eOP_EQUALS:
return equals(context, opPos, executionContext);
break;
case XPathExpression::eOP_LTE:
return lte(context, opPos, executionContext);
break;
case XPathExpression::eOP_LT:
return lt(context, opPos, executionContext);
break;
case XPathExpression::eOP_GTE:
return gte(context, opPos, executionContext);
break;
case XPathExpression::eOP_GT:
return gt(context, opPos, executionContext);
break;
case XPathExpression::eOP_PLUS:
return plus(context, opPos, executionContext);
break;
case XPathExpression::eOP_MINUS:
return minus(context, opPos, executionContext);
break;
case XPathExpression::eOP_MULT:
return mult(context, opPos, executionContext);
break;
case XPathExpression::eOP_DIV:
return div(context, opPos, executionContext);
break;
case XPathExpression::eOP_MOD:
return mod(context, opPos, executionContext);
break;
case XPathExpression::eOP_NEG:
return neg(context, opPos, executionContext);
break;
case XPathExpression::eOP_BOOL:
return boolean(context, opPos, executionContext);
break;
case XPathExpression::eOP_UNION:
return Union(context, opPos, executionContext);
break;
case XPathExpression::eOP_LITERAL:
return literal(context, opPos, executionContext);
break;
case XPathExpression::eOP_VARIABLE:
return variable(context, opPos, executionContext);
break;
case XPathExpression::eOP_GROUP:
return group(context, opPos, executionContext);
break;
case XPathExpression::eOP_NUMBERLIT:
return numberlit(context, opPos, executionContext);
break;
case XPathExpression::eOP_ARGUMENT:
return arg(context, opPos, executionContext);
break;
case XPathExpression::eOP_EXTFUNCTION:
return runExtFunction(context, opPos, executionContext);
break;
case XPathExpression::eOP_FUNCTION:
return runFunction(context, opPos, executionContext);
break;
case XPathExpression::eOP_LOCATIONPATH:
return locationPath(context, opPos, executionContext);
break;
case XPathExpression::eOP_LOCATIONPATHPATTERN:
return locationPathPattern(context, opPos, executionContext);
break;
default:
{
const XalanDOMString theOpCode = LongToDOMString(m_expression.m_opMap[opPos]);
executionContext.error(TranscodeFromLocalCodePage("ERROR! Unknown op code: ") + theOpCode,
context);
}
break;
}
return XObjectPtr();
}
inline void
XPath::doGetMatchScore(
XalanNode* context,
XPathExecutionContext& executionContext,
eMatchScore& score) const
{
assert(context != 0);
int opPos = 2;
while(m_expression.m_opMap[opPos] == XPathExpression::eOP_LOCATIONPATHPATTERN)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
score = SimpleNodeLocator::locationPathPattern(*this, executionContext, *context, opPos);
if(score == eMatchScoreNone)
{
opPos = nextOpPos;
}
else
{
break;
}
}
}
XPath::eMatchScore
XPath::getMatchScore(
XalanNode* node,
const PrefixResolver& resolver,
XPathExecutionContext& executionContext) const
{
eMatchScore score = eMatchScoreNone;
if(m_expression.m_opMap[0] == XPathExpression::eOP_MATCHPATTERN)
{
assert(node != 0);
const PrefixResolver* const theCurrentResolver =
executionContext.getPrefixResolver();
if (theCurrentResolver == &resolver)
{
doGetMatchScore(node, executionContext, score);
}
else
{
// Push and pop the PrefixResolver...
XPathExecutionContext::PrefixResolverSetAndRestore theSetAndRestore(
executionContext,
theCurrentResolver,
&resolver);
doGetMatchScore(node, executionContext, score);
}
}
else
{
executionContext.error(TranscodeFromLocalCodePage("Expected match pattern in getMatchScore!"),
node);
}
return score;
}
void
XPath::getTargetElementStrings(TargetElementStringsVectorType& targetStrings) const
{
int opPos = 2;
targetStrings.reserve(eDefaultTargetStringsSize);
while(m_expression.m_opMap[opPos] == XPathExpression::eOP_LOCATIONPATHPATTERN)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
opPos += 2;
while(m_expression.m_opMap[opPos] != XPathExpression::eENDOP)
{
const int nextStepPos =
m_expression.getNextOpCodePosition(opPos);
const int nextOp = m_expression.m_opMap[nextStepPos];
if(nextOp == XPathExpression::eOP_PREDICATE ||
nextOp == XPathExpression::eENDOP)
{
const int stepType = m_expression.m_opMap[opPos];
opPos += 3;
switch(stepType)
{
case XPathExpression::eOP_FUNCTION:
targetStrings.push_back(PSEUDONAME_ANY);
break;
case XPathExpression::eFROM_ROOT:
targetStrings.push_back(PSEUDONAME_ROOT);
break;
case XPathExpression::eMATCH_ATTRIBUTE:
case XPathExpression::eMATCH_ANY_ANCESTOR:
case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
{
const int tok = m_expression.m_opMap[opPos];
opPos++;
switch(tok)
{
case XPathExpression::eNODETYPE_COMMENT:
targetStrings.push_back(PSEUDONAME_COMMENT);
break;
case XPathExpression::eNODETYPE_TEXT:
targetStrings.push_back(PSEUDONAME_TEXT);
break;
case XPathExpression::eNODETYPE_NODE:
targetStrings.push_back(PSEUDONAME_NODE);
break;
case XPathExpression::eNODETYPE_ROOT:
targetStrings.push_back(PSEUDONAME_ROOT);
break;
case XPathExpression::eNODETYPE_ANYELEMENT:
targetStrings.push_back(PSEUDONAME_ANY);
break;
case XPathExpression::eNODETYPE_PI:
targetStrings.push_back(PSEUDONAME_PI);
break;
case XPathExpression::eNODENAME:
{
// Skip the namespace
const int tokenIndex = m_expression.m_opMap[opPos + 1];
if(tokenIndex >= 0)
{
const XalanDOMString& targetName =
m_expression.m_tokenQueue[tokenIndex].str();
if(::equals(targetName, PSEUDONAME_ANY) == true)
{
targetStrings.push_back(PSEUDONAME_ANY);
}
else
{
targetStrings.push_back(targetName);
}
}
else
{
targetStrings.push_back(PSEUDONAME_ANY);
}
}
break;
default:
targetStrings.push_back(PSEUDONAME_ANY);
break;
}
}
break;
}
}
opPos = nextStepPos;
}
opPos = nextOpPos;
}
}
const XObjectPtr
XPath::matchPattern(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
XObjectPtr score;
while(m_expression.m_opMap[opPos] == XPathExpression::eOP_LOCATIONPATHPATTERN)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
score = executeMore(context, opPos, executionContext);
assert(score.null() == false);
if(score->num() != eMatchScoreNone)
{
break;
}
else
{
opPos = nextOpPos;
}
}
if(score.null() == false)
{
return score;
}
else
{
return executionContext.getXObjectFactory().createNumber(getMatchScoreValue(eMatchScoreNone));
}
}
const XObjectPtr
XPath::Or(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
bool fResult = expr1->boolean();
if(fResult == false)
{
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
fResult = expr2->boolean();
}
return executionContext.getXObjectFactory().createBoolean(fResult);
}
const XObjectPtr
XPath::And(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
bool fResult = false;
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
if (expr1->boolean() == true)
{
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
if (expr2->boolean() == true)
{
fResult = true;
}
}
return executionContext.getXObjectFactory().createBoolean(fResult);
}
const XObjectPtr
XPath::notequals(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->notEquals(*expr2.get(), executionContext));
}
const XObjectPtr
XPath::equals(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->equals(*expr2.get(), executionContext));
}
const XObjectPtr
XPath::lte(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->lessThanOrEquals(*expr2.get(), executionContext));
}
const XObjectPtr
XPath::lt(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->lessThan(*expr2.get(), executionContext));
}
const XObjectPtr
XPath::gte(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->greaterThanOrEquals(*expr2.get(), executionContext));
}
const XObjectPtr
XPath::gt(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createBoolean(expr1->greaterThan(*expr2.get(), executionContext));
}
double
XPath::getNumericOperand(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
if (m_expression.m_opMap[opPos] == XPathExpression::eOP_NUMBERLIT)
{
assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));
return m_expression.getNumberLiteral(m_expression.m_opMap[opPos + 2]);
}
else
{
return executeMore(context, opPos, executionContext)->num();
}
}
const XObjectPtr
XPath::plus(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const double expr1 = getNumericOperand(context, opPos, executionContext);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const double expr2 = getNumericOperand(context, expr2Pos, executionContext);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::add(expr1, expr2));
}
const XObjectPtr
XPath::minus(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const double expr1 = getNumericOperand(context, opPos, executionContext);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const double expr2 = getNumericOperand(context, expr2Pos, executionContext);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::subtract(expr1, expr2));
}
const XObjectPtr
XPath::mult(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const double expr1 = getNumericOperand(context, opPos, executionContext);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const double expr2 = getNumericOperand(context, expr2Pos, executionContext);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::multiply(expr1, expr2));
}
const XObjectPtr
XPath::div(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const double expr1 = getNumericOperand(context, opPos, executionContext);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const double expr2 = getNumericOperand(context, expr2Pos, executionContext);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::divide(expr1, expr2));
}
const XObjectPtr
XPath::mod(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
const XObjectPtr expr1(executeMore(context, opPos, executionContext));
assert(expr1.get() != 0);
const int expr2Pos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr2(executeMore(context, expr2Pos, executionContext));
assert(expr2.get() != 0);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::modulus(expr1->num(), expr2->num()));
}
const XObjectPtr
XPath::neg(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
const XObjectPtr expr1(executeMore(context, opPos + 2, executionContext));
assert(expr1.get() != 0);
return executionContext.getXObjectFactory().createNumber(DoubleSupport::negative(expr1->num()));
}
const XObjectPtr
XPath::boolean(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
const XObjectPtr expr1(executeMore(context, opPos + 2, executionContext));
assert(expr1.get() != 0);
// Try to optimize when the result of the execution is
// already a boolean.
if (expr1->getType() == XObject::eTypeBoolean)
{
return expr1;
}
else
{
return executionContext.getXObjectFactory().createBoolean(expr1->boolean());
}
}
const XObjectPtr
XPath::Union(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
opPos += 2;
typedef XPathExecutionContext::BorrowReturnMutableNodeRefList BorrowReturnMutableNodeRefList;
BorrowReturnMutableNodeRefList resultNodeList(executionContext);
while(m_expression.m_opMap[opPos] != XPathExpression::eENDOP)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr expr(executeMore(context, opPos, executionContext));
const NodeRefListBase& nl =
expr->nodeset();
resultNodeList->addNodesInDocOrder(nl, executionContext);
opPos = nextOpPos;
}
return executionContext.getXObjectFactory().createNodeSet(resultNodeList);
}
const XObjectPtr
XPath::literal(
XalanNode* /* context */,
int opPos,
XPathExecutionContext& executionContext) const
{
assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));
const XToken& theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];
if (m_inStylesheet == true)
{
return executionContext.getXObjectFactory().createString(theLiteral);
}
else
{
return executionContext.getXObjectFactory().createString(theLiteral.str());
}
}
const XObjectPtr
XPath::variable(
XalanNode* /* context */,
int opPos,
XPathExecutionContext& executionContext) const
{
assert(executionContext.getPrefixResolver() != 0);
const XObject& ns = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];
const XObject& varName = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];
return executionContext.getVariable(XalanQNameByReference(ns.str(), varName.str()));
}
const XObjectPtr
XPath::numberlit(
XalanNode* /* context */,
int opPos,
XPathExecutionContext& executionContext) const
{
assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));
const XToken& theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];
if (m_inStylesheet == true)
{
return executionContext.getXObjectFactory().createNumber(theLiteral);
}
else
{
return executionContext.getXObjectFactory().createNumber(theLiteral.num());
}
}
const XObjectPtr
XPath::locationPath(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
assert(context != 0);
return SimpleNodeLocator::locationPath(*this, executionContext, *context, opPos);
}
const XObjectPtr
XPath::locationPathPattern(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
assert(context != 0);
const eMatchScore result =
SimpleNodeLocator::locationPathPattern(*this, executionContext, *context, opPos);
return executionContext.getXObjectFactory().createNumber(getMatchScoreValue(result));
}
const XObjectPtr
XPath::runExtFunction(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
const int endExtFunc = opPos + m_expression.m_opMap[opPos + 1] - 1;
opPos += 2;
const XalanDOMString& ns = m_expression.m_tokenQueue[m_expression.m_opMap[opPos]].str();
++opPos;
const XalanDOMString& funcName = m_expression.m_tokenQueue[m_expression.m_opMap[opPos]].str();
++opPos;
typedef XPathExecutionContext::XObjectArgVectorType XObjectArgVectorType;
XObjectArgVectorType args;
while(opPos < endExtFunc)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
args.push_back(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
}
return extfunction(context, opPos, ns, funcName, args, executionContext);
}
const XObjectPtr
XPath::runFunction(
XalanNode* context,
int opPos,
XPathExecutionContext& executionContext) const
{
const int endFunc = opPos + m_expression.m_opMap[opPos + 1] - 1;
opPos += 2;
// This is actually the position in the token queue of the
// string that contains the name of the function.
const int funcID = m_expression.m_opMap[opPos];
opPos++;
// Number of args is next, not used for now...
const int argCount = m_expression.m_opMap[opPos];
opPos++;
if (argCount == 0)
{
assert(opPos == endFunc);
return s_functions[funcID].execute(executionContext, context);
}
else if (argCount == 1)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
assert(opPos == endFunc);
return s_functions[funcID].execute(executionContext, context, theArg);
}
else if (argCount == 2)
{
int nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg1(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg2(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
assert(opPos == endFunc);
return s_functions[funcID].execute(executionContext, context, theArg1, theArg2);
}
else if (argCount == 3)
{
int nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg1(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg2(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
nextOpPos = m_expression.getNextOpCodePosition(opPos);
const XObjectPtr theArg3(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
assert(opPos == endFunc);
return s_functions[funcID].execute(executionContext, context, theArg1, theArg2, theArg3);
}
else
{
typedef XPathExecutionContext::XObjectArgVectorType XObjectArgVectorType;
XObjectArgVectorType args;
args.reserve(argCount);
while(opPos < endFunc)
{
const int nextOpPos = m_expression.getNextOpCodePosition(opPos);
args.push_back(executeMore(context, opPos, executionContext));
opPos = nextOpPos;
}
return function(context, opPos, funcID, args, executionContext);
}
}
static XalanDOMString PSEUDONAME_ANY;
static XalanDOMString PSEUDONAME_ROOT;
static XalanDOMString PSEUDONAME_TEXT;
static XalanDOMString PSEUDONAME_COMMENT;
static XalanDOMString PSEUDONAME_PI;
static XalanDOMString PSEUDONAME_OTHER;
static XalanDOMString PSEUDONAME_NODE;
const XalanDOMString& XPath::PSEUDONAME_ANY = ::PSEUDONAME_ANY;
const XalanDOMString& XPath::PSEUDONAME_ROOT = ::PSEUDONAME_ROOT;
const XalanDOMString& XPath::PSEUDONAME_TEXT = ::PSEUDONAME_TEXT;
const XalanDOMString& XPath::PSEUDONAME_COMMENT = ::PSEUDONAME_COMMENT;
const XalanDOMString& XPath::PSEUDONAME_PI = ::PSEUDONAME_PI;
const XalanDOMString& XPath::PSEUDONAME_OTHER = ::PSEUDONAME_OTHER;
const XalanDOMString& XPath::PSEUDONAME_NODE = ::PSEUDONAME_NODE;
// Don't auto-create the table...
XPath::FunctionTableType XPath::s_functions(false);
void
XPath::initialize()
{
s_functions.CreateTable();
::PSEUDONAME_ANY = XALAN_STATIC_UCODE_STRING("*");
::PSEUDONAME_ROOT = XALAN_STATIC_UCODE_STRING("/");
::PSEUDONAME_TEXT = XALAN_STATIC_UCODE_STRING("#text");
::PSEUDONAME_COMMENT = XALAN_STATIC_UCODE_STRING("#comment");
::PSEUDONAME_PI = XALAN_STATIC_UCODE_STRING("#pi");
::PSEUDONAME_OTHER = XALAN_STATIC_UCODE_STRING("*");
::PSEUDONAME_NODE = XALAN_STATIC_UCODE_STRING("#node");
}
void
XPath::terminate()
{
releaseMemory(::PSEUDONAME_ANY);
releaseMemory(::PSEUDONAME_ROOT);
releaseMemory(::PSEUDONAME_TEXT);
releaseMemory(::PSEUDONAME_COMMENT);
releaseMemory(::PSEUDONAME_PI);
releaseMemory(::PSEUDONAME_OTHER);
releaseMemory(::PSEUDONAME_NODE);
s_functions.DestroyTable();
}