git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@409 0109f412-320b-0410-ab79-c3e0c5ffbbe6
6497 lines
126 KiB
C++
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 *)"<", 4)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (uzChar == '>')
|
|
{
|
|
if (RC_BAD( rc = pOStream->write( (void *)">", 4)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (uzChar == '&')
|
|
{
|
|
if (RC_BAD( rc = pOStream->write( (void *)"&", 5)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (uzChar == '\'')
|
|
{
|
|
if (RC_BAD( rc = pOStream->write( (void *)"'", 6)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (uzChar == '"')
|
|
{
|
|
if (RC_BAD( rc = pOStream->write( (void *)""", 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);
|
|
}
|