Files
mars-flaim/xflaim/src/fxpath.cpp
dsandersoremutah c55dab446f Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-01-27 21:06:39 +00:00

2480 lines
50 KiB
C++

//------------------------------------------------------------------------------
// Desc: Methods for parsing and evaluating XPATH queries
//
// Tabs: 3
//
// Copyright (c) 2003-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: fxpath.cpp 3123 2006-01-24 17:19:50 -0700 (Tue, 24 Jan 2006) ahodgkinson $
//------------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC RCODE addCallbackFunc(
IF_Query * pQuery);
/****************************************************************************
Desc: Setup the tokenizer
****************************************************************************/
RCODE F_XPathTokenizer::setup(
IF_IStream * pIStream)
{
if( m_pIStream)
{
m_pIStream->Release();
m_pIStream = NULL;
}
if( pIStream)
{
m_pIStream = pIStream;
m_pIStream->AddRef();
}
return( NE_XFLM_OK);
}
/****************************************************************************
Desc: Skips any whitespace characters starting at the current location
****************************************************************************/
RCODE F_XPathTokenizer::skipWhitespace( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
for( ;;)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( !gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
break;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads the next character from the stream.
If no more characters are available, a NULL (0) character will be
returned
****************************************************************************/
RCODE F_XPathTokenizer::getChar(
FLMUNICODE * puChar)
{
RCODE rc = NE_XFLM_OK;
if( m_uiUngetCount)
{
*puChar = m_uUngetBuf[ --m_uiUngetCount];
}
else
{
if( RC_BAD( rc = flmReadUTF8CharAsUnicode( m_pIStream, puChar)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
*puChar = 0;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Returns the next character that will be read from the stream.
If no more characters are available, a NULL (0) character will be
returned
****************************************************************************/
RCODE F_XPathTokenizer::peekChar(
FLMUNICODE * puChar)
{
RCODE rc = NE_XFLM_OK;
if( m_uiUngetCount)
{
*puChar = m_uUngetBuf[ m_uiUngetCount - 1];
}
else
{
if( RC_BAD( rc = flmReadUTF8CharAsUnicode( m_pIStream, puChar)))
{
if( rc == NE_XFLM_EOF_HIT)
{
*puChar = 0;
rc = NE_XFLM_OK;
}
goto Exit;
}
if( RC_BAD( rc = ungetChar( *puChar)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Pushes the passed-in character onto the unget stack
****************************************************************************/
RCODE F_XPathTokenizer::ungetChar(
FLMUNICODE uChar)
{
RCODE rc = NE_XFLM_OK;
if( !uChar)
{
goto Exit;
}
if( m_uiUngetCount == XPATH_MAX_UNGET_CHARS)
{
rc = RC_SET( NE_XFLM_BUFFER_OVERFLOW);
goto Exit;
}
m_uUngetBuf[ m_uiUngetCount++] = uChar;
Exit:
return( rc);
}
/****************************************************************************
Desc: Gets the next XPATH token from the query stream
****************************************************************************/
RCODE F_XPathTokenizer::getNextToken(
F_XPathToken * pToken)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bConsumeParens = FALSE;
pToken->reset();
if( RC_BAD( rc = skipWhitespace()))
{
goto Exit;
}
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
switch( uChar)
{
case 0:
{
pToken->m_eTokenType = END_TOKEN;
break;
}
case FLM_UNICODE_LPAREN:
{
pToken->m_eTokenType = OP_LPAREN_TOKEN;
break;
}
case FLM_UNICODE_RPAREN:
{
pToken->m_eTokenType = OP_RPAREN_TOKEN;
break;
}
case FLM_UNICODE_LBRACKET:
{
pToken->m_eTokenType = OP_LBRACKET_TOKEN;
break;
}
case FLM_UNICODE_RBRACKET:
{
pToken->m_eTokenType = OP_RBRACKET_TOKEN;
break;
}
case FLM_UNICODE_PERIOD:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_PERIOD)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = DOUBLE_PERIOD_TOKEN;
}
else
{
pToken->m_eTokenType = PERIOD_TOKEN;
}
break;
}
case FLM_UNICODE_ATSIGN:
{
pToken->m_eTokenType = AXIS_ATSIGN_TOKEN;
pToken->m_ui64Val = (FLMUINT64)ATTRIBUTE_AXIS;
break;
}
case FLM_UNICODE_COMMA:
{
pToken->m_eTokenType = COMMA_TOKEN;
break;
}
case FLM_UNICODE_COLON:
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uChar != FLM_UNICODE_COLON)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
pToken->m_eTokenType = DOUBLE_COLON_TOKEN;
break;
}
case FLM_UNICODE_FSLASH:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_FSLASH)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_DOUBLE_FSLASH_TOKEN;
}
else
{
pToken->m_eTokenType = OP_FSLASH_TOKEN;
}
break;
}
case FLM_UNICODE_PIPE:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_PIPE)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_OR_TOKEN;
}
else
{
pToken->m_eTokenType = OP_UNION_TOKEN;
}
break;
}
case FLM_UNICODE_AMP:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_AMP)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_AND_TOKEN;
}
else
{
pToken->m_eTokenType = OP_BITAND_TOKEN;
}
break;
}
case FLM_UNICODE_PLUS:
{
pToken->m_eTokenType = OP_PLUS_TOKEN;
break;
}
case FLM_UNICODE_HYPHEN:
{
pToken->m_eTokenType = OP_MINUS_TOKEN;
break;
}
case FLM_UNICODE_TILDE:
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uChar != FLM_UNICODE_EQ)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
pToken->m_eTokenType = OP_APPROX_EQ_TOKEN;
break;
}
case FLM_UNICODE_EQ:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
// Check for double equal and allow it
// in expressions
if( uChar == FLM_UNICODE_EQ)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
}
pToken->m_eTokenType = OP_EQ_TOKEN;
break;
}
case FLM_UNICODE_BANG:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_EQ)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_NE_TOKEN;
}
else
{
pToken->m_eTokenType = OP_NOT_TOKEN;
}
break;
}
case FLM_UNICODE_LT:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_EQ)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_LE_TOKEN;
}
else
{
pToken->m_eTokenType = OP_LT_TOKEN;
}
break;
}
case FLM_UNICODE_GT:
{
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_EQ)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = OP_GE_TOKEN;
}
else
{
pToken->m_eTokenType = OP_GT_TOKEN;
}
break;
}
case FLM_UNICODE_ASTERISK:
{
if( m_eLastTokenType != UNKNOWN_TOKEN &&
m_eLastTokenType != AXIS_ATSIGN_TOKEN &&
m_eLastTokenType != DOUBLE_COLON_TOKEN &&
m_eLastTokenType != OP_LPAREN_TOKEN &&
m_eLastTokenType != OP_LBRACKET_TOKEN &&
m_eLastTokenType != COMMA_TOKEN &&
!isOperator( m_eLastTokenType))
{
pToken->m_eTokenType = OP_MULT_TOKEN;
}
else
{
pToken->m_eTokenType = NAME_TEST_WILD_TOKEN;
}
break;
}
case FLM_UNICODE_DOLLAR:
{
if( RC_BAD( rc = getName( pToken)))
{
goto Exit;
}
pToken->m_eTokenType = VAR_REF_TOKEN;
break;
}
case FLM_UNICODE_0:
case FLM_UNICODE_1:
case FLM_UNICODE_2:
case FLM_UNICODE_3:
case FLM_UNICODE_4:
case FLM_UNICODE_5:
case FLM_UNICODE_6:
case FLM_UNICODE_7:
case FLM_UNICODE_8:
case FLM_UNICODE_9:
{
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
if( RC_BAD( rc = getNumber( pToken)))
{
goto Exit;
}
pToken->m_eTokenType = NUMBER_TOKEN;
break;
}
case FLM_UNICODE_APOS:
case FLM_UNICODE_QUOTE:
{
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
if( RC_BAD( rc = getLiteral( pToken)))
{
goto Exit;
}
pToken->m_eTokenType = LITERAL_TOKEN;
break;
}
case FLM_UNICODE_LBRACE:
{
pToken->m_eTokenType = LBRACE_TOKEN;
break;
}
case FLM_UNICODE_RBRACE:
{
pToken->m_eTokenType = RBRACE_TOKEN;
break;
}
default:
{
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
if( RC_BAD( rc = getName( pToken)))
{
goto Exit;
}
if( pToken->m_puzPrefix)
{
pToken->m_eTokenType = NAME_TEST_QNAME_TOKEN;
goto Exit;
}
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
// Node type or function name?
if( uChar == FLM_UNICODE_LPAREN)
{
switch( pToken->m_puzLocal[ 0])
{
case FLM_UNICODE_b:
if( f_uninativecmp( pToken->m_puzLocal, "binary") == 0)
{
pToken->m_eTokenType = BINARY_TOKEN;
if (RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace()))
{
goto Exit;
}
if (RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if (uChar != FLM_UNICODE_APOS && uChar != FLM_UNICODE_QUOTE)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = getBinary( pToken)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace()))
{
goto Exit;
}
if (RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if (uChar != FLM_UNICODE_RPAREN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_c:
if( f_uninativecmp( pToken->m_puzLocal, "ceiling") == 0)
{
pToken->m_eTokenType = FUNC_CEILING_TOKEN;
}
if( f_uninativecmp( pToken->m_puzLocal, "comment") == 0)
{
pToken->m_eTokenType = NODE_TYPE_COMMENT_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "concat") == 0)
{
pToken->m_eTokenType = FUNC_CONCAT_TOKEN;
}
else if( f_uninativecmp(
pToken->m_puzLocal, "contains") == 0)
{
pToken->m_eTokenType = FUNC_CONTAINS_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "count") == 0)
{
pToken->m_eTokenType = FUNC_COUNT_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_f:
if( f_uninativecmp( pToken->m_puzLocal, "false") == 0)
{
pToken->m_eTokenType = FUNC_FALSE_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"floor") == 0)
{
pToken->m_eTokenType = FUNC_FLOOR_TOKEN;
}
else if (f_uninativecmp( pToken->m_puzLocal,
"funcCB") == 0)
{
pToken->m_eTokenType = FUNC_CB_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_i:
if( f_uninativecmp( pToken->m_puzLocal, "id") == 0)
{
pToken->m_eTokenType = FUNC_ID_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_l:
if( f_uninativecmp( pToken->m_puzLocal, "lang") == 0)
{
pToken->m_eTokenType = FUNC_LANG_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "last") == 0)
{
pToken->m_eTokenType = FUNC_LAST_TOKEN;
}
else if( f_uninativecmp(
pToken->m_puzLocal, "local-name") == 0)
{
pToken->m_eTokenType = FUNC_LOCAL_NAME_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_n:
if( f_uninativecmp( pToken->m_puzLocal, "name") == 0)
{
pToken->m_eTokenType = FUNC_NAME_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"namespace-uri") == 0)
{
pToken->m_eTokenType = FUNC_NAMESPACE_URI_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "node") == 0)
{
pToken->m_eTokenType = NODE_TYPE_NODE_TOKEN;
bConsumeParens = TRUE;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"normalize-space") == 0)
{
pToken->m_eTokenType = FUNC_NORM_SPACE_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "not") == 0)
{
pToken->m_eTokenType = FUNC_NOT_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "number") == 0)
{
pToken->m_eTokenType = FUNC_NUMBER_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_p:
if( f_uninativecmp( pToken->m_puzLocal, "position") == 0)
{
pToken->m_eTokenType = FUNC_POSITION_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"processing-instruction") == 0)
{
pToken->m_eTokenType = NODE_TYPE_PI_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_r:
if( f_uninativecmp( pToken->m_puzLocal,
"round") == 0)
{
pToken->m_eTokenType = FUNC_ROUND_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_s:
if( f_uninativecmp( pToken->m_puzLocal,
"starts-with") == 0)
{
pToken->m_eTokenType = FUNC_STARTS_WITH_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"string") == 0)
{
pToken->m_eTokenType = FUNC_STRING_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"string-length") == 0)
{
pToken->m_eTokenType = FUNC_STR_LEN_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"substring") == 0)
{
pToken->m_eTokenType = FUNC_SUBSTR_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"substring-after") == 0)
{
pToken->m_eTokenType = FUNC_SUBSTR_AFTER_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"substring-before") == 0)
{
pToken->m_eTokenType = FUNC_SUBSTR_BEFORE_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal, "sum") == 0)
{
pToken->m_eTokenType = FUNC_SUM_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_t:
if( f_uninativecmp( pToken->m_puzLocal,
"text") == 0)
{
pToken->m_eTokenType = NODE_TYPE_TEXT_TOKEN;
bConsumeParens = TRUE;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"translate") == 0)
{
pToken->m_eTokenType = FUNC_TRANSLATE_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"true") == 0)
{
pToken->m_eTokenType = FUNC_TRUE_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_u:
if( f_uninativecmp( pToken->m_puzLocal,
"unknown") == 0)
{
pToken->m_eTokenType = FUNC_UNKNOWN_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
default:
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
goto Exit;
}
// Axis specifier or node name?
if( uChar == FLM_UNICODE_COLON)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( RC_BAD( rc = peekChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_COLON)
{
if( RC_BAD( rc = ungetChar( FLM_UNICODE_COLON)))
{
goto Exit;
}
// If we have reached this point, we have a name followed
// by '::'. Verify that the name is a valid axis specifier.
switch( pToken->m_puzLocal[ 0])
{
case FLM_UNICODE_a:
if( f_uninativecmp( pToken->m_puzLocal,
"ancestor") == 0)
{
pToken->m_eTokenType = AXIS_ANCESTOR_TOKEN;
pToken->m_ui64Val = (FLMUINT64)ANCESTOR_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"ancestor-or-self") == 0)
{
pToken->m_eTokenType = AXIS_ANCESTOR_OR_SELF_TOKEN;
pToken->m_ui64Val = (FLMUINT64)ANCESTOR_OR_SELF_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"attribute") == 0)
{
pToken->m_eTokenType = AXIS_ATTRIB_TOKEN;
pToken->m_ui64Val = (FLMUINT64)ATTRIBUTE_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_c:
if( f_uninativecmp( pToken->m_puzLocal,
"child") == 0)
{
pToken->m_eTokenType = AXIS_CHILD_TOKEN;
pToken->m_ui64Val = (FLMUINT64)CHILD_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_d:
if( f_uninativecmp( pToken->m_puzLocal,
"descendant") == 0)
{
pToken->m_eTokenType = AXIS_DESCENDANT_TOKEN;
pToken->m_ui64Val = (FLMUINT64)DESCENDANT_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"descendant-or-self") == 0)
{
pToken->m_eTokenType = AXIS_DESCENDANT_OR_SELF_TOKEN;
pToken->m_ui64Val = (FLMUINT64)DESCENDANT_OR_SELF_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_f:
if( f_uninativecmp( pToken->m_puzLocal,
"following") == 0)
{
pToken->m_eTokenType = AXIS_FOLLOWING_TOKEN;
pToken->m_ui64Val = (FLMUINT64)FOLLOWING_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"following-sibling") == 0)
{
pToken->m_eTokenType = AXIS_FOLLOWING_SIB_TOKEN;
pToken->m_ui64Val = (FLMUINT64)FOLLOWING_SIBLING_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_m:
if( f_uninativecmp( pToken->m_puzLocal,
"meta") == 0)
{
pToken->m_eTokenType = AXIS_META_TOKEN;
pToken->m_ui64Val = (FLMUINT64)META_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_n:
if( f_uninativecmp( pToken->m_puzLocal,
"namespace") == 0)
{
pToken->m_eTokenType = AXIS_NAMESPACE_TOKEN;
pToken->m_ui64Val = (FLMUINT64)NAMESPACE_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_p:
if( f_uninativecmp( pToken->m_puzLocal,
"parent") == 0)
{
pToken->m_eTokenType = AXIS_PARENT_TOKEN;
pToken->m_ui64Val = (FLMUINT64)PARENT_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"preceding") == 0)
{
pToken->m_eTokenType = AXIS_PRECEDING_TOKEN;
pToken->m_ui64Val = (FLMUINT64)PRECEDING_AXIS;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"preceding-sibling") == 0)
{
pToken->m_eTokenType = AXIS_PRECEDING_SIB_TOKEN;
pToken->m_ui64Val = (FLMUINT64)PRECEDING_SIBLING_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
case FLM_UNICODE_s:
if( f_uninativecmp( pToken->m_puzLocal,
"self") == 0)
{
pToken->m_eTokenType = AXIS_SELF_TOKEN;
pToken->m_ui64Val = (FLMUINT64)SELF_AXIS;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
default:
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
goto Exit;
}
else if( uChar == FLM_UNICODE_ASTERISK)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
pToken->m_eTokenType = NAME_TEST_NCWILD_TOKEN;
goto Exit;
}
else
{
if( RC_BAD( rc = ungetChar( FLM_UNICODE_COLON)))
{
goto Exit;
}
}
}
// Operator?
if( m_eLastTokenType != UNKNOWN_TOKEN &&
m_eLastTokenType != LBRACE_TOKEN &&
m_eLastTokenType != RBRACE_TOKEN &&
m_eLastTokenType != DOUBLE_COLON_TOKEN &&
m_eLastTokenType != OP_LPAREN_TOKEN &&
m_eLastTokenType != OP_LBRACKET_TOKEN &&
m_eLastTokenType != COMMA_TOKEN &&
!isOperator( m_eLastTokenType) &&
!isAxisSpecifier( m_eLastTokenType))
{
if( f_uninativecmp( pToken->m_puzLocal,
"and") == 0)
{
pToken->m_eTokenType = OP_AND_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"or") == 0)
{
pToken->m_eTokenType = OP_OR_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"bitor") == 0)
{
pToken->m_eTokenType = OP_BITOR_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"bitand") == 0)
{
pToken->m_eTokenType = OP_BITAND_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"bitxor") == 0)
{
pToken->m_eTokenType = OP_BITXOR_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"mod") == 0)
{
pToken->m_eTokenType = OP_MOD_TOKEN;
}
else if( f_uninativecmp( pToken->m_puzLocal,
"div") == 0)
{
pToken->m_eTokenType = OP_DIV_TOKEN;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
}
goto Exit;
}
// None of the above conditions matched, so we have a QName
pToken->m_eTokenType = NAME_TEST_QNAME_TOKEN;
break;
}
}
// Get the operator flags (if any)
if( tokenCanHaveFlags( pToken->m_eTokenType))
{
FLMUNICODE uzTmpBuf[ 64];
FLMUNICODE uTmpChar;
FLMUINT uiOffset;
if( RC_BAD( rc = skipWhitespace()))
{
goto Exit;
}
if( RC_BAD( rc = peekChar( &uTmpChar)))
{
goto Exit;
}
if( uTmpChar == FLM_UNICODE_LBRACE)
{
if( RC_BAD( rc = getChar( &uTmpChar)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = skipWhitespace()))
{
goto Exit;
}
uiOffset = 0;
for( ;;)
{
if( RC_BAD( rc = getChar( &uTmpChar)))
{
goto Exit;
}
if( !gv_XFlmSysData.pXml->isLetter( uTmpChar) &&
uTmpChar != FLM_UNICODE_UNDERSCORE)
{
uzTmpBuf[ uiOffset] = 0;
if( f_uninativecmp( uzTmpBuf, "ci") == 0 ||
f_uninativecmp( uzTmpBuf, "caseinsensitive") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_CASE_INSENSITIVE;
}
else if( f_uninativecmp( uzTmpBuf, "cs") == 0 ||
f_uninativecmp( uzTmpBuf, "compressspace") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_COMPRESS_WHITESPACE;
}
else if( f_uninativecmp( uzTmpBuf, "ignls") == 0 ||
f_uninativecmp( uzTmpBuf, "ignoreleadingspace") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_IGNORE_LEADING_SPACE;
}
else if( f_uninativecmp( uzTmpBuf, "ignts") == 0 ||
f_uninativecmp( uzTmpBuf, "ignoretrailingspace") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_IGNORE_TRAILING_SPACE;
}
else if( f_uninativecmp( uzTmpBuf, "wstosp") == 0 ||
f_uninativecmp( uzTmpBuf, "whitespaceasspace") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_WHITESPACE_AS_SPACE;
}
else if( f_uninativecmp( uzTmpBuf, "ns") == 0 ||
f_uninativecmp( uzTmpBuf, "nospace") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_NO_WHITESPACE;
}
else if( f_uninativecmp( uzTmpBuf, "nu") == 0 ||
f_uninativecmp( uzTmpBuf, "nounderscores") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_NO_UNDERSCORES;
}
else if( f_uninativecmp( uzTmpBuf, "nd") == 0 ||
f_uninativecmp( uzTmpBuf, "nodashes") == 0)
{
pToken->m_uiTokenFlags |= XFLM_COMP_NO_DASHES;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
break;
}
uzTmpBuf[ uiOffset++] = uTmpChar;
}
if( !uTmpChar)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
else if( uTmpChar == FLM_UNICODE_RBRACE)
{
break;
}
else if( uTmpChar != FLM_UNICODE_COMMA)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
}
}
Exit:
m_eLastTokenType = pToken->m_eTokenType;
// Are we expecting a () sequence after the token that we need to
// just consume?
if (RC_OK( rc) && bConsumeParens)
{
if( RC_OK( rc = skipWhitespace()))
{
if( RC_OK( rc = getChar( &uChar)))
{
if (uChar != FLM_UNICODE_LPAREN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
}
else if (RC_OK( rc = skipWhitespace()))
{
if (RC_OK( rc = getChar( &uChar)))
{
if (uChar != FLM_UNICODE_RPAREN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
}
}
}
}
}
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XPathTokenizer::getName(
F_XPathToken * pToken)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiOffset;
FLMBOOL bFoundColon = FALSE;
FLMUINT uiMaxChars;
FLMUNICODE uChar;
FLMUNICODE uTmpChar;
uiOffset = 0;
if( (uiMaxChars = pToken->m_uiValBufSize / sizeof( FLMUNICODE)) < 32)
{
if( RC_BAD( rc = pToken->resizeBuffer( 32 * sizeof( FLMUNICODE))))
{
goto Exit;
}
uiMaxChars = pToken->m_uiValBufSize / sizeof( FLMUNICODE);
}
pToken->m_puzLocal = (FLMUNICODE *)pToken->m_pValBuf;
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( !gv_XFlmSysData.pXml->isLetter( uChar) &&
uChar != FLM_UNICODE_UNDERSCORE)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
((FLMUNICODE *)pToken->m_pValBuf)[ uiOffset++] = uChar;
for( ;;)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uiOffset == uiMaxChars)
{
if( RC_BAD( rc = pToken->resizeBuffer(
pToken->m_uiValBufSize * sizeof( FLMUNICODE) * 2)))
{
goto Exit;
}
uiMaxChars *= 2;
}
if( uChar == FLM_UNICODE_COLON)
{
if( bFoundColon)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = peekChar( &uTmpChar)))
{
goto Exit;
}
if( !gv_XFlmSysData.pXml->isNCNameChar( uTmpChar))
{
break;
}
uChar = 0;
pToken->m_puzPrefix = (FLMUNICODE *)pToken->m_pValBuf;
pToken->m_puzLocal =
&(((FLMUNICODE *)pToken->m_pValBuf)[ uiOffset + 1]);
bFoundColon = TRUE;
}
else if( !gv_XFlmSysData.pXml->isNCNameChar( uChar))
{
break;
}
((FLMUNICODE *)pToken->m_pValBuf)[ uiOffset++] = uChar;
}
((FLMUNICODE *)pToken->m_pValBuf)[ uiOffset] = 0;
if( bFoundColon &&
(*pToken->m_puzPrefix == 0 || *pToken->m_puzLocal == 0))
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XPathTokenizer::getNumber(
F_XPathToken * pToken)
{
RCODE rc = NE_XFLM_OK;
FLMUINT64 ui64Num = 0;
FLMUNICODE uChar;
for( ;;)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uChar < FLM_UNICODE_0 || uChar > FLM_UNICODE_9)
{
if( RC_BAD( rc = ungetChar( uChar)))
{
goto Exit;
}
break;
}
#if defined ( FLM_LINUX) || defined ( FLM_NLM) || defined( FLM_OSX)
if( ui64Num > ((0xFFFFFFFFFFFFFFFFULL / 10) + (uChar - FLM_UNICODE_0)))
#else
if( ui64Num > ((0xFFFFFFFFFFFFFFFF / 10) + (uChar - FLM_UNICODE_0)))
#endif
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num = (FLMUINT64)((ui64Num * 10) + (uChar - FLM_UNICODE_0));
}
pToken->m_ui64Val = ui64Num;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XPathTokenizer::getBinary(
F_XPathToken * pToken)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bDoubleQuote = FALSE;
FLMUINT uiOffset = 0;
FLMUINT uiMaxBytes;
FLMBYTE * pucBuf;
FLMBOOL bHaveHighNibble = FALSE;
FLMBYTE ucHighNibble = 0;
FLMBYTE ucNibble;
if( (uiMaxBytes = pToken->m_uiValBufSize) < 64)
{
if( RC_BAD( rc = pToken->resizeBuffer( 64)))
{
goto Exit;
}
uiMaxBytes = pToken->m_uiValBufSize;
}
pucBuf = (FLMBYTE *)pToken->m_pValBuf;
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_QUOTE)
{
bDoubleQuote = TRUE;
}
else if( uChar != FLM_UNICODE_APOS)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if ( uChar == 0)
{
rc = RC_SET( NE_XFLM_UNEXPECTED_END_OF_INPUT);
goto Exit;
}
if( bDoubleQuote && uChar == FLM_UNICODE_QUOTE)
{
break;
}
else if( !bDoubleQuote && uChar == FLM_UNICODE_APOS)
{
break;
}
if (uChar >= FLM_UNICODE_0 && uChar <= FLM_UNICODE_9)
{
ucNibble = (FLMBYTE)(uChar - FLM_UNICODE_0);
}
else if (uChar >= FLM_UNICODE_A && uChar <= FLM_UNICODE_F)
{
ucNibble = (FLMBYTE)(uChar - FLM_UNICODE_A + 10);
}
else if (uChar >= FLM_UNICODE_a && uChar <= FLM_UNICODE_f)
{
ucNibble = (FLMBYTE)(uChar - FLM_UNICODE_a + 10);
}
else if (gv_XFlmSysData.pXml->isWhitespace( uChar))
{
// Just skip whitespace, anything else we will treat as an
// error.
continue;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if (!bHaveHighNibble)
{
ucHighNibble = (FLMBYTE)(ucNibble << 4);
bHaveHighNibble = TRUE;
}
else
{
pucBuf [uiOffset++] = ucHighNibble | ucNibble;
if( uiOffset == uiMaxBytes)
{
if( RC_BAD( rc = pToken->resizeBuffer(
pToken->m_uiValBufSize * 2)))
{
goto Exit;
}
uiMaxBytes *= 2;
}
bHaveHighNibble = FALSE;
}
}
if (bHaveHighNibble)
{
pucBuf [uiOffset++] = ucHighNibble;
}
pToken->m_uiValBufLen = uiOffset;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XPathTokenizer::getLiteral(
F_XPathToken * pToken)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bDoubleQuote = FALSE;
FLMUINT uiOffset;
FLMUINT uiMaxChars;
uiOffset = 0;
if( (uiMaxChars = pToken->m_uiValBufSize / sizeof( FLMUNICODE)) < 32)
{
if( RC_BAD( rc = pToken->resizeBuffer( 32 * sizeof( FLMUNICODE))))
{
goto Exit;
}
uiMaxChars = pToken->m_uiValBufSize / sizeof( FLMUNICODE);
}
pToken->m_puzLocal = (FLMUNICODE *)pToken->m_pValBuf;
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if( uChar == FLM_UNICODE_QUOTE)
{
bDoubleQuote = TRUE;
}
else if( uChar != FLM_UNICODE_APOS)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = getChar( &uChar)))
{
goto Exit;
}
if ( uChar == 0)
{
rc = RC_SET( NE_XFLM_UNEXPECTED_END_OF_INPUT);
goto Exit;
}
if( bDoubleQuote && uChar == FLM_UNICODE_QUOTE)
{
break;
}
else if( !bDoubleQuote && uChar == FLM_UNICODE_APOS)
{
break;
}
pToken->m_puzLocal[ uiOffset++] = uChar;
if( uiOffset == uiMaxChars)
{
if( RC_BAD( rc = pToken->resizeBuffer(
pToken->m_uiValBufSize * sizeof( FLMUNICODE) * 2)))
{
goto Exit;
}
uiMaxChars *= 2;
}
}
pToken->m_puzLocal[ uiOffset++] = 0;
Exit:
return( rc);
}
/***************************************************************************
Desc: Class for handling query validator calls
***************************************************************************/
class XFLAIM_QueryValFunc : public IF_QueryValFunc, public XF_Base
{
public:
XFLAIM_QueryValFunc()
{
}
virtual ~XFLAIM_QueryValFunc()
{
}
RCODE XFLMAPI getValue(
IF_Db * pDb,
IF_DOMNode * pContextNode,
ValIterator eValueToGet,
eValTypes * peValType,
FLMBOOL * pbLastValue,
void * pvVal,
IF_DynaBuf * pDynaBuf = NULL);
RCODE XFLMAPI cloneSelf(
IF_QueryValFunc ** ppNewObj);
};
/****************************************************************************
Desc: Get the next value for a query function. Since this is really just
code to test the callback, it always returns a value whose type
is boolean and whose value is true.
****************************************************************************/
RCODE XFLMAPI XFLAIM_QueryValFunc::getValue(
IF_Db *, // pDb,
IF_DOMNode *, // pContextNode,
ValIterator eValueToGet,
eValTypes * peValType,
FLMBOOL * pbLastValue,
void * pvVal,
IF_DynaBuf * pDynaBuf)
{
RCODE rc = NE_XFLM_OK;
if (pDynaBuf)
{
(void)pDynaBuf->truncateData( 0);
}
if (eValueToGet != GET_FIRST_VAL && eValueToGet != GET_LAST_VAL)
{
rc = (eValueToGet == GET_NEXT_VAL)
? NE_XFLM_EOF_HIT
: NE_XFLM_BOF_HIT;
goto Exit;
}
*pbLastValue = TRUE;
*peValType = XFLM_BOOL_VAL;
*((XFlmBoolType *)pvVal) = XFLM_TRUE;
Exit:
return( rc);
}
/****************************************************************************
Desc: Copy self to create a new object.
****************************************************************************/
RCODE XFLMAPI XFLAIM_QueryValFunc::cloneSelf(
IF_QueryValFunc ** ppNewObj)
{
// No need to copy - simply reference, because it has no private
// state data that needs to have its own copy.
*ppNewObj = (IF_QueryValFunc *)this;
(*ppNewObj)->AddRef();
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Add a callback function predicate.
***************************************************************************/
FSTATIC RCODE addCallbackFunc(
IF_Query * pQuery)
{
RCODE rc = NE_XFLM_OK;
XFLAIM_QueryValFunc * pFuncObj = NULL;
// Create a callback function object
if ((pFuncObj = f_new XFLAIM_QueryValFunc) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if (RC_BAD( rc = pQuery->addFunction( pFuncObj, TRUE)))
{
goto Exit;
}
Exit:
if (pFuncObj)
{
pFuncObj->Release();
}
return( rc);
}
/****************************************************************************
Desc: Parse an XPATH query
****************************************************************************/
RCODE F_XPath::parseQuery(
F_Db * pDb,
IF_IStream * pIStream,
IF_Query * pQuery)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
F_XMLNamespace * pNamespace = NULL;
eXPathAxisTypes eCurrentAxis = CHILD_AXIS;
eDomNodeType eNodeType = ELEMENT_NODE;
FLMUINT uiDictNum;
if( RC_BAD( rc = pDb->getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = m_tokenizer.setup( pIStream)))
{
goto Exit;
}
// Process any namespace declarations
popNamespaces( getNamespaceCount());
if( RC_BAD( rc = pushNamespace( NULL, NULL)))
{
goto Exit;
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.getType() == LBRACE_TOKEN)
{
for( ;;)
{
if( (pNamespace = f_new F_XMLNamespace) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.getType() != NAME_TEST_QNAME_TOKEN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( m_curToken.getPrefixPtr())
{
if( f_uninativecmp( m_curToken.getPrefixPtr(),
"xmlns") != 0)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = pNamespace->setPrefix(
m_curToken.getLocalPtr())))
{
goto Exit;
}
}
else
{
if( f_uninativecmp( m_curToken.getLocalPtr(),
"xmlns") != 0)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.getType() != OP_EQ_TOKEN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.getType() != LITERAL_TOKEN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = pNamespace->setURI(
m_curToken.getLocalPtr())))
{
goto Exit;
}
if( RC_BAD( rc = pushNamespace( pNamespace)))
{
goto Exit;
}
pNamespace->Release();
pNamespace = NULL;
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.getType() == RBRACE_TOKEN)
{
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
break;
}
else if( m_curToken.getType() != COMMA_TOKEN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
}
for( ;;)
{
if( m_curToken.m_eTokenType == END_TOKEN)
{
break;
}
switch( m_curToken.m_eTokenType)
{
case OP_AND_TOKEN:
case OP_OR_TOKEN:
case OP_EQ_TOKEN:
case OP_APPROX_EQ_TOKEN:
case OP_NOT_TOKEN:
case OP_NE_TOKEN:
case OP_LT_TOKEN:
case OP_LE_TOKEN:
case OP_GT_TOKEN:
case OP_GE_TOKEN:
case OP_BITAND_TOKEN:
case OP_BITOR_TOKEN:
case OP_BITXOR_TOKEN:
case OP_MULT_TOKEN:
case OP_DIV_TOKEN:
case OP_MOD_TOKEN:
case OP_PLUS_TOKEN:
case OP_MINUS_TOKEN:
case OP_LPAREN_TOKEN:
case OP_RPAREN_TOKEN:
case OP_COMMA_TOKEN:
case OP_LBRACKET_TOKEN:
case OP_RBRACKET_TOKEN:
if( RC_BAD( rc = pQuery->addOperator(
(eQueryOperators)m_curToken.m_eTokenType,
m_curToken.m_uiTokenFlags)))
{
goto Exit;
}
break;
case LITERAL_TOKEN:
if( RC_BAD( rc = pQuery->addUnicodeValue(
(FLMUNICODE *)m_curToken.m_pValBuf)))
{
goto Exit;
}
break;
case BINARY_TOKEN:
if( RC_BAD( rc = pQuery->addBinaryValue(
m_curToken.m_pValBuf,
m_curToken.m_uiValBufLen)))
{
goto Exit;
}
break;
case NUMBER_TOKEN:
if( RC_BAD( rc = pQuery->addUINT64Value( m_curToken.m_ui64Val)))
{
goto Exit;
}
break;
case FUNC_TRUE_TOKEN:
case FUNC_FALSE_TOKEN:
case FUNC_UNKNOWN_TOKEN:
{
FLMBOOL bVal = (m_curToken.m_eTokenType == FUNC_TRUE_TOKEN)
? TRUE
: FALSE;
FLMBOOL bUnknown = (m_curToken.m_eTokenType == FUNC_UNKNOWN_TOKEN)
? TRUE
: FALSE;
if ( RC_BAD( rc = pQuery->addBoolean( bVal, bUnknown)))
{
goto Exit;
}
// consume the opening and closing paren
if ( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if ( m_curToken.m_eTokenType != OP_LPAREN_TOKEN)
{
rc = RC_SET( NE_XFLM_Q_EXPECTING_LPAREN);
goto Exit;
}
if ( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if ( m_curToken.m_eTokenType != OP_RPAREN_TOKEN)
{
rc = RC_SET( NE_XFLM_Q_EXPECTING_RPAREN);
goto Exit;
}
}
break;
case FUNC_LAST_TOKEN:
case FUNC_POSITION_TOKEN:
case FUNC_COUNT_TOKEN:
case FUNC_ID_TOKEN:
case FUNC_LOCAL_NAME_TOKEN:
case FUNC_NAMESPACE_URI_TOKEN:
case FUNC_NAME_TOKEN:
case FUNC_STRING_TOKEN:
case FUNC_CONCAT_TOKEN:
case FUNC_STARTS_WITH_TOKEN:
case FUNC_CONTAINS_TOKEN:
case FUNC_SUBSTR_BEFORE_TOKEN:
case FUNC_SUBSTR_AFTER_TOKEN:
case FUNC_SUBSTR_TOKEN:
case FUNC_STR_LEN_TOKEN:
case FUNC_NORM_SPACE_TOKEN:
case FUNC_TRANSLATE_TOKEN:
case FUNC_NOT_TOKEN:
case FUNC_LANG_TOKEN:
case FUNC_NUMBER_TOKEN:
case FUNC_SUM_TOKEN:
case FUNC_FLOOR_TOKEN:
case FUNC_CEILING_TOKEN:
case FUNC_ROUND_TOKEN:
if( RC_BAD( rc = pQuery->addFunction( XFLM_FUNC_xxx)))
{
goto Exit;
}
break;
case FUNC_CB_TOKEN:
if (RC_BAD( rc = addCallbackFunc( pQuery)))
{
goto Exit;
}
break;
case AXIS_ANCESTOR_TOKEN:
case AXIS_ANCESTOR_OR_SELF_TOKEN:
case AXIS_CHILD_TOKEN:
case AXIS_DESCENDANT_TOKEN:
case AXIS_DESCENDANT_OR_SELF_TOKEN:
case AXIS_FOLLOWING_TOKEN:
case AXIS_FOLLOWING_SIB_TOKEN:
case AXIS_PARENT_TOKEN:
case AXIS_PRECEDING_TOKEN:
case AXIS_PRECEDING_SIB_TOKEN:
case AXIS_SELF_TOKEN:
case AXIS_ATTRIB_TOKEN:
case AXIS_NAMESPACE_TOKEN:
case AXIS_ATSIGN_TOKEN:
case AXIS_META_TOKEN:
{
eCurrentAxis = (eXPathAxisTypes)m_curToken.m_ui64Val;
eNodeType = ELEMENT_NODE;
if (m_curToken.m_eTokenType == AXIS_ATSIGN_TOKEN)
{
eNodeType = ATTRIBUTE_NODE;
}
else
{
if (m_curToken.m_eTokenType == AXIS_META_TOKEN)
{
eNodeType = ANY_NODE_TYPE;
}
else if (m_curToken.m_eTokenType == AXIS_ATTRIB_TOKEN ||
m_curToken.m_eTokenType == AXIS_NAMESPACE_TOKEN)
{
eNodeType = ATTRIBUTE_NODE;
}
else if (m_curToken.m_eTokenType == AXIS_SELF_TOKEN)
{
eNodeType = ANY_NODE_TYPE;
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
if( m_curToken.m_eTokenType != DOUBLE_COLON_TOKEN)
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
switch( m_curToken.m_eTokenType)
{
case NAME_TEST_WILD_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
eNodeType, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NAME_TEST_QNAME_TOKEN:
{
if (eCurrentAxis == META_AXIS)
{
if (f_uninativecmp( m_curToken.getLocalPtr(),
"nodeid") == 0)
{
uiDictNum = XFLM_META_NODE_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"documentid") == 0)
{
uiDictNum = XFLM_META_DOCUMENT_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"parentid") == 0)
{
uiDictNum = XFLM_META_PARENT_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"firstchildid") == 0)
{
uiDictNum = XFLM_META_FIRST_CHILD_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"lastchildid") == 0)
{
uiDictNum = XFLM_META_LAST_CHILD_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"nextsiblingid") == 0)
{
uiDictNum = XFLM_META_NEXT_SIBLING_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"prevsiblingid") == 0)
{
uiDictNum = XFLM_META_PREV_SIBLING_ID;
}
else if (f_uninativecmp( m_curToken.getLocalPtr(),
"value") == 0)
{
uiDictNum = XFLM_META_VALUE;
}
else
{
rc = RC_SET( NE_XFLM_Q_INVALID_META_DATA_TYPE);
goto Exit;
}
}
else
{
if( m_curToken.getPrefixPtr())
{
if( RC_BAD( rc = findNamespace(
m_curToken.getPrefixPtr(), &pNamespace)))
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
pDb, eNodeType == ELEMENT_NODE
? ELM_ELEMENT_TAG
: ELM_ATTRIBUTE_TAG,
m_curToken.getLocalPtr(),
NULL, pNamespace ? TRUE : FALSE,
pNamespace ? pNamespace->getURIPtr() : NULL,
&uiDictNum, NULL)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
if( !m_curToken.getPrefixPtr())
{
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
pDb, eNodeType == ELEMENT_NODE
? ELM_ELEMENT_TAG
: ELM_ATTRIBUTE_TAG,
m_curToken.getLocalPtr(),
NULL, FALSE, NULL, &uiDictNum, NULL)))
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
if( pNamespace)
{
pNamespace->Release();
pNamespace = NULL;
}
}
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
eNodeType, uiDictNum)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NODE_TYPE_NODE_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
ANY_NODE_TYPE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NODE_TYPE_TEXT_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
DATA_NODE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NAME_TEST_NCWILD_TOKEN:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
case NODE_TYPE_COMMENT_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
COMMENT_NODE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NODE_TYPE_PI_TOKEN:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
default:
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
break;
}
case NAME_TEST_QNAME_TOKEN:
eNodeType = ELEMENT_NODE;
if( RC_BAD( rc = findNamespace(
m_curToken.getPrefixPtr(), &pNamespace)))
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
pDb, ELM_ELEMENT_TAG, m_curToken.getLocalPtr(),
NULL, pNamespace ? TRUE : FALSE, pNamespace ? pNamespace->getURIPtr() : NULL,
&uiDictNum, NULL)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
if( !m_curToken.getPrefixPtr())
{
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
pDb, ELM_ELEMENT_TAG, m_curToken.getLocalPtr(),
NULL, FALSE, NULL, &uiDictNum, NULL)))
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
}
if( pNamespace)
{
pNamespace->Release();
pNamespace = NULL;
}
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
eNodeType, uiDictNum)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
case PERIOD_TOKEN:
if( RC_BAD( rc = pQuery->addXPathComponent( SELF_AXIS,
ANY_NODE_TYPE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
case DOUBLE_PERIOD_TOKEN:
if ( RC_BAD( rc = pQuery->addXPathComponent( PARENT_AXIS,
ANY_NODE_TYPE, 0)))
{
goto Exit;
}
eCurrentAxis = PARENT_AXIS;
eNodeType = ELEMENT_NODE;
break;
case OP_FSLASH_TOKEN:
eCurrentAxis = CHILD_AXIS;
break;
case OP_DOUBLE_FSLASH_TOKEN:
eCurrentAxis = DESCENDANT_AXIS;
break;
case NODE_TYPE_NODE_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
ANY_NODE_TYPE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
break;
}
case NODE_TYPE_COMMENT_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
COMMENT_NODE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NODE_TYPE_TEXT_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
DATA_NODE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case NAME_TEST_WILD_TOKEN:
{
if( RC_BAD( rc = pQuery->addXPathComponent( eCurrentAxis,
ELEMENT_NODE, 0)))
{
goto Exit;
}
eCurrentAxis = CHILD_AXIS;
eNodeType = ELEMENT_NODE;
break;
}
case DOUBLE_COLON_TOKEN:
case OP_UNION_TOKEN:
case NODE_TYPE_PI_TOKEN:
case NAME_TEST_NCWILD_TOKEN:
case VAR_REF_TOKEN:
case END_TOKEN:
default:
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = getNextToken()))
{
goto Exit;
}
}
Exit:
m_tokenizer.setup( NULL);
if( pNamespace)
{
pNamespace->Release();
}
if( pNameTable)
{
pNameTable->Release();
}
return( rc);
}
/****************************************************************************
Desc: Parse an XPATH query
****************************************************************************/
RCODE F_XPath::parseQuery(
F_Db * pDb,
char * pszQuery,
IF_Query * pQuery)
{
RCODE rc = NE_XFLM_OK;
F_BufferIStream istream;
if( RC_BAD( rc= istream.open( (FLMBYTE *)pszQuery, f_strlen( pszQuery))))
{
goto Exit;
}
if( RC_BAD( rc = parseQuery( pDb, &istream, pQuery)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XPath::getNextToken( void)
{
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = m_tokenizer.getNextToken( &m_curToken)))
{
goto Exit;
}
Exit:
return( rc);
}