//------------------------------------------------------------------------------ // 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( "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 // "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 "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 "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( "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 "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 "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 "(#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( "")) { 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 "")) { 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:" 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:" 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 *)"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 *)"", 3))) { goto Exit; } ePrevNodeType = COMMENT_NODE; } else { // Output the beginning of a cdata section if( RC_BAD( rc = pOStream->write( (void *)"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 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); }