Files
mars-flaim/xflaim/src/fxml.cpp

6497 lines
126 KiB
C++

//------------------------------------------------------------------------------
// Desc: XML parser
//
// Tabs: 3
//
// Copyright (c) 2000-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: fxml.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
// Global data
extern FLMUNICODE gv_uzXFLAIMNamespace[];
static FLMUNICODE gv_puzNamespaceDeclPrefix[] =
{
FLM_UNICODE_x,
FLM_UNICODE_m,
FLM_UNICODE_l,
FLM_UNICODE_n,
FLM_UNICODE_s,
0
};
static FLMUNICODE gv_puzXMLPrefix[] =
{
FLM_UNICODE_x,
FLM_UNICODE_m,
FLM_UNICODE_l,
0
};
FLMUNICODE gv_puzXMLNSURI[] =
{
FLM_UNICODE_h,
FLM_UNICODE_t,
FLM_UNICODE_t,
FLM_UNICODE_p,
FLM_UNICODE_COLON,
FLM_UNICODE_FSLASH,
FLM_UNICODE_FSLASH,
FLM_UNICODE_w,
FLM_UNICODE_w,
FLM_UNICODE_w,
FLM_UNICODE_PERIOD,
FLM_UNICODE_w,
FLM_UNICODE_3,
FLM_UNICODE_c,
FLM_UNICODE_PERIOD,
FLM_UNICODE_o,
FLM_UNICODE_r,
FLM_UNICODE_g,
FLM_UNICODE_FSLASH,
FLM_UNICODE_T,
FLM_UNICODE_R,
FLM_UNICODE_FSLASH,
FLM_UNICODE_1,
FLM_UNICODE_9,
FLM_UNICODE_9,
FLM_UNICODE_9,
FLM_UNICODE_FSLASH,
FLM_UNICODE_R,
FLM_UNICODE_E,
FLM_UNICODE_C,
FLM_UNICODE_HYPHEN,
FLM_UNICODE_x,
FLM_UNICODE_m,
FLM_UNICODE_l,
FLM_UNICODE_HYPHEN,
FLM_UNICODE_n,
FLM_UNICODE_a,
FLM_UNICODE_m,
FLM_UNICODE_e,
FLM_UNICODE_s,
FLM_UNICODE_HYPHEN,
FLM_UNICODE_1,
FLM_UNICODE_9,
FLM_UNICODE_9,
FLM_UNICODE_9,
FLM_UNICODE_0,
FLM_UNICODE_1,
FLM_UNICODE_1,
FLM_UNICODE_4,
0
};
FSTATIC RCODE exportUniValue(
IF_OStream * pOStream,
FLMUNICODE * puzStr,
FLMUINT uiStrChars,
FLMBOOL bEncodeSpecialChars,
FLMUINT uiIndentCount);
/****************************************************************************
Desc: Constructor
****************************************************************************/
F_XMLImport::F_XMLImport()
{
m_uiValBufSize = 0;
m_pucValBuf = NULL;
m_bSetup = FALSE;
m_fnStatus = NULL;
m_pvCallbackData = NULL;
m_tmpPool.poolInit( 4096);
m_attrPool.poolInit( 4096);
m_puzCurrLineBuf = NULL;
m_uiCurrLineBufMaxChars = 0;
reset();
}
/****************************************************************************
Desc: Destructor
****************************************************************************/
F_XMLImport::~F_XMLImport()
{
reset();
if( m_pucValBuf)
{
f_free( &m_pucValBuf);
}
if( m_puzCurrLineBuf)
{
f_free( &m_puzCurrLineBuf);
}
m_tmpPool.poolFree();
m_attrPool.poolFree();
}
/****************************************************************************
Desc: Resets member variables so the object can be reused
****************************************************************************/
void F_XMLImport::reset( void)
{
m_uiCurrLineNum = 0;
m_uiCurrLineNumChars = 0;
m_uiCurrLineOffset = 0;
m_ucUngetByte = 0;
m_uiCurrLineFilePos = 0;
m_uiCurrLineBytes = 0;
m_pStream = NULL;
m_uiFlags = 0;
m_eXMLEncoding = XFLM_XML_USASCII_ENCODING;
m_pDb = NULL;
m_uiCollection = 0;
f_memset( &m_importStats, 0, sizeof( XFLM_IMPORT_STATS));
popNamespaces( getNamespaceCount());
m_tmpPool.poolReset( NULL);
resetAttrList();
}
/****************************************************************************
Desc: Initializes the object (allocates buffers, etc.)
****************************************************************************/
RCODE F_XMLImport::setup( void)
{
RCODE rc = NE_XFLM_OK;
flmAssert( !m_bSetup);
if( RC_BAD( rc = resizeValBuffer( 2048)))
{
goto Exit;
}
m_bSetup = TRUE;
Exit:
if( RC_BAD( rc))
{
if( m_pucValBuf)
{
f_free( &m_pucValBuf);
m_pucValBuf = NULL;
}
}
return( rc);
}
/****************************************************************************
Desc: Reads data from the input stream and builds a FLAIM record
****************************************************************************/
RCODE F_XMLImport::import(
IF_IStream * pStream,
F_Db * pDb,
FLMUINT uiCollection,
FLMUINT uiFlags,
F_DOMNode * pNodeToLinkTo,
eNodeInsertLoc eInsertLoc,
F_DOMNode ** ppNewNode,
XFLM_IMPORT_STATS * pImportStats)
{
RCODE rc = NE_XFLM_OK;
// Reset the state of the parser
reset();
// If a root element was passed in, do some sanity checks
// before importing the XML stream
if (pNodeToLinkTo)
{
FLMUINT uiTmp;
if( RC_BAD( rc = pNodeToLinkTo->getCollection( pDb, &uiTmp)))
{
goto Exit;
}
if( uiTmp != uiCollection)
{
rc = RC_SET( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
m_pDb = pDb;
m_uiCollection = uiCollection;
// Set up namespace support. Un-prefixed names (NULL prefix) are
// not bound to a namespace (NULL URI). The 'xml' namespace prefix
// is, by definition, bound to 'http://www.w3.org/XML/1998/namespace'
if( RC_BAD( rc = pushNamespace( NULL, NULL)))
{
goto Exit;
}
if( RC_BAD( rc = pushNamespace(
gv_puzXMLPrefix, gv_puzXMLNSURI)))
{
goto Exit;
}
m_pStream = pStream;
m_uiFlags = uiFlags;
if( RC_BAD( rc = processProlog()))
{
goto Exit;
}
if( RC_BAD( rc = processElement( pNodeToLinkTo, eInsertLoc, ppNewNode)))
{
goto Exit;
}
// Call the status hook one last time
m_importStats.uiDocuments++;
if( m_fnStatus)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
// Tally and return the import stats
if( pImportStats)
{
pImportStats->uiChars += m_importStats.uiChars;
pImportStats->uiAttributes += m_importStats.uiAttributes;
pImportStats->uiElements += m_importStats.uiElements;
pImportStats->uiText += m_importStats.uiText;
pImportStats->uiDocuments += m_importStats.uiDocuments;
}
Exit:
if( RC_BAD( rc) && pImportStats)
{
pImportStats->uiErrLineNum = m_importStats.uiErrLineNum
? m_importStats.uiErrLineNum
: m_uiCurrLineNum;
pImportStats->uiErrLineOffset = m_importStats.uiErrLineOffset
? m_importStats.uiErrLineOffset
: m_uiCurrLineOffset;
pImportStats->eErrorType = ( XMLParseError)( m_importStats.eErrorType);
pImportStats->uiErrLineFilePos = m_importStats.uiErrLineFilePos;
pImportStats->uiErrLineBytes = m_importStats.uiErrLineBytes;
pImportStats->eXMLEncoding = m_importStats.eXMLEncoding;
}
m_pDb = NULL;
m_uiCollection = 0;
return( rc);
}
/****************************************************************************
Desc: Process an XML prolog
****************************************************************************/
RCODE F_XMLImport::processProlog( void)
{
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (lineHasToken( "<?xml"))
{
if( RC_BAD( rc = processXMLDecl()))
{
goto Exit;
}
}
if( RC_BAD( rc = processMisc()))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (lineHasToken( "<!DOCTYPE"))
{
if( RC_BAD( rc = processDocTypeDecl()))
{
goto Exit;
}
if( RC_BAD( rc = processMisc()))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Converts a Unicode string to a number
****************************************************************************/
RCODE F_XMLImport::unicodeToNumber64(
FLMUNICODE * puzVal,
FLMUINT64 * pui64Val,
FLMBOOL * pbNeg)
{
char szTmpBuf[ 64];
FLMUINT uiLoop;
FLMBOOL bNeg = FALSE;
FLMUNICODE uChar;
RCODE rc = NE_XFLM_OK;
if( !puzVal)
{
*pui64Val = 0;
*pbNeg = FALSE;
goto Exit;
}
for( uiLoop = 0; uiLoop < sizeof( szTmpBuf); uiLoop++)
{
if( (uChar = puzVal[ uiLoop]) == 0)
{
break;
}
else if( uiLoop == 0 && uChar == FLM_UNICODE_HYPHEN)
{
bNeg = TRUE;
continue;
}
szTmpBuf[ uiLoop] = (char)uChar;
}
if( uiLoop == sizeof( szTmpBuf))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
szTmpBuf[ uiLoop] = 0;
*pui64Val = f_atou64( szTmpBuf);
if( pbNeg)
{
*pbNeg = bNeg;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Creates a new text node and links it to the passed-in parent
****************************************************************************/
RCODE F_XMLImport::flushElementValue(
F_DOMNode * pParent,
FLMBYTE * pucValue,
FLMUINT uiValueLen)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pData = NULL;
FLMUNICODE * puzTextStart = (FLMUNICODE *)pucValue;
if( !uiValueLen)
{
flmAssert( 0);
goto Exit;
}
if( RC_BAD( rc = pParent->createNode( m_pDb, DATA_NODE, 0,
XFLM_LAST_CHILD, (IF_DOMNode **)&pData)))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_CREATING_DATA_NODE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
goto Exit;
}
switch( pParent->m_pCachedNode->getDataType())
{
case XFLM_TEXT_TYPE:
{
if( RC_BAD( rc = pData->setUnicode( m_pDb, puzTextStart)))
{
goto Exit;
}
m_importStats.uiText++;
if( m_fnStatus && (m_importStats.uiText % 50) == 0)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
break;
}
case XFLM_NUMBER_TYPE:
{
FLMUINT64 ui64Val;
FLMBOOL bNeg;
if( RC_BAD( rc = unicodeToNumber64( puzTextStart, &ui64Val, &bNeg)))
{
goto Exit;
}
if( !bNeg)
{
if( RC_BAD( rc = pData->setUINT64( m_pDb, ui64Val)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pData->setINT64( m_pDb, -((FLMINT64)ui64Val))))
{
goto Exit;
}
}
break;
}
case XFLM_BINARY_TYPE:
{
if( RC_BAD( rc = pData->setBinary( m_pDb, pucValue, uiValueLen)))
{
goto Exit;
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
Exit:
if( pData)
{
pData->Release();
}
return( rc);
}
/****************************************************************************
Desc: Processes an XML element
****************************************************************************/
RCODE F_XMLImport::processElement(
F_DOMNode * pNodeToLinkTo,
eNodeInsertLoc eInsertLoc,
F_DOMNode ** ppNewNode)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bHasContent;
FLMBOOL bFlushedValue = FALSE;
FLMUINT uiChars;
FLMUINT uiOffset = 0;
FLMUNICODE uChar;
F_DOMNode * pElement = NULL;
F_XMLNamespace * pNamespace = NULL;
FLMUNICODE * puzPrefix;
FLMUNICODE * puzLocal;
FLMUINT uiStartNSCount = getNamespaceCount();
FLMUINT uiTmp;
FLMUINT uiWhitespaceStartOffset = 0;
FLMBOOL bNamespaceDecl;
FLMUINT uiSavedLineNum = 0;
FLMUINT uiSavedOffset = 0;
FLMUINT uiSavedFilePos = 0;
FLMUINT uiSavedLineBytes = 0;
if( RC_BAD( rc = processSTag( pNodeToLinkTo, eInsertLoc, &bHasContent, &pElement)))
{
goto Exit;
}
if (ppNewNode)
{
*ppNewNode = pElement;
(*ppNewNode)->AddRef();
}
if( !bHasContent)
{
goto Exit;
}
for( ;;)
{
if ((uChar = getChar()) == 0)
{
uChar = ASCII_NEWLINE;
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
}
if( uChar == FLM_UNICODE_LT)
{
if( uiWhitespaceStartOffset)
{
// Set the offset to where the whitespace would
// have started.
flmAssert( uiWhitespaceStartOffset <= uiOffset);
uiOffset = uiWhitespaceStartOffset;
uiWhitespaceStartOffset = 0;
}
if( uiOffset)
{
// Flush the value
if( pElement)
{
if( pElement->m_pCachedNode->getDataType() == XFLM_TEXT_TYPE ||
pElement->m_pCachedNode->getDataType() == XFLM_NUMBER_TYPE)
{
if( uiOffset + 1 >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( uiOffset + 2)))
{
goto Exit;
}
}
m_pucValBuf[ uiOffset] = 0;
m_pucValBuf[ uiOffset + 1] = 0;
}
if( RC_BAD( rc = flushElementValue(
pElement, m_pucValBuf, uiOffset)))
{
goto Exit;
}
}
bFlushedValue = TRUE;
uiOffset = 0;
}
// Preserve start location for error handling if necessary
uiSavedLineNum = m_uiCurrLineNum;
uiSavedOffset = m_uiCurrLineOffset;
uiSavedFilePos = m_uiCurrLineFilePos;
uiSavedLineBytes = m_uiCurrLineBytes;
if (lineHasToken( "?"))
{
if( RC_BAD( rc = processPI( pElement,
uiSavedLineNum,
uiSavedOffset,
uiSavedFilePos,
uiSavedLineBytes)))
{
goto Exit;
}
}
else if (lineHasToken( "!--"))
{
if( RC_BAD( rc = processComment( pElement,
uiSavedLineNum,
uiSavedOffset,
uiSavedFilePos,
uiSavedLineBytes)))
{
goto Exit;
}
}
else if (lineHasToken( "![CDATA["))
{
if( RC_BAD( rc = processCDATA( pElement,
uiSavedLineNum,
uiSavedOffset,
uiSavedFilePos,
uiSavedLineBytes)))
{
goto Exit;
}
}
else if (lineHasToken( "/"))
{
break;
}
else if( gv_XFlmSysData.pXml->isNameChar( peekChar()))
{
// Unget the "<" - because processElement expect to see
// "<elementname"
ungetChar();
if( RC_BAD( rc = processElement( pElement, XFLM_LAST_CHILD, NULL)))
{
goto Exit;
}
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_BAD_ELEMENT_NAME,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
else if( pElement->m_pCachedNode->getDataType() == XFLM_BINARY_TYPE)
{
ungetChar();
if( RC_BAD( rc = getBinaryVal( &uiOffset)))
{
goto Exit;
}
}
else if (uChar == FLM_UNICODE_AMP)
{
if( RC_BAD( rc = processReference( &uChar)))
{
goto Exit;
}
flmAssert( uChar);
if (pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE)
{
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
uiWhitespaceStartOffset = 0;
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
}
else
{
if( pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE)
{
if( m_uiFlags & FLM_XML_COMPRESS_WHITESPACE_FLAG)
{
if( gv_XFlmSysData.pXml->isWhitespace( uChar))
{
// If uiOffset is zero, this is still leading
// white space, and we should ignore it.
// Otherwise, we need to keep track of where
// whitespace began.
if( !uiOffset)
{
uChar = 0;
}
else
{
uiWhitespaceStartOffset = uiOffset;
}
}
else
{
// Last character is not whitespace.
uiWhitespaceStartOffset = 0;
}
}
if( uChar)
{
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
}
}
}
flmAssert( !uiOffset);
uiSavedOffset = m_uiCurrLineOffset;
if( RC_BAD( rc = getQualifiedName( &uiChars,
&puzPrefix, &puzLocal, &bNamespaceDecl, NULL)))
{
goto Exit;
}
// Validate that the end tag matches the start tag
if( pElement)
{
// Element names cannot be "xmlns" or begin with "xmlns:"
if (bNamespaceDecl)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_XMLNS_IN_ELEMENT_NAME,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( puzPrefix)
{
FLMUINT uiPrefixId1;
FLMUINT uiPrefixId2;
if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId(
m_pDb, puzPrefix, &uiPrefixId1)))
{
goto Exit;
}
if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiPrefixId2)))
{
goto Exit;
}
if( uiPrefixId1 != uiPrefixId2)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_ELEMENT_NAME_MISMATCH,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
else
{
if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiTmp)))
{
goto Exit;
}
if( uiTmp)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_ELEMENT_NAME_MISMATCH,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_PREFIX_NOT_DEFINED,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
}
goto Exit;
}
if( RC_BAD( rc = m_pDb->getElementNameId(
pNamespace->getURIPtr(), puzLocal, &uiTmp)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_ELEMENT_NAME_MISMATCH,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
}
goto Exit;
}
if( pElement->getNameId() != uiTmp)
{
setErrInfo( m_uiCurrLineNum,
uiSavedOffset,
XML_ERR_ELEMENT_NAME_MISMATCH,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
// Skip any whitespace after the name
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
// Get the ending ">"
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
if( pNamespace)
{
pNamespace->Release();
}
popNamespaces( getNamespaceCount() - uiStartNSCount);
if( pElement)
{
pElement->Release();
}
return( rc);
}
/****************************************************************************
Desc: Processes an XML STag
****************************************************************************/
RCODE F_XMLImport::processSTag(
F_DOMNode * pNodeToLinkTo,
eNodeInsertLoc eInsertLoc,
FLMBOOL * pbHasContent,
F_DOMNode ** ppElement)
{
FLMUNICODE uChar;
FLMUINT uiChars;
F_DOMNode * pElement = NULL;
F_XMLNamespace * pNamespace = NULL;
FLMUNICODE * puzTmpPrefix;
FLMUNICODE * puzPrefix = NULL;
FLMUNICODE * puzTmpLocal;
FLMUNICODE * puzLocal = NULL;
FLMUINT uiNameId;
FLMUINT uiAllocSize;
void * pvMark = m_tmpPool.poolMark();
RCODE rc = NE_XFLM_OK;
FLMBOOL bNamespaceDecl;
FLMUINT uiSavedLineNum;
FLMUINT uiSavedOffset;
FLMUINT uiSavedFilePos;
FLMUINT uiSavedLineBytes;
*pbHasContent = FALSE;
if( getChar() != FLM_UNICODE_LT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_ELEMENT_LT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
uiSavedLineNum = m_uiCurrLineNum;
uiSavedOffset = m_uiCurrLineOffset;
uiSavedFilePos = m_uiCurrLineFilePos;
uiSavedLineBytes = m_uiCurrLineBytes;
if( RC_BAD( rc = getQualifiedName( &uiChars, &puzTmpPrefix, &puzTmpLocal,
&bNamespaceDecl, NULL)))
{
goto Exit;
}
// Element names cannot be "xmlns" or begin with "xmlns:"
if (bNamespaceDecl)
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_XMLNS_IN_ELEMENT_NAME,
uiSavedFilePos,
uiSavedLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
uiAllocSize = (f_unilen( puzTmpLocal) + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzLocal)))
{
goto Exit;
}
f_unicpy( puzLocal, puzTmpLocal);
if( puzTmpPrefix)
{
// Need to save the prefix, because as parsing
// continues, the scratch buffer will be overwritten
uiAllocSize = (f_unilen( puzTmpPrefix) + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzPrefix)))
{
goto Exit;
}
f_unicpy( puzPrefix, puzTmpPrefix);
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
// Read the attributes
resetAttrList();
uChar = peekChar();
if( uChar != FLM_UNICODE_GT && uChar != FLM_UNICODE_FSLASH)
{
if( RC_BAD( rc = processAttributeList()))
{
goto Exit;
}
}
// Find or create the element's name ID
if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_PREFIX_NOT_DEFINED,
uiSavedFilePos,
uiSavedLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
}
goto Exit;
}
if( RC_BAD( rc = m_pDb->getElementNameId(
pNamespace->getURIPtr(), puzLocal, &uiNameId)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) ||
(pNamespace->getURIPtr() &&
f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0))
{
rc = RC_SET( NE_XFLM_UNDEFINED_ELEMENT_NAME);
goto Exit;
}
// Automatically extend the schema
uiNameId = 0;
if( RC_BAD( rc = m_pDb->createElementDef(
pNamespace->getURIPtr(),
puzLocal, XFLM_TEXT_TYPE, &uiNameId)))
{
goto Exit;
}
}
// Create the element node
if( pNodeToLinkTo)
{
if( RC_BAD( rc = pNodeToLinkTo->createNode( m_pDb, ELEMENT_NODE,
uiNameId, eInsertLoc, (IF_DOMNode **)&pElement)))
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_CREATING_ELEMENT_NODE,
uiSavedFilePos,
uiSavedLineBytes);
goto Exit;
}
}
else
{
if( RC_BAD( rc = m_pDb->createRootElement( m_uiCollection,
uiNameId, (IF_DOMNode **)&pElement)))
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_CREATING_ROOT_ELEMENT,
uiSavedFilePos,
uiSavedLineBytes);
goto Exit;
}
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
// Need to end with ">" or "/>"
uChar = getChar();
if( uChar == FLM_UNICODE_GT)
{
*pbHasContent = TRUE;
}
else if( uChar == FLM_UNICODE_FSLASH)
{
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
// Set the element's prefix
if( RC_BAD( rc = addAttributesToElement( pElement)))
{
goto Exit;
}
if( puzPrefix)
{
if( RC_BAD( rc = pElement->setPrefix( m_pDb, puzPrefix)))
{
goto Exit;
}
}
if( ppElement)
{
*ppElement = pElement;
pElement = NULL;
}
m_importStats.uiElements++;
if( m_fnStatus && (m_importStats.uiElements % 50) == 0)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
Exit:
if( pElement)
{
pElement->Release();
}
if( pNamespace)
{
pNamespace->Release();
}
m_tmpPool.poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc: Processes an element's attributes
****************************************************************************/
RCODE F_XMLImport::processAttributeList( void)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiChars;
FLMUNICODE * puzLocal;
FLMUNICODE * puzPrefix;
XML_ATTR * pAttr = NULL;
FLMBOOL bFoundDefaultNamespace = FALSE;
FLMUINT uiNamespaceCount = 0;
FLMBOOL bNamespaceDecl;
FLMBOOL bDefaultNamespaceDecl;
FLMUINT uiSavedLineNum;
FLMUINT uiSavedOffset;
FLMUINT uiSavedFilePos;
FLMUINT uiSavedLineBytes;
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( !gv_XFlmSysData.pXml->isNameChar( peekChar()))
{
break;
}
uiSavedLineNum = m_uiCurrLineNum;
uiSavedOffset = m_uiCurrLineOffset;
uiSavedFilePos = m_uiCurrLineFilePos;
uiSavedLineBytes = m_uiCurrLineBytes;
if( RC_BAD( rc = getQualifiedName( &uiChars,
&puzPrefix, &puzLocal, &bNamespaceDecl,
&bDefaultNamespaceDecl)))
{
goto Exit;
}
if( RC_BAD( rc = allocAttribute( &pAttr)))
{
goto Exit;
}
pAttr->uiLineNum = uiSavedLineNum;
pAttr->uiLineOffset = uiSavedOffset;
pAttr->uiLineFilePos = uiSavedFilePos;
pAttr->uiLineBytes = uiSavedLineBytes;
if( RC_BAD( rc = setPrefix( pAttr, puzPrefix)))
{
goto Exit;
}
if( RC_BAD( rc = setLocalName( pAttr, puzLocal)))
{
goto Exit;
}
if (bNamespaceDecl)
{
if (bDefaultNamespaceDecl)
{
pAttr->uiFlags |= F_DEFAULT_NS_DECL;
}
else
{
pAttr->uiFlags |= F_PREFIXED_NS_DECL;
}
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
// Attribute name must be followed by an "="
if( getChar() != FLM_UNICODE_EQ)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_EQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
pAttr->uiValueLineNum = m_uiCurrLineNum;
pAttr->uiValueLineOffset = m_uiCurrLineOffset;
if( RC_BAD( rc = processAttValue( pAttr)))
{
goto Exit;
}
m_importStats.uiAttributes++;
if( m_fnStatus && (m_importStats.uiAttributes % 50) == 0)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
}
// Push any namespace declarations onto the stack
for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext)
{
// Duplicate namespace declarations are not allowed within a single element.
// So, multiple default namespace declarations or multiple uses of the same
// prefix in will result in a syntax error.
if( pAttr->uiFlags & F_DEFAULT_NS_DECL)
{
// Default namespace declaration
if( bFoundDefaultNamespace)
{
setErrInfo( pAttr->uiLineNum,
pAttr->uiLineOffset,
XML_ERR_MULTIPLE_XMLNS_DECLS,
pAttr->uiLineFilePos,
pAttr->uiLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( !pAttr->puzVal || *pAttr->puzVal == 0)
{
// No namespace
if( RC_BAD( rc = pushNamespace( NULL, NULL)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pushNamespace( NULL, pAttr->puzVal)))
{
goto Exit;
}
}
uiNamespaceCount++;
bFoundDefaultNamespace = TRUE;
}
else if( pAttr->uiFlags & F_PREFIXED_NS_DECL)
{
// Check for a unique prefix within current element
if( RC_OK( rc = findNamespace( &pAttr->puzLocalName [6],
NULL, uiNamespaceCount)))
{
setErrInfo( pAttr->uiLineNum,
pAttr->uiLineOffset,
XML_ERR_MULTIPLE_PREFIX_DECLS,
pAttr->uiLineFilePos,
pAttr->uiLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
else if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
else
{
rc = NE_XFLM_OK;
}
if( RC_BAD( rc = pushNamespace(
&pAttr->puzLocalName [6], pAttr->puzVal)))
{
goto Exit;
}
uiNamespaceCount++;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML declaration
****************************************************************************/
RCODE F_XMLImport::processXMLDecl( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
// Have already eaten the "<?xml" - must have whitespace after it
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = processVersion()))
{
goto Exit;
}
uChar = peekChar();
if (!uChar || gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if (RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
else
{
goto Process_Question_Mark;
}
if (lineHasToken( "encoding"))
{
if( RC_BAD( rc = processEncodingDecl()))
{
goto Exit;
}
uChar = peekChar();
if (!uChar || gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if (RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
else
{
goto Process_Question_Mark;
}
}
if (lineHasToken( "standalone"))
{
if( RC_BAD( rc = processSDDecl()))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
Process_Question_Mark:
if (!lineHasToken( "?>"))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_QUEST_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML document type declaration
****************************************************************************/
RCODE F_XMLImport::processDocTypeDecl( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
// Have already eaten the "<!DOCTYPE"
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
uChar = peekChar();
if (!uChar || gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (lineHasToken( "SYSTEM"))
{
if( RC_BAD( rc = processID( FALSE)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
else if (lineHasToken( "PUBLIC"))
{
if( RC_BAD( rc = processID( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
}
if( peekChar() == FLM_UNICODE_LBRACKET)
{
// Eat up the '['
(void)getChar();
for( ;;)
{
uChar = getChar();
if( uChar == FLM_UNICODE_PERCENT)
{
if( RC_BAD( rc = processPERef()))
{
goto Exit;
}
}
else if( uChar == FLM_UNICODE_RBRACKET)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
break;
}
else if (gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
else
{
ungetChar();
if( RC_BAD( rc = processMarkupDecl()))
{
goto Exit;
}
}
}
}
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: See if the current line has the specified token in it starting
from the current offset.
****************************************************************************/
FLMBOOL F_XMLImport::lineHasToken(
const char * pszToken)
{
FLMUINT uiOffset;
uiOffset = m_uiCurrLineOffset;
while (uiOffset < m_uiCurrLineNumChars)
{
if (m_puzCurrLineBuf [uiOffset] != (FLMUNICODE)(*pszToken))
{
// Do NOT change m_uiCurrLineOffset if we return FALSE.
return( FALSE);
}
pszToken++;
uiOffset++;
if (*pszToken == 0)
{
m_uiCurrLineOffset = uiOffset;
return( TRUE);
}
}
return( FALSE);
}
/****************************************************************************
Desc: Processes an XML markup declaration
****************************************************************************/
RCODE F_XMLImport::processMarkupDecl( void)
{
RCODE rc = NE_XFLM_OK;
if (lineHasToken( "<?"))
{
rc = processPI( NULL, 0, 0, 0, 0);
goto Exit;
}
if (lineHasToken( "<!--"))
{
rc = processComment( NULL, 0, 0, 0, 0);
goto Exit;
}
if (lineHasToken( "<!ENTITY"))
{
rc = processEntityDecl();
goto Exit;
}
if (lineHasToken( "<!ELEMENT"))
{
rc = processElementDecl();
goto Exit;
}
if (lineHasToken( "<!ATTLIST"))
{
rc = processAttListDecl();
goto Exit;
}
if (lineHasToken( "<!NOTATION"))
{
rc = processNotationDecl();
goto Exit;
}
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_INVALID_XML_MARKUP,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML element declaration
****************************************************************************/
RCODE F_XMLImport::processElementDecl( void)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten up the "<!ELEMENT" - must be followed by whitespace
// before the name.
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = processContentSpec()))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an attribute list declaration
****************************************************************************/
RCODE F_XMLImport::processAttListDecl( void)
{
FLMUNICODE uChar;
FLMUINT uiAttDefCount = 0;
RCODE rc = NE_XFLM_OK;
FLMUINT uiAttListLineNum = m_uiCurrLineNum;
FLMUINT uiAttListLineOffset = m_uiCurrLineOffset - 9;
// Have already eaten up the "<!ATTLIST" - must be whitespace before
// the name.
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
for( ;;)
{
uChar = peekChar();
if (!uChar || gv_XFlmSysData.pXml->isWhitespace( uChar))
{
if (RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( peekChar() == FLM_UNICODE_GT)
{
break;
}
if( RC_BAD( rc = processAttDef()))
{
goto Exit;
}
uiAttDefCount++;
}
else if (uChar == FLM_UNICODE_GT)
{
break;
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
uChar = getChar();
flmAssert( uChar == FLM_UNICODE_GT);
if( !uiAttDefCount)
{
setErrInfo( uiAttListLineNum,
uiAttListLineOffset,
XML_ERR_MUST_HAVE_ONE_ATT_DEF,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes and entity declaration
****************************************************************************/
RCODE F_XMLImport::processEntityDecl( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bGEDecl = FALSE;
// Have already eaten up the "<!ENTITY" - must be followed by whitespace
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( peekChar() == FLM_UNICODE_PERCENT)
{
uChar = getChar();
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
else
{
bGEDecl = TRUE;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
// Name must be followed by whitespace
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
uChar = peekChar();
if( gv_XFlmSysData.pXml->isQuoteChar( uChar))
{
if( RC_BAD( rc = processEntityValue()))
{
goto Exit;
}
}
else
{
if (lineHasToken( "SYSTEM"))
{
if( RC_BAD( rc = processID( TRUE)))
{
goto Exit;
}
}
else if (lineHasToken( "PUBLIC"))
{
if( RC_BAD( rc = processID( FALSE)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
goto Process_GT;
}
if (!gv_XFlmSysData.pXml->isWhitespace( peekChar()))
{
goto Process_GT;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (!bGEDecl)
{
goto Process_GT;
}
if (!lineHasToken( "NDATA"))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_NDATA,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
// Whitespace must be between the NDATA and the name
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
}
Process_GT:
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML ID
****************************************************************************/
RCODE F_XMLImport::processID(
FLMBOOL bPublicId)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten the "SYSTEM" or "PUBLIC" token
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if (bPublicId)
{
// Public ID
if( RC_BAD( rc = getPubidLiteral()))
{
goto Exit;
}
// Must be whitespace if it wasn't a '>'
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
}
// Get the system ID
if (RC_BAD( rc = getSystemLiteral()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes a notation declaration
****************************************************************************/
RCODE F_XMLImport::processNotationDecl( void)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten up the "<!NOTATION" - must be whitespace before
// the name.
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
// Must be whitespace following the name
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if (lineHasToken( "SYSTEM"))
{
if( RC_BAD( rc = processID( FALSE)))
{
goto Exit;
}
}
else if (lineHasToken( "PUBLIC"))
{
if( RC_BAD( rc = processID( TRUE)))
{
goto Exit;
}
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_SYSTEM_OR_PUBLIC,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( getChar() != FLM_UNICODE_GT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_GT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes and attribute definition
****************************************************************************/
RCODE F_XMLImport::processAttDef( void)
{
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
// Must be whitespace between the name and type
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = processAttType()))
{
goto Exit;
}
// Must be whitespace between type and default decl.
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = processDefaultDecl()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an attribute type
****************************************************************************/
RCODE F_XMLImport::processAttType( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMUINT uiChars;
if (lineHasToken( "CDATA"))
{
}
else if (lineHasToken( "ID"))
{
if (lineHasToken( "REF"))
{
if (peekChar() == FLM_UNICODE_S)
{
(void)getChar();
}
}
}
else if (lineHasToken( "ENTIT"))
{
if (lineHasToken( "IES"))
{
}
else if (peekChar() == FLM_UNICODE_Y)
{
(void)getChar();
}
}
else if (lineHasToken( "NMTOKEN"))
{
if (peekChar() == FLM_UNICODE_S)
{
(void)getChar();
}
}
else if (lineHasToken( "NOTATION"))
{
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if (getChar() != FLM_UNICODE_LPAREN)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_LPAREN,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
uChar = getChar();
if( uChar == FLM_UNICODE_RPAREN)
{
break;
}
else if( uChar != FLM_UNICODE_PIPE)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_RPAREN_OR_PIPE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
}
else if (peekChar() == FLM_UNICODE_LPAREN)
{
(void)getChar();
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
getNmtoken( &uiChars);
if( !uiChars)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_NAME,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
uChar = getChar();
if( uChar == FLM_UNICODE_RPAREN)
{
break;
}
else if( uChar != FLM_UNICODE_PIPE)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_RPAREN_OR_PIPE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_INVALID_ATT_TYPE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes a default declaration
****************************************************************************/
RCODE F_XMLImport::processDefaultDecl( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
uChar = getChar();
if (uChar == FLM_UNICODE_POUND)
{
if (lineHasToken( "FIXED"))
{
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = processAttValue( NULL)))
{
goto Exit;
}
}
else if (lineHasToken( "IMPLIED"))
{
goto Exit;
}
else if (lineHasToken( "REQUIRED"))
{
goto Exit;
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_INVALID_DEFAULT_DECL,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
else if (gv_XFlmSysData.pXml->isQuoteChar( uChar))
{
ungetChar();
if( RC_BAD( rc = processAttValue( NULL)))
{
goto Exit;
}
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_INVALID_DEFAULT_DECL,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes a content specification
****************************************************************************/
RCODE F_XMLImport::processContentSpec( void)
{
RCODE rc = NE_XFLM_OK;
if (lineHasToken( "EMPTY") || lineHasToken( "ANY"))
{
goto Exit;
}
if (getChar() == FLM_UNICODE_LPAREN)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (lineHasToken( "#PCDATA"))
{
if( RC_BAD( rc = processMixedContent()))
{
goto Exit;
}
}
else if (lineHasToken( "#"))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset + 1,
XML_ERR_EXPECTING_PCDATA,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
else
{
if( RC_BAD( rc = processChildContent()))
{
goto Exit;
}
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes mixed content
****************************************************************************/
RCODE F_XMLImport::processMixedContent( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bExpectingAsterisk = FALSE;
// Have eaten up the "(<whitespace>#PCDATA"
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
uChar = getChar();
if( uChar == FLM_UNICODE_RPAREN)
{
break;
}
else if( uChar == FLM_UNICODE_PIPE)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
bExpectingAsterisk = TRUE;
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_RPAREN_OR_PIPE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
if( bExpectingAsterisk)
{
if( getChar() != FLM_UNICODE_ASTERISK)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_ASTERISK,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes child content
****************************************************************************/
RCODE F_XMLImport::processChildContent( void)
{
FLMUNICODE uChar;
FLMUINT uiItemCount = 0;
FLMUINT uiDelimCount = 0;
FLMBOOL bChoice = FALSE;
FLMBOOL bSeq = FALSE;
RCODE rc = NE_XFLM_OK;
// Have eaten up the "("
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
uChar = getChar();
if( uChar == FLM_UNICODE_LPAREN)
{
if( RC_BAD( rc = processChildContent()))
{
goto Exit;
}
uiItemCount++;
}
else if (uChar == FLM_UNICODE_RPAREN)
{
if( !uiItemCount || (uiItemCount - 1) != uiDelimCount)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EMPTY_CONTENT_INVALID,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
break;
}
else if (uChar == FLM_UNICODE_PIPE)
{
if( bSeq)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
bChoice = TRUE;
uiDelimCount++;
}
else if (uChar == FLM_UNICODE_COMMA)
{
if (bChoice)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
bSeq = TRUE;
uiDelimCount++;
}
else
{
ungetChar();
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
uiItemCount++;
uChar = peekChar();
if (uChar == FLM_UNICODE_QUEST ||
uChar == FLM_UNICODE_ASTERISK ||
uChar == FLM_UNICODE_PLUS)
{
// Eat up a "?", "*", or "+"
(void)getChar();
}
}
}
uChar = peekChar();
if( uChar == FLM_UNICODE_QUEST ||
uChar == FLM_UNICODE_ASTERISK ||
uChar == FLM_UNICODE_PLUS)
{
// Eat up a "?", "*", or "+"
(void)getChar();
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes a misc. declaration
****************************************************************************/
RCODE F_XMLImport::processMisc( void)
{
RCODE rc = NE_XFLM_OK;
for( ;;)
{
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
if( rc == NE_FLM_IO_END_OF_FILE || rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
if (lineHasToken( "<!--"))
{
if (RC_BAD( rc = processComment( NULL, 0, 0, 0, 0)))
{
goto Exit;
}
}
else if (lineHasToken( "<?"))
{
if( RC_BAD( rc = processPI( NULL, 0, 0, 0, 0)))
{
goto Exit;
}
}
else
{
break;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes a processing instruction
****************************************************************************/
RCODE F_XMLImport::processPI(
F_DOMNode * pParent,
FLMUINT uiSavedLineNum,
FLMUINT uiSavedOffset,
FLMUINT uiSavedFilePos,
FLMUINT uiSavedLineBytes)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMUINT uiChars;
FLMUINT uiOffset = 0;
F_DOMNode * pPI = NULL;
FLMUINT uiNameLineNum = m_uiCurrLineNum;
FLMUINT uiNameOffset = m_uiCurrLineOffset;
FLMUINT uiNameFilePos = m_uiCurrLineFilePos;
FLMUINT uiNameLineBytes = m_uiCurrLineBytes;
// Have already eaten up the "<?"
if( RC_BAD( rc = getName( &uiChars)))
{
goto Exit;
}
if( uiChars >= 3 &&
(m_uChars[ 0] == FLM_UNICODE_X ||
m_uChars[ 0] == FLM_UNICODE_x) &&
(m_uChars[ 1] == FLM_UNICODE_M ||
m_uChars[ 1] == FLM_UNICODE_m) &&
(m_uChars[ 2] == FLM_UNICODE_L ||
m_uChars[ 2] == FLM_UNICODE_l))
{
setErrInfo( uiNameLineNum,
uiNameOffset,
XML_ERR_XML_ILLEGAL_PI_NAME,
uiNameFilePos,
uiNameLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( pParent)
{
if( RC_BAD( rc = pParent->createNode( m_pDb, PROCESSING_INSTRUCTION_NODE,
0, XFLM_LAST_CHILD, (IF_DOMNode **)&pPI)))
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_CREATING_PI_NODE,
uiSavedFilePos,
uiSavedLineBytes);
goto Exit;
}
if( RC_BAD( rc = pPI->setUnicode( m_pDb, m_uChars)))
{
goto Exit;
}
}
// Must be whitespace after the name
if( RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
for (;;)
{
if (lineHasToken( "?>"))
{
break;
}
if ((uChar = getChar()) == 0)
{
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
uChar = ASCII_NEWLINE;
}
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
if( uiOffset && pPI)
{
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0;
if( RC_BAD( rc = pPI->setUnicode( m_pDb, (FLMUNICODE *)m_pucValBuf)))
{
goto Exit;
}
}
Exit:
if( pPI)
{
pPI->Release();
}
return( rc);
}
/****************************************************************************
Desc: Gets an XML name from the input stream
****************************************************************************/
RCODE F_XMLImport::getName(
FLMUINT * puiChars)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCharCount = 0;
FLMUNICODE uChar;
// Get the first character
uChar = getChar();
if( !gv_XFlmSysData.pXml->isLetter( uChar) && uChar != FLM_UNICODE_UNDERSCORE)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_ILLEGAL_FIRST_NAME_CHAR,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
m_uChars[ uiCharCount++] = uChar;
// Cannot go off of the current line
for (;;)
{
if ((uChar = getChar()) == 0)
{
break;
}
if (!gv_XFlmSysData.pXml->isNameChar( uChar))
{
ungetChar();
break;
}
if (uiCharCount >= FLM_XML_MAX_CHARS)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
m_uChars [uiCharCount++] = uChar;
}
m_uChars[ uiCharCount] = 0;
Exit:
if (puiChars)
{
*puiChars = uiCharCount;
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLImport::getQualifiedName(
FLMUINT * puiChars,
FLMUNICODE ** ppuzPrefix,
FLMUNICODE ** ppuzLocal,
FLMBOOL * pbNamespaceDecl,
FLMBOOL * pbDefaultNamespaceDecl
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCharCount = 0;
FLMUNICODE * puzPrefix = NULL;
FLMUNICODE * puzLocal = &m_uChars [0];
FLMUNICODE uChar;
FLMBOOL bFoundColon = FALSE;
*pbNamespaceDecl = FALSE;
if (pbDefaultNamespaceDecl)
{
*pbDefaultNamespaceDecl = FALSE;
}
// Get the first character, then the rest of the name must
// be on the same line.
uChar = getChar();
if( !gv_XFlmSysData.pXml->isLetter( uChar) && uChar != FLM_UNICODE_UNDERSCORE)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_ILLEGAL_FIRST_NAME_CHAR,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
m_uChars[ uiCharCount++] = uChar;
for (;;)
{
if ((uChar = getChar()) == 0)
{
break;
}
if (!gv_XFlmSysData.pXml->isNameChar( uChar))
{
ungetChar();
break;
}
if( uiCharCount >= FLM_XML_MAX_CHARS)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
if( uChar == FLM_UNICODE_COLON)
{
if( bFoundColon)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_ILLEGAL_COLON_IN_NAME,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
// If what we have so far is "xmlns", then don't put it
// into the prefix - the xmlns: should simply be part of
// the local name.
if (uiCharCount != 5 || !isXMLNS( m_uChars))
{
uChar = 0;
puzPrefix = &m_uChars [0];
puzLocal = &m_uChars[ uiCharCount + 1];
}
else
{
*pbNamespaceDecl = TRUE;
}
bFoundColon = TRUE;
}
m_uChars[ uiCharCount++] = uChar;
}
m_uChars[ uiCharCount] = 0;
*ppuzPrefix = puzPrefix;
*ppuzLocal = puzLocal;
if (!puzPrefix && !*pbNamespaceDecl && uiCharCount == 5 &&
isXMLNS( m_uChars))
{
*pbNamespaceDecl = TRUE;
if (pbDefaultNamespaceDecl)
{
*pbDefaultNamespaceDecl = TRUE;
}
}
Exit:
*puiChars = uiCharCount;
return( rc);
}
/****************************************************************************
Desc: Gets an XML Nmtoken from the input stream
****************************************************************************/
void F_XMLImport::getNmtoken(
FLMUINT * puiChars)
{
FLMUINT uiCharCount = 0;
FLMUNICODE uChar;
for (;;)
{
if ((uChar = getChar()) == 0)
{
break;
}
if( !gv_XFlmSysData.pXml->isNameChar( uChar))
{
ungetChar();
break;
}
uiCharCount++;
}
*puiChars = uiCharCount;
}
/****************************************************************************
Desc: Processes the XML version information encoded within the document
****************************************************************************/
RCODE F_XMLImport::processVersion( void)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten the whitespace
if (!lineHasToken( "version"))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_VERSION,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( getChar() != FLM_UNICODE_EQ)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_EQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
// Version must be '1.0' or "1.0"
if (!lineHasToken( "'1.0'") && !lineHasToken( "\"1.0\""))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_INVALID_VERSION_NUM,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML encoding declaration
****************************************************************************/
RCODE F_XMLImport::processEncodingDecl( void)
{
RCODE rc = NE_XFLM_OK;
// Have already skipped the "encoding"
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (getChar() != FLM_UNICODE_EQ)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_EQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (lineHasToken( "'UTF-8'") || lineHasToken( "\"UTF-8\"") ||
lineHasToken( "'utf-8'") || lineHasToken( "\"utf-8\""))
{
m_eXMLEncoding = XFLM_XML_UTF8_ENCODING;
}
else if (lineHasToken( "'us-ascii'") || lineHasToken( "\"us-ascii\""))
{
m_eXMLEncoding = XFLM_XML_USASCII_ENCODING;
}
else
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_UNSUPPORTED_ENCODING,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
m_importStats.eXMLEncoding = m_eXMLEncoding;
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML SD declaration
****************************************************************************/
RCODE F_XMLImport::processSDDecl( void)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten the "standalone"
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if( getChar() != FLM_UNICODE_EQ)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_EQ,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (!lineHasToken( "'yes'") &&
!lineHasToken( "\"yes\"") &&
!lineHasToken( "'no'") &&
!lineHasToken( "\"no\""))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_YES_OR_NO,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Get next byte from input stream.
****************************************************************************/
RCODE F_XMLImport::getByte(
FLMBYTE * pucByte)
{
RCODE rc = NE_XFLM_OK;
if (m_ucUngetByte)
{
*pucByte = m_ucUngetByte;
m_ucUngetByte = 0;
}
else
{
if( RC_BAD( rc = m_pStream->read( (char *)pucByte, 1, NULL)))
{
goto Exit;
}
}
m_importStats.uiChars++;
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads next line from the input stream.
****************************************************************************/
RCODE F_XMLImport::getLine( void)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucByte1;
FLMBYTE ucByte2;
FLMBYTE ucByte3;
FLMUNICODE uChar;
m_uiCurrLineNumChars = 0;
m_uiCurrLineOffset = 0;
m_uiCurrLineFilePos = m_importStats.uiChars;
for (;;)
{
if( RC_BAD( rc = getByte( &ucByte1)))
{
if (rc == NE_XFLM_EOF_HIT)
{
if (m_uiCurrLineNumChars)
{
rc = NE_XFLM_OK;
}
}
goto Exit;
}
// Keep count of the characters.
if( m_fnStatus && (m_importStats.uiChars % 1024) == 0)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
// Convert CRLF->CR
if( ucByte1 == ASCII_CR)
{
if( RC_BAD( rc = getByte( &ucByte1)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
else
{
goto Exit;
}
}
if( ucByte1 != ASCII_NEWLINE)
{
ungetByte( ucByte1);
}
// End of the line
break;
}
else if (ucByte1 == ASCII_NEWLINE)
{
// End of the line
break;
}
// Look for escape sequences
if( m_uiFlags & FLM_XML_TRANSLATE_ESC_FLAG)
{
if( ucByte1 == ASCII_BACKSLASH)
{
if( RC_BAD( rc = getByte( &ucByte1)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
uChar = ASCII_BACKSLASH;
goto Process_Char;
}
else
{
goto Exit;
}
}
if( ucByte1 == ASCII_LOWER_N)
{
// End of line
break;
}
else if( ucByte1 == ASCII_LOWER_T)
{
uChar = ASCII_TAB;
goto Process_Char;
}
else if( ucByte1 == ASCII_BACKSLASH)
{
// No translation -- preserve backslash
uChar = ASCII_BACKSLASH;
goto Process_Char;
}
else
{
ungetByte( ucByte1);
uChar = ASCII_BACKSLASH;
goto Process_Char;
}
}
}
if( m_eXMLEncoding == XFLM_XML_UTF8_ENCODING)
{
if( ucByte1 <= 0x7F)
{
uChar = (FLMUNICODE)ucByte1;
}
else
{
if( RC_BAD( rc = getByte( &ucByte2)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_BAD_UTF8);
}
goto Exit;
}
if( (ucByte2 >> 6) != 0x02)
{
rc = RC_SET( NE_XFLM_BAD_UTF8);
goto Exit;
}
if( (ucByte1 >> 5) == 0x06)
{
uChar = ((FLMUNICODE)( ucByte1 - 0xC0) << 6) +
(FLMUNICODE)(ucByte2 - 0x80);
}
else
{
if( RC_BAD( rc = getByte( &ucByte3)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_BAD_UTF8);
}
goto Exit;
}
if( (ucByte3 >> 6) != 0x02 || (ucByte1 >> 4) != 0x0E)
{
rc = RC_SET( NE_XFLM_BAD_UTF8);
goto Exit;
}
uChar = ((FLMUNICODE)(ucByte1 - 0xE0) << 12) +
((FLMUNICODE)(ucByte2 - 0x80) << 6) +
(FLMUNICODE)(ucByte3 - 0x80);
}
}
}
else if( m_eXMLEncoding == XFLM_XML_USASCII_ENCODING)
{
uChar = (FLMUNICODE)ucByte1;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
Process_Char:
// We have a character, add it to the current line.
if (m_uiCurrLineNumChars == m_uiCurrLineBufMaxChars)
{
// Allocate more space for the line buffer
if (RC_BAD( rc = f_realloc(
sizeof( FLMUNICODE) * (m_uiCurrLineBufMaxChars + 512),
&m_puzCurrLineBuf)))
{
goto Exit;
}
m_uiCurrLineBufMaxChars += 512;
}
m_puzCurrLineBuf [m_uiCurrLineNumChars++] = uChar;
m_uiCurrLineBytes = m_importStats.uiChars - m_uiCurrLineFilePos;
}
// Increment the line count
m_uiCurrLineNum++;
m_importStats.uiLines++;
if( m_fnStatus && (m_importStats.uiLines % 100) == 0)
{
m_fnStatus( XML_STATS,
(void *)&m_importStats, NULL, NULL, m_pvCallbackData);
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML entity value
****************************************************************************/
RCODE F_XMLImport::processEntityValue( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMUNICODE uQuoteChar;
uQuoteChar = getChar();
// Caller should already have looked to make sure the
// character is a quote character.
flmAssert( gv_XFlmSysData.pXml->isQuoteChar( uQuoteChar));
for( ;;)
{
if ((uChar = getChar()) == 0)
{
// Quoted value cannot go to next line
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_QUOTE_BEFORE_EOL,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if (uChar == uQuoteChar)
{
break;
}
else if( uChar == FLM_UNICODE_PERCENT)
{
if( RC_BAD( rc = processPERef()))
{
goto Exit;
}
}
else if( uChar == FLM_UNICODE_AMP)
{
if( RC_BAD( rc = processReference( NULL)))
{
goto Exit;
}
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML PERef
****************************************************************************/
RCODE F_XMLImport::processPERef( void)
{
RCODE rc = NE_XFLM_OK;
// Have already eaten the "%" character
// Name must immediately follow on the same line as the %
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
if( getChar() != FLM_UNICODE_SEMI)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_SEMI,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML reference
****************************************************************************/
RCODE F_XMLImport::processReference(
FLMUNICODE * puChar)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMBOOL bHex = FALSE;
FLMUINT uiNum;
FLMUINT uiNumOffset;
if( puChar)
{
*puChar = 0;
}
// Ampersand has already been processed.
if (peekChar() == FLM_UNICODE_POUND)
{
uiNumOffset = m_uiCurrLineOffset - 1;
(void)getChar();
if (peekChar() == FLM_UNICODE_x)
{
(void)getChar();
bHex = TRUE;
}
uiNum = 0;
for (;;)
{
if ((uChar = getChar()) == 0)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_UNEXPECTED_EOL_IN_ENTITY,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if (uChar == FLM_UNICODE_SEMI)
{
if (!uiNum || uiNum > 0xFFFF)
{
setErrInfo( m_uiCurrLineNum,
uiNumOffset,
XML_ERR_INVALID_CHARACTER_NUMBER,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if (puChar)
{
*puChar = (FLMUNICODE)uiNum;
}
break;
}
// Validate that the characters are valid dec/hex characters
if( bHex)
{
if (uChar >= ASCII_ZERO && uChar <= ASCII_NINE)
{
uiNum <<= 4;
uiNum += (FLMUINT)(uChar - ASCII_ZERO);
}
else if (uChar >= ASCII_UPPER_A && uChar <= ASCII_UPPER_F)
{
uiNum <<= 4;
uiNum += (FLMUINT)(uChar - ASCII_UPPER_A + 10);
}
else if (uChar >= ASCII_LOWER_A && uChar <= ASCII_LOWER_F)
{
uiNum <<= 4;
uiNum += (FLMUINT)(uChar - ASCII_LOWER_A + 10);
}
else
{
setErrInfo( m_uiCurrLineNum,
uiNumOffset,
XML_ERR_INVALID_CHARACTER_NUMBER,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
else
{
if (uChar >= ASCII_ZERO && uChar <= ASCII_NINE)
{
uiNum *= 10;
uiNum += (FLMUINT)(uChar - ASCII_ZERO);
}
else
{
setErrInfo( m_uiCurrLineNum,
uiNumOffset,
XML_ERR_INVALID_CHARACTER_NUMBER,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
// Cannot handle unicode characters more than 16 bits.
if (uiNum > 0xFFFF)
{
setErrInfo( m_uiCurrLineNum,
uiNumOffset,
XML_ERR_INVALID_CHARACTER_NUMBER,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
}
else if (lineHasToken( "lt;"))
{
if (puChar)
{
*puChar = FLM_UNICODE_LT;
}
}
else if (lineHasToken( "gt;"))
{
if (puChar)
{
*puChar = FLM_UNICODE_GT;
}
}
else if (lineHasToken( "amp;"))
{
if (puChar)
{
*puChar = FLM_UNICODE_AMP;
}
}
else if (lineHasToken( "apos;"))
{
if (puChar)
{
*puChar = FLM_UNICODE_APOS;
}
}
else if (lineHasToken( "quot;"))
{
if (puChar)
{
*puChar = FLM_UNICODE_QUOTE;
}
}
else if (puChar)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_UNSUPPORTED_ENTITY,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
// If we are expecting an entity that can be turned into
// a character, we need to return an error.
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
else
{
// Name must be on the same line as the '&'
if( RC_BAD( rc = getName( NULL)))
{
goto Exit;
}
// Make sure we have a semicolon after the name
if (getChar() != FLM_UNICODE_SEMI)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_SEMI,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an attribute value
****************************************************************************/
RCODE F_XMLImport::processAttValue(
XML_ATTR * pAttr)
{
FLMUNICODE uChar;
FLMUNICODE uQuoteChar;
FLMUINT uiOffset = 0;
RCODE rc = NE_XFLM_OK;
// Must be on a single or double quote
uQuoteChar = getChar();
if (!gv_XFlmSysData.pXml->isQuoteChar( uQuoteChar))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_QUOTE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
for( ;;)
{
if ((uChar = getChar()) == 0)
{
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
uChar = ASCII_NEWLINE;
}
if (uChar == uQuoteChar)
{
break;
}
else if( uChar == FLM_UNICODE_AMP)
{
if( RC_BAD( rc = processReference( &uChar)))
{
goto Exit;
}
flmAssert( uChar);
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
else
{
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
}
if( pAttr && uiOffset)
{
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0;
if( RC_BAD( rc = setUnicode( pAttr, (FLMUNICODE *)m_pucValBuf)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads an XML system literal from the input stream
****************************************************************************/
RCODE F_XMLImport::getSystemLiteral( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uQuoteChar;
FLMUNICODE uChar;
uQuoteChar = getChar();
if (!gv_XFlmSysData.pXml->isQuoteChar( uQuoteChar))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_QUOTE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
for (;;)
{
// Must terminate with quote character.
if ((uChar = getChar()) == 0)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_QUOTE_BEFORE_EOL,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if (uChar == uQuoteChar)
{
break;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads an XML public ID literal from the input stream
****************************************************************************/
RCODE F_XMLImport::getPubidLiteral( void)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uQuoteChar;
FLMUNICODE uChar;
uQuoteChar = getChar();
if (!gv_XFlmSysData.pXml->isQuoteChar( uQuoteChar))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_QUOTE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
for( ;;)
{
// Must terminate with quote character.
if ((uChar = getChar()) == 0)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_QUOTE_BEFORE_EOL,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if (uChar == uQuoteChar)
{
break;
}
if( !gv_XFlmSysData.pXml->isPubidChar( uChar))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_INVALID_PUBLIC_ID_CHAR,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Processes an XML comment
****************************************************************************/
RCODE F_XMLImport::processComment(
F_DOMNode * pParent,
FLMUINT uiSavedLineNum,
FLMUINT uiSavedOffset,
FLMUINT uiSavedFilePos,
FLMUINT uiSavedLineBytes)
{
FLMUNICODE uChar;
FLMUINT uiOffset;
FLMUINT uiMaxOffset;
F_DOMNode * pComment = NULL;
RCODE rc = NE_XFLM_OK;
// Have already eaten up the "<!--"
uiOffset = 0;
uiMaxOffset = m_uiValBufSize;
for( ;;)
{
// See if we have the termination of the comment
if (lineHasToken( "-->"))
{
break;
}
if ((uChar = getChar()) == 0)
{
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
uChar = ASCII_NEWLINE;
}
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= uiMaxOffset)
{
if (RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
uiMaxOffset = m_uiValBufSize;
}
}
if( pParent)
{
if( RC_BAD( rc = pParent->createNode( m_pDb, COMMENT_NODE, 0,
XFLM_LAST_CHILD, (IF_DOMNode **)&pComment)))
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_CREATING_COMMENT_NODE,
uiSavedFilePos,
uiSavedLineBytes);
goto Exit;
}
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0;
if( RC_BAD( rc = pComment->setUnicode(
m_pDb, (FLMUNICODE *)m_pucValBuf)))
{
goto Exit;
}
pComment->Release();
pComment = NULL;
}
Exit:
if( pComment)
{
pComment->Release();
}
return( rc);
}
/****************************************************************************
Desc: Processes a CDATA tag
****************************************************************************/
RCODE F_XMLImport::processCDATA(
F_DOMNode * pParent,
FLMUINT uiSavedLineNum,
FLMUINT uiSavedOffset,
FLMUINT uiSavedFilePos,
FLMUINT uiSavedLineBytes)
{
FLMUNICODE uChar;
FLMUINT uiOffset = 0;
F_DOMNode * pCData = NULL;
RCODE rc = NE_XFLM_OK;
// Have already eaten up the "<![CDATA["
for( ;;)
{
if (lineHasToken( "]]>"))
{
break;
}
if ((uChar = getChar()) == 0)
{
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
uChar = ASCII_NEWLINE;
}
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar;
uiOffset += sizeof( FLMUNICODE);
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
}
if( pParent)
{
if( RC_BAD( rc = pParent->createNode( m_pDb, CDATA_SECTION_NODE, 0,
XFLM_LAST_CHILD, (IF_DOMNode **)&pCData)))
{
setErrInfo( uiSavedLineNum,
uiSavedOffset,
XML_ERR_CREATING_CDATA_NODE,
uiSavedFilePos,
uiSavedLineBytes);
goto Exit;
}
*((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0;
if( RC_BAD( rc = pCData->setUnicode( m_pDb, (FLMUNICODE *)m_pucValBuf)))
{
goto Exit;
}
pCData->Release();
pCData = NULL;
}
Exit:
if( pCData)
{
pCData->Release();
}
return( rc);
}
/****************************************************************************
Desc: Skips any whitespace characters in the input stream
****************************************************************************/
RCODE F_XMLImport::skipWhitespace(
FLMBOOL bRequired)
{
FLMUNICODE uChar;
FLMUINT uiCount = 0;
RCODE rc = NE_XFLM_OK;
for( ;;)
{
if ((uChar = getChar()) == 0)
{
uiCount++;
if (RC_BAD( rc = getLine()))
{
goto Exit;
}
continue;
}
if( !gv_XFlmSysData.pXml->isWhitespace( uChar))
{
ungetChar();
break;
}
uiCount++;
}
if( !uiCount && bRequired)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
XML_ERR_EXPECTING_WHITESPACE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_XMLImport::resizeValBuffer(
FLMUINT uiSize)
{
RCODE rc = NE_XFLM_OK;
if( uiSize == m_uiValBufSize)
{
goto Exit;
}
if( uiSize == ~((FLMUINT)0))
{
uiSize = m_uiValBufSize + 2048;
}
if( m_pucValBuf)
{
if( uiSize)
{
if( RC_BAD( rc = f_realloc( uiSize, &m_pucValBuf)))
{
goto Exit;
}
}
else
{
f_free( &m_pucValBuf);
m_pucValBuf = NULL;
}
}
else
{
flmAssert( !m_pucValBuf);
if( RC_BAD( rc = f_alloc( uiSize, &m_pucValBuf)))
{
goto Exit;
}
}
m_uiValBufSize = uiSize;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_XMLImport::getBinaryVal(
FLMUINT * puiLength)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uChar;
FLMUNICODE uChar2;
FLMUINT uiOffset = 0;
FLMBOOL bHavePreamble;
flmAssert( *puiLength == 0);
for( ;;)
{
bHavePreamble = FALSE;
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
Retry:
uChar = getChar();
if( !f_isHexChar( uChar))
{
if( uChar != FLM_UNICODE_LT)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_HEX_DIGIT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
ungetChar();
break;
}
uChar2 = getChar();
if( uChar == FLM_UNICODE_0 &&
(uChar2 == FLM_UNICODE_X || uChar2 == FLM_UNICODE_x))
{
if( bHavePreamble)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_HEX_DIGIT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
bHavePreamble = TRUE;
goto Retry;
}
if( !f_isHexChar( uChar2))
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset - 1,
XML_ERR_EXPECTING_HEX_DIGIT,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
m_pucValBuf[ uiOffset++] =
(f_getHexVal( uChar) << 4) | f_getHexVal( uChar2);
if( RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
uChar = getChar();
if( uChar != FLM_UNICODE_COMMA)
{
ungetChar();
}
}
*puiLength = uiOffset;
Exit:
return( rc);
}
/****************************************************************************
Desc: Constructor
****************************************************************************/
F_XMLNamespaceMgr::F_XMLNamespaceMgr()
{
m_pFirstNamespace = NULL;
m_uiNamespaceCount = 0;
}
/****************************************************************************
Desc: Destructor
****************************************************************************/
F_XMLNamespaceMgr::~F_XMLNamespaceMgr()
{
popNamespaces( m_uiNamespaceCount);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_XMLNamespaceMgr::popNamespaces(
FLMUINT uiCount)
{
F_XMLNamespace * pTmpNamespace;
flmAssert( uiCount <= m_uiNamespaceCount);
while( uiCount && m_pFirstNamespace)
{
pTmpNamespace = m_pFirstNamespace;
m_pFirstNamespace = m_pFirstNamespace->m_pNext;
pTmpNamespace->m_pNext = NULL;
pTmpNamespace->Release();
m_uiNamespaceCount--;
uiCount--;
}
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespaceMgr::findNamespace(
FLMUNICODE * puzPrefix,
F_XMLNamespace ** ppNamespace,
FLMUINT uiMaxSearchSize)
{
F_XMLNamespace * pTmpNamespace = m_pFirstNamespace;
RCODE rc = NE_XFLM_OK;
while( pTmpNamespace)
{
if( !uiMaxSearchSize)
{
pTmpNamespace = NULL;
break;
}
if( !puzPrefix && !pTmpNamespace->m_puzPrefix)
{
break;
}
else if( puzPrefix && pTmpNamespace->m_puzPrefix)
{
if( f_unicmp( puzPrefix, pTmpNamespace->m_puzPrefix) == 0)
{
break;
}
}
pTmpNamespace = pTmpNamespace->m_pNext;
uiMaxSearchSize--;
}
if( !pTmpNamespace)
{
rc = RC_SET( NE_XFLM_NOT_FOUND);
goto Exit;
}
if( ppNamespace)
{
if( *ppNamespace)
{
(*ppNamespace)->Release();
}
pTmpNamespace->AddRef();
*ppNamespace = pTmpNamespace;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespaceMgr::pushNamespace(
FLMUNICODE * puzPrefix,
FLMUNICODE * puzNamespaceURI)
{
F_XMLNamespace * pNewNamespace = NULL;
RCODE rc = NE_XFLM_OK;
if( (pNewNamespace = f_new F_XMLNamespace) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( RC_BAD( rc = pNewNamespace->setPrefix( puzPrefix)))
{
goto Exit;
}
if( RC_BAD( rc = pNewNamespace->setURI( puzNamespaceURI)))
{
goto Exit;
}
pNewNamespace->m_pNext = m_pFirstNamespace;
m_pFirstNamespace = pNewNamespace;
pNewNamespace = NULL;
m_uiNamespaceCount++;
Exit:
if( pNewNamespace)
{
pNewNamespace->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespaceMgr::pushNamespace(
F_XMLNamespace * pNamespace)
{
flmAssert( m_pFirstNamespace != pNamespace &&
!pNamespace->m_pNext);
pNamespace->AddRef();
pNamespace->m_pNext = m_pFirstNamespace;
m_pFirstNamespace = pNamespace;
m_uiNamespaceCount++;
return( NE_XFLM_OK);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespace::setPrefix(
FLMUNICODE * puzPrefix)
{
FLMUINT uiLen;
RCODE rc = NE_XFLM_OK;
if( m_puzPrefix)
{
f_free( &m_puzPrefix);
}
if( puzPrefix)
{
uiLen = f_unilen( puzPrefix);
if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1),
&m_puzPrefix)))
{
goto Exit;
}
f_unicpy( m_puzPrefix, puzPrefix);
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespace::setURI(
FLMUNICODE * puzURI)
{
FLMUINT uiLen;
RCODE rc = NE_XFLM_OK;
if( m_puzURI)
{
f_free( &m_puzURI);
}
if( puzURI)
{
uiLen = f_unilen( puzURI);
if( RC_BAD( rc = f_alloc(
sizeof( FLMUNICODE) * (uiLen + 1), &m_puzURI)))
{
goto Exit;
}
f_unicpy( m_puzURI, puzURI);
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLNamespace::setup(
FLMUNICODE * puzPrefix,
FLMUNICODE * puzURI,
F_XMLNamespace * pNext)
{
FLMUINT uiLen;
RCODE rc = NE_XFLM_OK;
flmAssert( !m_puzPrefix);
flmAssert( !m_puzURI);
flmAssert( !m_pNext);
if( puzPrefix)
{
uiLen = f_unilen( puzPrefix);
if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1),
&m_puzPrefix)))
{
goto Exit;
}
f_unicpy( m_puzPrefix, puzPrefix);
}
if( puzURI)
{
uiLen = f_unilen( puzURI);
if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1),
&m_puzURI)))
{
goto Exit;
}
f_unicpy( m_puzURI, puzURI);
}
m_pNext = pNext;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_XMLImport::addAttributesToElement(
F_DOMNode * pElement)
{
RCODE rc = NE_XFLM_OK;
XML_ATTR * pAttr;
F_XMLNamespace * pNamespace = NULL;
F_DOMNode * pTmpNode = NULL;
FLMUINT uiNameId;
FLMUINT uiAttrDataType;
// Make sure any prefixes (e.g., xmlns:xxxx) are added to the database
// before they are used - in case they are used by the attributes
// themselves.
for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext)
{
if( pAttr->uiFlags & F_PREFIXED_NS_DECL)
{
FLMUINT uiPrefixId;
// Create the prefix (stored in &puzLocalName [6]) if it doesn't
// already exist
if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId( m_pDb,
&pAttr->puzLocalName [6], &uiPrefixId)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
uiPrefixId = 0;
if( RC_BAD( rc = m_pDb->createPrefixDef( TRUE,
&pAttr->puzLocalName [6], &uiPrefixId)))
{
goto Exit;
}
}
}
}
// Add the attributes to the element
//
// NOTE: The XML namespace specification states that the names
// of all unqualified attributes are assigned to the
// appropriate per-element-type partition. This means that
// the combination of the attribute name with the parent
// element's type and namespace name is used to uniquely
// identify each unqualified attribute.
//
// For sake of clarity and useability, however, the parser
// deviates from the namespace specification. Each unprefixed
// attribute encountered by the parser will inherit the
// namespace of the parent element, even if the namespace
// is a default namespace.
for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext)
{
if( pAttr->uiFlags & F_DEFAULT_NS_DECL)
{
// Add the namespace declaration to the element
if( RC_BAD( rc = pElement->createAttribute( m_pDb, ATTR_XMLNS_TAG,
(IF_DOMNode **)&pTmpNode)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY)))
{
goto Exit;
}
}
else if( pAttr->uiFlags & F_PREFIXED_NS_DECL)
{
// Find the attribute definition
if( RC_BAD( rc = m_pDb->getAttributeNameId(
NULL, pAttr->puzLocalName, &uiNameId)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG))
{
rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME);
goto Exit;
}
uiNameId = 0;
if( RC_BAD( rc = m_pDb->createAttributeDef(
NULL, pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId,
(IF_DOMNode **)&pTmpNode)))
{
goto Exit;
}
}
// Add the namespace declaration to the element
if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId,
(IF_DOMNode **)&pTmpNode)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY)))
{
goto Exit;
}
}
else
{
if( pAttr->puzPrefix)
{
if( RC_BAD( rc = findNamespace( pAttr->puzPrefix, &pNamespace)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
setErrInfo( pAttr->uiLineNum, pAttr->uiLineOffset,
XML_ERR_PREFIX_NOT_DEFINED, pAttr->uiLineFilePos,
pAttr->uiLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
}
goto Exit;
}
}
else
{
if( pNamespace)
{
pNamespace->Release();
}
pNamespace = NULL;
}
if( RC_BAD( rc = m_pDb->getAttributeNameId(
pNamespace ? pNamespace->getURIPtr() : NULL,
pAttr->puzLocalName, &uiNameId)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) ||
(pNamespace &&
f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0))
{
rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME);
goto Exit;
}
uiNameId = 0;
if( RC_BAD( rc = m_pDb->createAttributeDef(
pNamespace ? pNamespace->getURIPtr() : NULL,
pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId)))
{
goto Exit;
}
}
if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId,
(IF_DOMNode **)&pTmpNode)))
{
goto Exit;
}
if (pAttr->puzPrefix)
{
if( RC_BAD( rc = pTmpNode->setPrefix( m_pDb, pAttr->puzPrefix)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
setErrInfo( pAttr->uiLineNum,
pAttr->uiLineOffset,
XML_ERR_PREFIX_NOT_DEFINED,
pAttr->uiLineFilePos,
pAttr->uiLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
}
goto Exit;
}
}
if( RC_BAD( rc = pTmpNode->getDataType( m_pDb, &uiAttrDataType)))
{
goto Exit;
}
switch( uiAttrDataType)
{
case XFLM_TEXT_TYPE:
{
if( RC_BAD( rc = pTmpNode->setUnicode(
m_pDb, pAttr->puzVal)))
{
goto Exit;
}
break;
}
case XFLM_NUMBER_TYPE:
{
FLMUINT64 ui64Val;
FLMBOOL bNeg;
if( RC_BAD( rc = unicodeToNumber64(
pAttr->puzVal, &ui64Val, &bNeg)))
{
goto Exit;
}
if( !bNeg)
{
if( RC_BAD( rc = pTmpNode->setUINT64( m_pDb, ui64Val)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pTmpNode->setINT64( m_pDb, -((FLMINT64)ui64Val))))
{
goto Exit;
}
}
break;
}
case XFLM_BINARY_TYPE:
{
FLMBOOL bHavePreamble;
FLMUNICODE * puzStr = pAttr->puzVal;
FLMUINT uiOffset = 0;
// Convert the Unicode value to binary
while( puzStr && *puzStr)
{
bHavePreamble = FALSE;
while( gv_XFlmSysData.pXml->isWhitespace( *puzStr))
{
puzStr++;
}
Retry:
if( !f_isHexChar( *puzStr))
{
break;
}
if( *puzStr == FLM_UNICODE_0 &&
(puzStr[ 1] == FLM_UNICODE_X || puzStr[ 1] == FLM_UNICODE_x))
{
if( bHavePreamble)
{
setErrInfo( pAttr->uiValueLineNum,
pAttr->uiValueLineOffset,
XML_ERR_INVALID_BINARY_ATTR_VALUE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
bHavePreamble = TRUE;
puzStr += 2;
goto Retry;
}
if( !f_isHexChar( puzStr[ 1]))
{
setErrInfo( pAttr->uiValueLineNum,
pAttr->uiValueLineOffset,
XML_ERR_INVALID_BINARY_ATTR_VALUE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_XFLM_INVALID_XML);
goto Exit;
}
if( uiOffset >= m_uiValBufSize)
{
if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0))))
{
goto Exit;
}
}
m_pucValBuf[ uiOffset++] =
(f_getHexVal( *puzStr) << 4) | f_getHexVal( puzStr[ 1]);
puzStr += 2;
while( gv_XFlmSysData.pXml->isWhitespace( *puzStr))
{
puzStr++;
}
if( *puzStr == FLM_UNICODE_COMMA)
{
puzStr++;
}
}
if( RC_BAD( rc = pTmpNode->setBinary(
m_pDb, m_pucValBuf, uiOffset)))
{
goto Exit;
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
}
}
Exit:
if( pTmpNode)
{
pTmpNode->Release();
}
if( pNamespace)
{
pNamespace->Release();
}
return( rc);
}
// Some forward declarations
class F_Element;
class F_Attribute;
/*****************************************************************************
Desc: Keeps track of an attribute that we are going to output
*****************************************************************************/
class F_Attribute : public F_Object
{
public:
F_Attribute(
F_Element * pElement)
{
m_uiTmpSpaceSize = sizeof( m_uzTmpSpace);
m_puzName = &m_uzTmpSpace [0];
reset( pElement);
}
~F_Attribute();
FINLINE void reset(
F_Element * pElement)
{
m_uiNameChars = 0;
m_bIsNamespaceDecl = FALSE;
m_bDefaultNamespaceDecl = FALSE;
m_uiNamespaceChars = 0;
m_uiValueChars = 0;
m_uiPrefixChars = 0;
m_pElement = pElement;
}
RCODE allocNameSpace( void);
RCODE setupAttribute(
IF_Db * pDb,
IF_DOMNode * pNode);
RCODE setPrefix( void);
RCODE outputAttr(
IF_OStream * pOStream);
FINLINE F_Attribute * getNext( void)
{
return( m_pNext);
}
private:
FLMUNICODE m_uzTmpSpace [150];
FLMUINT m_uiTmpSpaceSize;
FLMBOOL m_bIsNamespaceDecl;
FLMBOOL m_bDefaultNamespaceDecl;
FLMUNICODE * m_puzName;
FLMUINT m_uiNameChars;
FLMUNICODE * m_puzNamespace;
FLMUINT m_uiNamespaceChars;
FLMUNICODE * m_puzValue;
FLMUINT m_uiValueChars;
FLMUNICODE * m_puzPrefix;
FLMUINT m_uiPrefixChars;
F_Element * m_pElement;
F_Attribute * m_pNext;
friend class F_Element;
};
/*****************************************************************************
Desc: Destructor for F_Attribute class.
*****************************************************************************/
F_Attribute::~F_Attribute()
{
if (m_puzName != &m_uzTmpSpace [0])
{
f_free( &m_puzName);
}
}
/*****************************************************************************
Desc: Keeps track of an element that we are going to output
*****************************************************************************/
class F_Element : public F_Object
{
public:
F_Element(
F_Element * pParentElement,
F_Attribute ** ppAvailAttrs,
FLMUINT * puiNextPrefixNum)
{
m_uiTmpSpaceSize = sizeof( m_uzTmpSpace);
m_puzName = &m_uzTmpSpace [0];
m_pFirstAttr = NULL;
m_pLastAttr = NULL;
m_pNext = NULL;
m_uiIndentCount = 0;
m_bIsDocumentRoot = FALSE;
reset( pParentElement, ppAvailAttrs, puiNextPrefixNum);
}
~F_Element()
{
F_Attribute * pAttr;
F_Attribute * pTmpAttr;
// Delete all of the attributes
pAttr = m_pFirstAttr;
while (pAttr)
{
pTmpAttr = pAttr;
pAttr = pAttr->m_pNext;
delete pTmpAttr;
}
if (m_puzName != &m_uzTmpSpace [0])
{
f_free( &m_puzName);
}
}
FINLINE void reset(
F_Element * pParentElement,
F_Attribute ** ppAvailAttrs,
FLMUINT * puiNextPrefixNum)
{
m_uiNameChars = 0;
m_uiNamespaceChars = 0;
m_uiPrefixChars = 0;
m_pParentElement = pParentElement;
m_puiNextPrefixNum = puiNextPrefixNum;
m_ppAvailAttrs = ppAvailAttrs;
m_pNext = NULL;
m_uiIndentCount = 0;
m_bIsDocumentRoot = FALSE;
}
FINLINE void setIndentCount(
FLMUINT uiIndentCount)
{
m_uiIndentCount = uiIndentCount;
}
FINLINE void setDocumentRoot(
FLMBOOL bIsDocumentRoot)
{
m_bIsDocumentRoot = bIsDocumentRoot;
}
RCODE allocAttr(
F_Attribute ** ppAttr);
FINLINE void makeAttrAvail(
F_Attribute * pAttr)
{
pAttr->m_pNext = *m_ppAvailAttrs;
*m_ppAvailAttrs = pAttr;
}
FINLINE void makeAllAttrsAvail( void)
{
if (m_pFirstAttr)
{
m_pLastAttr->m_pNext = *m_ppAvailAttrs;
*m_ppAvailAttrs = m_pFirstAttr;
m_pFirstAttr = NULL;
m_pLastAttr = NULL;
}
}
RCODE saveAttribute(
IF_Db * pDb,
IF_DOMNode * pNode);
RCODE allocNameSpace( void);
RCODE setupElement(
IF_Db * pDb,
IF_DOMNode * pNode);
RCODE addNamespaceDecl(
FLMUNICODE * puzPrefix,
FLMUINT uiPrefixChars,
FLMUNICODE * puzNamespace,
FLMUINT uiNamespaceChars,
F_Attribute ** ppAttr);
void genPrefix(
FLMUNICODE * puzPrefix,
FLMUINT * puiPrefixChars);
RCODE findPrefix(
FLMUNICODE * puzNamespace,
FLMUINT uiNamespaceChars,
FLMBOOL bForElement,
FLMUNICODE ** ppuzPrefix,
FLMUINT * puiPrefixChars);
FINLINE RCODE setPrefix( void)
{
return( findPrefix( m_puzNamespace, m_uiNamespaceChars, TRUE,
&m_puzPrefix, &m_uiPrefixChars));
}
FINLINE F_Element * getParentElement( void)
{
return( m_pParentElement);
}
RCODE outputElem(
IF_OStream * pOStream,
FLMBOOL bStartOfElement,
FLMBOOL bEndOfElement,
FLMBOOL bAddNewLine);
RCODE outputLocalData(
IF_OStream * pOStream,
IF_DOMNode * pDbNode,
IF_Db * ifpDb,
eExportFormatType eFormatType,
FLMUINT uiIndentCount);
FINLINE F_Element * getNext( void)
{
return( m_pNext);
}
FINLINE void makeAvail(
F_Element ** ppAvailElements)
{
m_pNext = *ppAvailElements;
*ppAvailElements = this;
}
private:
FLMUNICODE m_uzTmpSpace [100];
FLMUINT m_uiTmpSpaceSize;
FLMUNICODE * m_puzName;
FLMUINT m_uiNameChars;
FLMUNICODE * m_puzNamespace;
FLMUINT m_uiNamespaceChars;
FLMUNICODE * m_puzPrefix;
FLMUINT m_uiPrefixChars;
F_Attribute * m_pFirstAttr;
F_Attribute * m_pLastAttr;
F_Element * m_pParentElement;
F_Element * m_pNext;
FLMUINT * m_puiNextPrefixNum;
F_Attribute ** m_ppAvailAttrs;
FLMBOOL m_bIsDocumentRoot;
FLMUINT m_uiIndentCount;
friend class F_Attribute;
};
/*****************************************************************************
Desc: Allocate space to hold the name, namespace, and value for an attribute.
*****************************************************************************/
RCODE F_Attribute::allocNameSpace( void)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiSpaceNeeded;
FLMUNICODE * puzTmp;
uiSpaceNeeded = (m_uiNameChars +
m_uiNamespaceChars +
m_uiValueChars + 3) * sizeof( FLMUNICODE);
if (uiSpaceNeeded > m_uiTmpSpaceSize)
{
if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp)))
{
goto Exit;
}
if (m_puzName != &m_uzTmpSpace [0])
{
f_free( &m_puzName);
}
m_puzName = puzTmp;
m_uiTmpSpaceSize = uiSpaceNeeded;
}
m_puzNamespace = &m_puzName [m_uiNameChars + 1];
m_puzValue = &m_puzNamespace [m_uiNamespaceChars + 1];
Exit:
return( rc);
}
/*****************************************************************************
Desc: Setup an attribute with its namespace, etc.
*****************************************************************************/
RCODE F_Attribute::setupAttribute(
IF_Db * pDb,
IF_DOMNode * pNode
)
{
RCODE rc = NE_XFLM_OK;
// Determine if the attribute is a namespace declaration
if (RC_BAD( rc = pNode->isNamespaceDecl( pDb, &m_bIsNamespaceDecl)))
{
goto Exit;
}
// Get the length of the name of the attribute
if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL,
0, &m_uiNameChars)))
{
goto Exit;
}
// If it is a namespace declaration, no need to get the namespace URI,
// we already know what it is, and we will output it with an xmlns prefix
// Otherwise, we need to get the namespace so we can determine a prefix,
// if any. If the namespace is the same namespace as the enclosing
// element, we do not need to output a prefix.
if (!m_bIsNamespaceDecl)
{
// Get the number of characters in the namespace of the attribute
if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL,
0, &m_uiNamespaceChars)))
{
goto Exit;
}
}
// Get the number of characters in the attribute's value.
if (RC_BAD( rc = pNode->getUnicodeChars( pDb, &m_uiValueChars)))
{
goto Exit;
}
// Allocate space for the name, namespace, and value
if (RC_BAD( rc = allocNameSpace()))
{
goto Exit;
}
// Get the attribute name.
if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName,
(m_uiNameChars + 1) * sizeof( FLMUNICODE),
&m_uiNameChars)))
{
goto Exit;
}
// Get the namespace, if necessary
if (m_uiNamespaceChars)
{
if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace,
(m_uiNamespaceChars + 1) * sizeof( FLMUNICODE),
&m_uiNamespaceChars)))
{
goto Exit;
}
}
// Get the value, if any
if (m_uiValueChars)
{
if (RC_BAD( rc = pNode->getUnicode( pDb, m_puzValue,
(m_uiValueChars + 1) * sizeof( FLMUNICODE),
0, m_uiValueChars, &m_uiValueChars)))
{
goto Exit;
}
}
// If it is a namespace declaration, the local name must either be
// "xmlns" or begin with "xmlns:"
if (m_bIsNamespaceDecl)
{
// Make sure name is "xmlns" or begins with "xmlns:"
if (m_uiNameChars != 5 && m_uiNameChars <= 6)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL);
goto Exit;
}
if (!isXMLNS( m_puzName))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL);
goto Exit;
}
else if (m_uiNameChars == 5)
{
m_bDefaultNamespaceDecl = TRUE;
}
else if (m_puzName [5] != ':')
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL);
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Set the prefix for an attribute.
*****************************************************************************/
RCODE F_Attribute::setPrefix( void)
{
RCODE rc = NE_XFLM_OK;
// If this is a namespace declaration, there should be no prefix in the name.
if (m_bIsNamespaceDecl)
{
flmAssert( !m_uiPrefixChars);
}
// Only need to set a prefix on an attribute if it has a namespace
// Otherwise, leave it alone - no prefix.
else if (m_uiNamespaceChars)
{
// See if we can find a namespace declaration in either
// this element's attributes, or any of its parent element
// attributes.
if (RC_BAD( rc = m_pElement->findPrefix( m_puzNamespace,
m_uiNamespaceChars, FALSE,
&m_puzPrefix, &m_uiPrefixChars)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Export a unicode string to the string buffer - as UTF8.
*****************************************************************************/
FSTATIC RCODE exportUniValue(
IF_OStream * pOStream,
FLMUNICODE * puzStr,
FLMUINT uiStrChars,
FLMBOOL bEncodeSpecialChars,
FLMUINT uiIndentCount
)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucTmp [4];
FLMUINT uiLen;
FLMUINT uiCharOffset = 0;
FLMUNICODE uzChar;
FLMBOOL bIndent = FALSE;
FLMUINT uiICount = 0;
while ( *puzStr && uiCharOffset < uiStrChars)
{
uzChar = *puzStr;
// Handle encoding of special characters
if (bEncodeSpecialChars)
{
if (uzChar == '<')
{
if (RC_BAD( rc = pOStream->write( (void *)"&lt;", 4)))
{
goto Exit;
}
}
else if (uzChar == '>')
{
if (RC_BAD( rc = pOStream->write( (void *)"&gt;", 4)))
{
goto Exit;
}
}
else if (uzChar == '&')
{
if (RC_BAD( rc = pOStream->write( (void *)"&amp;", 5)))
{
goto Exit;
}
}
else if (uzChar == '\'')
{
if (RC_BAD( rc = pOStream->write( (void *)"&apos;", 6)))
{
goto Exit;
}
}
else if (uzChar == '"')
{
if (RC_BAD( rc = pOStream->write( (void *)"&quot;", 6)))
{
goto Exit;
}
}
else
{
goto Normal_Encoding;
}
}
else
{
Normal_Encoding:
// Output the character as UTF8.
if (uzChar <= 0x007F)
{
// New Line char found. Need to indent.
if( uzChar == ASCII_NEWLINE)
{
bIndent = TRUE;
}
ucTmp [0] = (FLMBYTE)uzChar;
uiLen = 1;
}
else if (*puzStr <= 0x07FF)
{
ucTmp [0] = (FLMBYTE)(0xC0 | (FLMBYTE)(uzChar >> 6));
ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F));
uiLen = 2;
}
else
{
ucTmp [0] = (FLMBYTE)(0xE0 | (FLMBYTE)(uzChar >> 12));
ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)((uzChar & 0x0FC0) >> 6));
ucTmp [2] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F));
uiLen = 3;
}
if (RC_BAD( rc = pOStream->write( (void *)&ucTmp[0], uiLen)))
{
goto Exit;
}
if( bIndent && uiIndentCount)
{
for( uiICount = uiIndentCount; uiICount; uiICount--)
{
if (RC_BAD( rc = pOStream->write( (void *)"\t", 1)))
{
goto Exit;
}
}
bIndent = FALSE;
}
}
puzStr++;
uiCharOffset++;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Output an attribute to the string buffer.
*****************************************************************************/
RCODE F_Attribute::outputAttr(
IF_OStream * pOStream)
{
RCODE rc = NE_XFLM_OK;
if (RC_BAD( rc = pOStream->write( (void *)" ", 1)))
{
goto Exit;
}
if (m_uiPrefixChars)
{
if (RC_BAD( rc = exportUniValue( pOStream, m_puzPrefix, m_uiPrefixChars, FALSE, 0)))
{
goto Exit;
}
if (RC_BAD( rc = pOStream->write( (void *)":", 1)))
{
goto Exit;
}
}
if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0)))
{
goto Exit;
}
if (RC_BAD( rc = pOStream->write( (void *)"=\"", 2)))
{
goto Exit;
}
if (RC_BAD( rc = exportUniValue( pOStream, m_puzValue, m_uiValueChars, TRUE, 0)))
{
goto Exit;
}
if (RC_BAD( rc = pOStream->write( (void *)"\"", 1)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Allocate a new attribute.
*****************************************************************************/
RCODE F_Element::allocAttr(
F_Attribute ** ppAttr
)
{
RCODE rc = NE_XFLM_OK;
if ((*ppAttr = *m_ppAvailAttrs) != NULL)
{
*m_ppAvailAttrs = (*ppAttr)->m_pNext;
(*ppAttr)->reset( this);
}
else
{
if ((*ppAttr = f_new F_Attribute( this)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Save an attribute in an element. Put at end of list.
*****************************************************************************/
RCODE F_Element::saveAttribute(
IF_Db * pDb,
IF_DOMNode * pNode
)
{
RCODE rc = NE_XFLM_OK;
F_Attribute * pAttr = NULL;
if (RC_BAD( rc = allocAttr( &pAttr)))
{
goto Exit;
}
// Set up the attribute
if (RC_BAD( rc = pAttr->setupAttribute( pDb, pNode)))
{
goto Exit;
}
// Put attribute at end of list of attributes.
pAttr->m_pNext = NULL;
if (m_pLastAttr)
{
m_pLastAttr->m_pNext = pAttr;
}
else
{
m_pFirstAttr = pAttr;
}
m_pLastAttr = pAttr;
// Set pAttr to NULL so it won't be made available at exit.
pAttr = NULL;
Exit:
if (pAttr)
{
makeAttrAvail( pAttr);
}
return( rc);
}
/*****************************************************************************
Desc: Allocate space for the element's name and namespace.
*****************************************************************************/
RCODE F_Element::allocNameSpace( void)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiSpaceNeeded;
FLMUNICODE * puzTmp;
uiSpaceNeeded = (m_uiNameChars + m_uiNamespaceChars + 2) * sizeof( FLMUNICODE);
// Allocate space for the name and namespace
if (uiSpaceNeeded > m_uiTmpSpaceSize)
{
if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp)))
{
goto Exit;
}
if (m_puzName != &m_uzTmpSpace [0])
{
f_free( &m_puzName);
}
m_puzName = puzTmp;
m_uiTmpSpaceSize = uiSpaceNeeded;
}
m_puzNamespace = &m_puzName [m_uiNameChars + 1];
Exit:
return( rc);
}
/*****************************************************************************
Desc: Setup an element with its namespace, etc.
*****************************************************************************/
RCODE F_Element::setupElement(
IF_Db * pDb,
IF_DOMNode * pNode
)
{
RCODE rc = NE_XFLM_OK;
IF_DOMNode * pAttrNode = NULL;
F_Attribute * pAttr;
// Get the length of the name of the element
if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL,
0, &m_uiNameChars)))
{
goto Exit;
}
// Get the number of characters in the namespace of the element
if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL,
0, &m_uiNamespaceChars)))
{
goto Exit;
}
if (RC_BAD( rc = allocNameSpace()))
{
goto Exit;
}
// Get the element name.
if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName,
(m_uiNameChars + 1) * sizeof( FLMUNICODE),
&m_uiNameChars)))
{
goto Exit;
}
// Get the namespace, if necessary
if (m_uiNamespaceChars)
{
if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace,
(m_uiNamespaceChars + 1) * sizeof( FLMUNICODE),
&m_uiNamespaceChars)))
{
goto Exit;
}
}
// See if the node has any attributes.
for (;;)
{
rc = (RCODE)(pAttrNode
? pAttrNode->getNextSibling( pDb, &pAttrNode)
: pNode->getFirstAttribute( pDb, &pAttrNode));
if (RC_BAD( rc))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
break;
}
else
{
goto Exit;
}
}
if (RC_BAD( rc = saveAttribute( pDb, pAttrNode)))
{
goto Exit;
}
}
// Get the prefix for the element
if (RC_BAD( rc = setPrefix()))
{
goto Exit;
}
// Set the prefix for every attribute
pAttr = m_pFirstAttr;
while (pAttr)
{
if (RC_BAD( rc = pAttr->setPrefix()))
{
goto Exit;
}
pAttr = pAttr->m_pNext;
}
Exit:
if (pAttrNode)
{
pAttrNode->Release();
}
return( rc);
}
/*****************************************************************************
Desc: Add an attribute that is a namespace to an element.
*****************************************************************************/
RCODE F_Element::addNamespaceDecl(
FLMUNICODE * puzPrefix,
FLMUINT uiPrefixChars,
FLMUNICODE * puzNamespace,
FLMUINT uiNamespaceChars,
F_Attribute ** ppAttr
)
{
RCODE rc = NE_XFLM_OK;
F_Attribute * pAttr = NULL;
// If uiPrefixChars is zero, we are being asked to create a default
// namespace. But that can only be output once in the element,
// so make sure it is not already declared. If it is, do nothing.
if (!uiPrefixChars)
{
pAttr = m_pFirstAttr;
while (pAttr && !pAttr->m_bDefaultNamespaceDecl)
{
pAttr = pAttr->m_pNext;
}
if (pAttr)
{
goto Exit;
}
}
if (RC_BAD( rc = allocAttr( &pAttr)))
{
goto Exit;
}
pAttr->m_bIsNamespaceDecl = TRUE;
// name will be "xmlns:<prefixname>" or, in the case of no namespace, "xmlns"
if (!uiPrefixChars)
{
// "xmlns" - but make sure not already declared.
pAttr->m_uiNameChars = 5;
pAttr->m_bDefaultNamespaceDecl = TRUE;
}
else
{
// "xmlns:<prefixname>"
pAttr->m_uiNameChars = uiPrefixChars + 6;
}
pAttr->m_uiNamespaceChars = 0;
pAttr->m_uiValueChars = uiNamespaceChars;
if (RC_BAD( rc = pAttr->allocNameSpace()))
{
goto Exit;
}
// Always output "xmlns" as the first part of the name
f_memcpy( pAttr->m_puzName, gv_puzNamespaceDeclPrefix, 5 * sizeof( FLMUNICODE));
if (uiPrefixChars)
{
pAttr->m_puzName [5] = ':';
f_memcpy( &pAttr->m_puzName [6], puzPrefix, uiPrefixChars * sizeof( FLMUNICODE));
pAttr->m_puzName [6 + uiPrefixChars] = 0;
}
else
{
pAttr->m_puzName [5] = 0;
}
if (uiNamespaceChars)
{
f_memcpy( pAttr->m_puzValue, puzNamespace,
uiNamespaceChars * sizeof( FLMUNICODE));
}
pAttr->m_puzValue [pAttr->m_uiValueChars] = 0;
// Put new namespace decl at front of list of attributes.
if ((pAttr->m_pNext = m_pFirstAttr) == NULL)
{
m_pLastAttr = pAttr;
}
m_pFirstAttr = pAttr;
*ppAttr = pAttr;
// Set pAttr to NULL so that it won't be made available at exit.
pAttr = NULL;
Exit:
if (pAttr)
{
makeAttrAvail( pAttr);
}
return( rc);
}
/*****************************************************************************
Desc: Generate a random prefix, ensure that it is not defined anywhere
in the path.
*****************************************************************************/
void F_Element::genPrefix(
FLMUNICODE * puzPrefix,
FLMUINT * puiPrefixChars
)
{
FLMUINT uiTmp;
FLMUINT uiPrefixChars;
FLMUNICODE * puzTmp;
F_Attribute * pAttr;
F_Element * pElement;
puzPrefix [0] = 'p';
puzPrefix [1] = 'r';
puzPrefix [2] = 'f';
puzPrefix [3] = 'x';
for (;;)
{
// Append the number in reverse digit order - it really doesn't matter
// because we're just trying to generate a unique prefix number.
puzTmp = &puzPrefix [4];
uiPrefixChars = 4;
uiTmp = *m_puiNextPrefixNum;
do
{
*puzTmp++ = (FLMUNICODE)((uiTmp % 10) + '0');
uiPrefixChars++;
uiTmp /= 10;
} while (uiTmp);
// See if the prefix is defined.
pAttr = m_pFirstAttr;
pElement = this;
while (pAttr)
{
if (pAttr->m_bIsNamespaceDecl &&
pAttr->m_uiNameChars > 6 &&
pAttr->m_uiNameChars - 6 == uiPrefixChars &&
f_memcmp( puzPrefix, &pAttr->m_puzName [6],
uiPrefixChars * sizeof( FLMUNICODE)) == 0)
{
break;
}
if ((pAttr = pAttr->m_pNext) == NULL)
{
pElement = pElement->m_pParentElement;
while (pElement && !pElement->m_pFirstAttr)
{
pElement = pElement->m_pParentElement;
}
if (!pElement)
{
break;
}
pAttr = pElement->m_pFirstAttr;
}
}
// If the prefix was not defined, we can use it.
if (!pAttr)
{
break;
}
(*m_puiNextPrefixNum)++;
}
puzPrefix [uiPrefixChars] = 0;
*puiPrefixChars = uiPrefixChars;
}
/*****************************************************************************
Desc: Find a prefix for a namespace
*****************************************************************************/
RCODE F_Element::findPrefix(
FLMUNICODE * puzNamespace,
FLMUINT uiNamespaceChars,
FLMBOOL bForElement,
FLMUNICODE ** ppuzPrefix,
FLMUINT * puiPrefixChars)
{
RCODE rc = NE_XFLM_OK;
F_Attribute * pAttr = m_pFirstAttr;
F_Element * pElement = this;
FLMUNICODE uzPrefix [50];
FLMUINT uiPrefixChars;
for (;;)
{
if ( pAttr)
{
if (pAttr->m_bIsNamespaceDecl &&
uiNamespaceChars == pAttr->m_uiValueChars &&
(!uiNamespaceChars ||
f_memcmp( puzNamespace, pAttr->m_puzValue,
uiNamespaceChars * sizeof( FLMUNICODE)) == 0))
{
// Don't set the prefix if it is the default namespace.
if (!pAttr->m_bDefaultNamespaceDecl)
{
// Prefix comes after the "xmlns:"
*ppuzPrefix = &pAttr->m_puzName [6];
*puiPrefixChars = pAttr->m_uiNameChars - 6;
goto Exit;
}
// Default namespace is only OK for elements,
// but not attributes. We don't want to count
// attributes as having been "found" if they matched
// the default namespace. This routine is only called
// for attributes if the attribute namepace is non-empty.
else if (bForElement)
{
goto Exit;
}
}
pAttr = pAttr->m_pNext;
}
if ( !pAttr)
{
pElement = pElement->m_pParentElement;
while (pElement && !pElement->m_pFirstAttr)
{
pElement = pElement->m_pParentElement;
}
if (!pElement)
{
break;
}
pAttr = pElement->m_pFirstAttr;
}
}
// If namespaces is empty, the only declaration that is legal is
// a default namespace declaration.
if (!uiNamespaceChars)
{
if (RC_BAD( rc = addNamespaceDecl( NULL, 0, NULL, 0, &pAttr)))
{
goto Exit;
}
}
else
{
// Manufacture a prefix that is not used in the hierarchy yet.
genPrefix( uzPrefix, &uiPrefixChars);
if (RC_BAD( rc = addNamespaceDecl( uzPrefix, uiPrefixChars, puzNamespace,
uiNamespaceChars, &pAttr)))
{
goto Exit;
}
*ppuzPrefix = &pAttr->m_puzName [6];
*puiPrefixChars = pAttr->m_uiNameChars - 6;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Output the element name, with its attributes - this marks the
beginning of the element.
*****************************************************************************/
RCODE F_Element::outputElem(
IF_OStream * pOStream,
FLMBOOL bStartOfElement,
FLMBOOL bEndOfElement,
FLMBOOL bAddNewLine)
{
RCODE rc = NE_XFLM_OK;
F_Attribute * pAttr;
F_Attribute * pPrevAttr;
FLMUINT uiIndentCount = 0;
FLMBOOL bEndNode;
bEndNode = ( m_bIsDocumentRoot && !bStartOfElement);
if( bAddNewLine && ( !m_bIsDocumentRoot || bEndNode))
{
if (RC_BAD( rc = pOStream->write( (void *)"\n", 1)))
{
goto Exit;
}
for( uiIndentCount = 0; uiIndentCount < m_uiIndentCount; uiIndentCount++)
{
if (RC_BAD( rc = pOStream->write( (void *)"\t", 1)))
{
goto Exit;
}
}
}
// Output the element name
if ( bStartOfElement)
{
if (RC_BAD( rc = pOStream->write( (void *)"<", 1)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = pOStream->write( (void *)"</", 2)))
{
goto Exit;
}
}
if (m_uiPrefixChars)
{
if (RC_BAD( rc = exportUniValue( pOStream, m_puzPrefix, m_uiPrefixChars, FALSE, 0)))
{
goto Exit;
}
if (RC_BAD( rc = pOStream->write( (void *)":", 1)))
{
goto Exit;
}
}
if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0)))
{
goto Exit;
}
if (bStartOfElement)
{
// Output the attributes. As we go, remove any attributes that are
// not namespace declarations. They are not needed after this.
pPrevAttr = NULL;
pAttr = m_pFirstAttr;
while (pAttr)
{
if (RC_BAD( rc = pAttr->outputAttr( pOStream)))
{
goto Exit;
}
if (!pAttr->m_bIsNamespaceDecl)
{
if (pPrevAttr)
{
pPrevAttr->m_pNext = pAttr->m_pNext;
makeAttrAvail( pAttr);
pAttr = pPrevAttr->m_pNext;
}
else
{
m_pFirstAttr = pAttr->m_pNext;
makeAttrAvail( pAttr);
pAttr = m_pFirstAttr;
}
// See if we deleted the last attribute in the list.
if (!pAttr)
{
m_pLastAttr = pPrevAttr;
}
}
else
{
pPrevAttr = pAttr;
pAttr = pAttr->m_pNext;
}
}
}
// Close out the element
if (RC_BAD( rc = (RCODE)(bStartOfElement && bEndOfElement
? pOStream->write( (void *)"/>", 2)
: pOStream->write( (void *)">", 1))))
{
goto Exit;
}
if ( bAddNewLine && bEndNode)
{
if (RC_BAD( rc = pOStream->write( (void *)"\n", 1)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Output Data that is contained on an element node.
*****************************************************************************/
RCODE F_Element::outputLocalData(
IF_OStream * pOStream,
IF_DOMNode * pDbNode,
IF_Db * ifpDb,
eExportFormatType eFormatType,
FLMUINT uiIndentCount)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uzTmpData [150];
FLMUNICODE * puzData = &uzTmpData [0];
FLMUINT uiDataBufSize = sizeof( uzTmpData);
FLMUINT uiChars;
if (RC_BAD( rc = pDbNode->getUnicodeChars( ifpDb, &uiChars)))
{
goto Exit;
}
if (uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE))
{
FLMUNICODE * puzNew;
if (RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE),
&puzNew)))
{
goto Exit;
}
if (puzData != &uzTmpData [0])
{
f_free( &puzData);
}
puzData = puzNew;
uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE);
}
if (RC_BAD( rc = pDbNode->getUnicode( ifpDb, puzData,
uiDataBufSize, 0, uiChars, &uiChars)))
{
goto Exit;
}
// Output the value.
if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars, TRUE,
eFormatType >= XFLM_EXPORT_INDENT_DATA ? uiIndentCount : 0)))
{
goto Exit;
}
Exit:
return ( rc);
}
/*****************************************************************************
Desc: Outputs a UTF8 stream of XML, starting at the specified node. Node and
all of its descendant nodes are output.
*****************************************************************************/
RCODE FLMAPI F_Db::exportXML(
IF_DOMNode * pStartNode,
IF_OStream * pOStream,
eExportFormatType eFormatType)
{
RCODE rc = NE_XFLM_OK;
F_Element * pAvailElements = NULL;
F_Element * pTmpElement;
F_Attribute * pAvailAttrs = NULL;
F_Attribute * pTmpAttr;
FLMUNICODE uzTmpData [150];
FLMUNICODE * puzData = &uzTmpData [0];
FLMUINT uiDataBufSize = sizeof( uzTmpData);
IF_DOMNode * pDbNode = NULL;
eDomNodeType ePrevNodeType;
F_Element * pCurrElement = NULL;
FLMUINT uiNextPrefixNum = 0;
FLMBOOL bStartOfDocument = TRUE;
FLMBOOL bShouldFormat = FALSE;
FLMBOOL bIsDataLocal = FALSE;
FLMUINT uiIndentCount = 0;
FLMUINT uiICount = 0;
// This routine should only be called if the node type is element node.
flmAssert( pStartNode->getNodeType() == ELEMENT_NODE);
ePrevNodeType = ELEMENT_NODE;
pDbNode = pStartNode;
pDbNode->AddRef();
for (;;)
{
// Output the current node, depending on its type.
if( pDbNode->getNodeType() == ELEMENT_NODE)
{
if (pAvailElements)
{
pTmpElement = pAvailElements;
pAvailElements = pAvailElements->getNext();
pTmpElement->reset( pCurrElement, &pAvailAttrs, &uiNextPrefixNum);
}
else
{
if ((pTmpElement = f_new F_Element( pCurrElement, &pAvailAttrs,
&uiNextPrefixNum)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
pCurrElement = pTmpElement;
if (RC_BAD( rc = pCurrElement->setupElement( (IF_Db *)this, pDbNode)))
{
goto Exit;
}
if( eFormatType >= XFLM_EXPORT_INDENT)
{
pCurrElement->setIndentCount(uiIndentCount);
}
if( pDbNode == pStartNode)
{
pCurrElement->setDocumentRoot( TRUE);
}
// Only want a New Line and tabs for Element if:
// 1) New Line format is indicated
// 2) Previous Element Was NOT Data
bShouldFormat = ( (eFormatType >= XFLM_EXPORT_NEW_LINE) &&
(ePrevNodeType != DATA_NODE))
? TRUE
: FALSE;
if( RC_BAD( rc = pDbNode->isDataLocalToNode( (IF_Db *)this,
&bIsDataLocal)))
{
goto Exit;
}
if( bIsDataLocal)
{
if( RC_BAD( rc = pCurrElement->outputElem( pOStream,
TRUE, FALSE, bShouldFormat)))
{
goto Exit;
}
pCurrElement->outputLocalData( pOStream,
pDbNode,
(IF_Db *)this,
eFormatType,
uiIndentCount);
}
if( RC_OK( rc = pDbNode->getFirstChild( (IF_Db *)this, &pDbNode)))
{
if( !bIsDataLocal && RC_BAD( rc = pCurrElement->outputElem(
pOStream, TRUE, FALSE, bShouldFormat)))
{
goto Exit;
}
bStartOfDocument = FALSE;
uiIndentCount++;
ePrevNodeType = ELEMENT_NODE;
continue;
}
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
// Write out the "/>" for the element, because it had no
// child nodes.
if( bIsDataLocal)
{
if( RC_BAD( rc = pCurrElement->outputElem( pOStream,
FALSE, TRUE, bShouldFormat)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pCurrElement->outputElem( pOStream,
TRUE, TRUE, bShouldFormat)))
{
goto Exit;
}
}
// We are now done with this element
ePrevNodeType = ELEMENT_NODE;
pTmpElement = pCurrElement;
pCurrElement = pCurrElement->getParentElement();
pTmpElement->makeAvail( &pAvailElements);
if( !pCurrElement)
{
break;
}
Get_Element_Sibling:
// See if we have a sibling. Go up tree until we find
// a node that has a sibling.
for( ;;)
{
if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode)))
{
break;
}
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
// Need to close previous element
if( uiIndentCount)
{
uiIndentCount--;
}
if( RC_BAD( rc = pCurrElement->outputElem( pOStream, FALSE, TRUE,
eFormatType >= XFLM_EXPORT_NEW_LINE
? TRUE
: FALSE)))
{
goto Exit;
}
if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// There should be a parent node at this point!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
pTmpElement = pCurrElement;
pCurrElement = pCurrElement->getParentElement();
pTmpElement->makeAvail( &pAvailElements);
if( !pCurrElement)
{
pDbNode->Release();
pDbNode = NULL;
goto Exit;
}
}
}
else
{
// Only output data, comment, and cdata nodes.
if( pDbNode->getNodeType() == DATA_NODE ||
pDbNode->getNodeType() == COMMENT_NODE ||
pDbNode->getNodeType() == CDATA_SECTION_NODE)
{
FLMUINT uiChars;
if( RC_BAD( rc = pDbNode->getUnicodeChars( (IF_Db *)this,
&uiChars)))
{
goto Exit;
}
if( uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE))
{
FLMUNICODE * puzNew;
if( RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE),
&puzNew)))
{
goto Exit;
}
if( puzData != &uzTmpData [0])
{
f_free( &puzData);
}
puzData = puzNew;
uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE);
}
if( RC_BAD( rc = pDbNode->getUnicode( (IF_Db *)this, puzData,
uiDataBufSize, 0, uiChars, &uiChars)))
{
goto Exit;
}
if( pDbNode->getNodeType() == DATA_NODE)
{
// Output the value
if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars,
TRUE, eFormatType >= XFLM_EXPORT_INDENT_DATA
? uiIndentCount
: 0)))
{
goto Exit;
}
ePrevNodeType = DATA_NODE;
}
else if( pDbNode->getNodeType() == COMMENT_NODE)
{
//If Comment Node follows Data Node do not add new line
if( eFormatType >= XFLM_EXPORT_INDENT_DATA &&
ePrevNodeType != DATA_NODE)
{
if (RC_BAD( rc = pOStream->write( (void *)"\n", 1)))
{
goto Exit;
}
for( uiICount = 0; uiICount < uiIndentCount; uiICount++)
{
if (RC_BAD( rc = pOStream->write( (void *)"\t", 1)))
{
goto Exit;
}
}
}
// Output the beginning of a comment
if (RC_BAD( rc = pOStream->write( (void *)"<!--", 4)))
{
goto Exit;
}
// Output the comment value - as is, no encoding
if( RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars,
FALSE, eFormatType >= XFLM_EXPORT_INDENT_DATA
? uiIndentCount
: 0)))
{
goto Exit;
}
// Output the end of the comment
if( RC_BAD( rc = pOStream->write( (void *)"-->", 3)))
{
goto Exit;
}
ePrevNodeType = COMMENT_NODE;
}
else
{
// Output the beginning of a cdata section
if( RC_BAD( rc = pOStream->write( (void *)"<![CDATA[", 9)))
{
goto Exit;
}
// Output the cdata value - as is, no encoding
if( RC_BAD( rc = exportUniValue( pOStream, puzData,
uiChars, FALSE, 0)))
{
goto Exit;
}
// Output the end of the cdata section
if( RC_BAD( rc = pOStream->write( (void *)"]]>", 3)))
{
goto Exit;
}
ePrevNodeType = CDATA_SECTION_NODE;
}
}
// Have a data node, or comment node probably
// In any case, see if there are any sibling nodes.
// If not, go back to enclosing element node.
if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode)))
{
continue;
}
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
// Go back up to enclosing element
if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode)))
{
// There better be a parent node or we have a corruption!
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
// Parent node better be an element
if( pDbNode->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// If we were traversing the attributes of an element,
// we need to now go back and get its child nodes.
// Write out the </elementname> for the element
if( RC_BAD( rc = pCurrElement->outputElem( pOStream,
FALSE, TRUE, FALSE)))
{
goto Exit;
}
// We are now done with this element
if( uiIndentCount)
{
uiIndentCount--;
}
ePrevNodeType = ELEMENT_NODE;
pTmpElement = pCurrElement;
pCurrElement = pCurrElement->getParentElement();
pTmpElement->makeAvail( &pAvailElements);
if( !pCurrElement)
{
break;
}
goto Get_Element_Sibling;
}
}
Exit:
if( puzData != &uzTmpData [0])
{
f_free( &puzData);
}
while( pCurrElement)
{
pTmpElement = pCurrElement;
pCurrElement = pCurrElement->getParentElement();
delete pTmpElement;
}
while( pAvailElements)
{
pTmpElement = pAvailElements;
pAvailElements = pAvailElements->getNext();
delete pTmpElement;
}
while( pAvailAttrs)
{
pTmpAttr = pAvailAttrs;
pAvailAttrs = pAvailAttrs->getNext();
delete pTmpAttr;
}
if( pDbNode)
{
pDbNode->Release();
}
return( rc);
}