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

17993 lines
337 KiB
C++

//------------------------------------------------------------------------------
// Desc: DOM node implementation
//
// Tabs: 3
//
// Copyright (c) 2003-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: fdom.cpp 3112 2006-01-19 13:12:40 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
// Local constants
#define SEN_RESERVE_BYTES 5
/****************************************************************************
Desc:
****************************************************************************/
FINLINE RCODE F_Db::attrIsInIndexDef(
FLMUINT uiAttrNameId,
FLMBOOL * pbIsInIndexDef)
{
RCODE rc = NE_XFLM_OK;
F_AttrElmInfo defInfo;
if( RC_BAD( rc = m_pDict->getAttribute( this, uiAttrNameId, &defInfo)))
{
return( rc);
}
*pbIsInIndexDef = defInfo.m_pFirstIcd ? TRUE : FALSE;
return( NE_XFLM_OK);
}
/*****************************************************************************
Desc: This class converts a text stream of Unicode or UTF8 to an ASCII
text stream.
******************************************************************************/
class F_AsciiIStream : public IF_IStream
{
public:
F_AsciiIStream(
FLMBYTE * pucText,
FLMUINT uiNumBytesInBuffer,
eXFlmTextType eTextType)
{
m_pucText = pucText;
m_pucCurrPtr = pucText;
m_uiCurrChar = 0;
m_eTextType = eTextType;
if( uiNumBytesInBuffer)
{
m_pucEnd = &pucText[ uiNumBytesInBuffer];
}
else
{
m_pucEnd = NULL;
}
}
virtual ~F_AsciiIStream()
{
}
RCODE FLMAPI read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead);
FINLINE RCODE FLMAPI close( void)
{
return( NE_XFLM_OK);
}
private:
const FLMBYTE * m_pucText;
const FLMBYTE * m_pucCurrPtr;
const FLMBYTE * m_pucEnd;
FLMUINT m_uiCurrChar;
eXFlmTextType m_eTextType;
};
/*****************************************************************************
Desc:
******************************************************************************/
FLMINT FLMAPI F_BTreeIStream::Release( void)
{
FLMATOMIC refCnt = --m_refCnt;
if (m_refCnt == 0)
{
close();
if( gv_XFlmSysData.pNodePool)
{
m_refCnt = 1;
gv_XFlmSysData.pNodePool->insertBTreeIStream( this);
return( 0);
}
else
{
delete this;
}
}
return( refCnt);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::canSetValue(
F_Db * pDb,
FLMUINT uiDataType)
{
RCODE rc = NE_XFLM_OK;
F_Database * pDatabase = pDb->m_pDatabase;
IF_DOMNode * pNode = NULL;
eDomNodeType eNodeType = getNodeType();
if( eNodeType < ELEMENT_NODE || eNodeType > ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// Cannot set a value without a data type
if( uiDataType == XFLM_NODATA_TYPE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
goto Exit;
}
// If the node is read-only, don't allow it to be changed
if( getModeFlags() & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
// If this is a comment or CDATA node, only allow text values
if (uiDataType != XFLM_TEXT_TYPE &&
(eNodeType == COMMENT_NODE || eNodeType == CDATA_SECTION_NODE))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// If the node is a data node and it has already been linked
// into the document, its data type cannot be changed.
if( getParentId() && eNodeType == DATA_NODE && uiDataType != getDataType())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Cannot allow a value to be set on this node if a pending input stream
// is still open.
if( pDatabase->m_pPendingInput &&
pDatabase->m_pPendingInput != m_pCachedNode)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
goto Exit;
}
Exit:
if( pNode)
{
pNode->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI F_DOMNode::Release( void)
{
FLMINT iRefCnt = --m_refCnt;
if (iRefCnt == 0)
{
if( gv_XFlmSysData.pNodeCacheMgr)
{
m_refCnt = 1;
gv_XFlmSysData.pNodeCacheMgr->insertDOMNode( this);
return( 0);
}
else
{
delete this;
}
}
return( iRefCnt);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::isChildTypeValid(
eDomNodeType eChildNodeType)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bTypeValid = FALSE;
if( !m_pCachedNode)
{
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
goto Exit;
}
switch( getNodeType())
{
case ELEMENT_NODE:
{
if (eChildNodeType == ELEMENT_NODE ||
(eChildNodeType == DATA_NODE &&
getDataType() != XFLM_NODATA_TYPE && getDataLength() == 0) ||
eChildNodeType == COMMENT_NODE ||
eChildNodeType == PROCESSING_INSTRUCTION_NODE ||
eChildNodeType == CDATA_SECTION_NODE)
{
bTypeValid = TRUE;
}
break;
}
case DOCUMENT_NODE:
{
if (eChildNodeType == ELEMENT_NODE ||
eChildNodeType == PROCESSING_INSTRUCTION_NODE ||
eChildNodeType == COMMENT_NODE)
{
bTypeValid = TRUE;
}
break;
}
case ATTRIBUTE_NODE:
case DATA_NODE:
case CDATA_SECTION_NODE:
case PROCESSING_INSTRUCTION_NODE:
case COMMENT_NODE:
{
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
if (!bTypeValid)
{
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::isDescendantOf(
F_Db * pDb,
F_DOMNode * pAncestor,
FLMBOOL * pbDescendant)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pParent = NULL;
FLMUINT64 ui64AncestorId;
FLMUINT64 ui64ThisParentId;
*pbDescendant = FALSE;
if( !m_pCachedNode)
{
goto Exit;
}
ui64AncestorId = pAncestor->getNodeId();
ui64ThisParentId = getParentId();
if( ui64ThisParentId == ui64AncestorId)
{
*pbDescendant = TRUE;
goto Exit;
}
if( !ui64ThisParentId ||
(ui64AncestorId != ui64ThisParentId &&
ui64ThisParentId == getDocumentId()) || !pAncestor->getFirstChildId())
{
goto Exit;
}
if( RC_BAD( rc = getParentNode( pDb, (IF_DOMNode **)&pParent)))
{
goto Exit;
}
while( pParent)
{
if( pParent->getNodeId() == ui64AncestorId)
{
*pbDescendant = TRUE;
goto Exit;
}
if( RC_BAD( rc = pParent->getParentNode( pDb, (IF_DOMNode **)&pParent)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
}
Exit:
if( pParent)
{
pParent->Release();
}
return( rc);
}
/*****************************************************************************
Notes: When an node is unlinked, its document or root node ID is not
changed. Once unlinked, the node can be deleted or re-linked
elsewhere within the same document.
This routine assumes that the caller has checked the cannot delete
bits and read-only bits if necessary.
******************************************************************************/
RCODE F_DOMNode::unlinkNode(
F_Db * pDb,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pTmpNode = NULL;
F_COLLECTION * pCollection = NULL;
FLMUINT64 ui64OldPrevSib = 0;
FLMUINT64 ui64OldNextSib = 0;
FLMBOOL bChangedThisHeader = FALSE;
eDomNodeType eNodeType;
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Unlink the node from its siblings and parent
if( (ui64OldPrevSib = getPrevSibId()) != 0)
{
if( RC_BAD( rc = pDb->getNode( getCollection(), getPrevSibId(),
&pTmpNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setNextSibId( getNextSibId());
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
{
goto Exit;
}
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
setPrevSibId( 0);
bChangedThisHeader = TRUE;
}
if( (ui64OldNextSib = getNextSibId()) != 0)
{
if( RC_BAD( rc = pDb->getNode( getCollection(), getNextSibId(),
&pTmpNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setPrevSibId( ui64OldPrevSib);
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
{
goto Exit;
}
if( !bChangedThisHeader)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
}
setNextSibId( 0);
bChangedThisHeader = TRUE;
}
if( getParentId())
{
FLMBOOL bChangedTmpHeader = FALSE;
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
&pTmpNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND ||
rc == NE_XFLM_DOM_NODE_DELETED)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if( eNodeType == ANNOTATION_NODE)
{
if (!bChangedTmpHeader)
{
if (RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
bChangedTmpHeader = TRUE;
}
pTmpNode->setAnnotationId( 0);
}
else
{
// If the parent node is one whose child elements must all
// be unique, we must remove the node from the node list of the
// parent.
if( pTmpNode->getModeFlags() & FDOM_HAVE_CELM_LIST)
{
FLMUINT uiElmOffset;
if( !bChangedTmpHeader)
{
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
bChangedTmpHeader = TRUE;
}
// Only element nodes should be child nodes of this parent.
flmAssert( eNodeType == ELEMENT_NODE);
if( !pTmpNode->findChildElm( getNameId(), &uiElmOffset))
{
// Child node should have been found.
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( RC_BAD( rc = pTmpNode->removeChildElm( uiElmOffset)))
{
goto Exit;
}
}
// If this is a data node, we need to update the parent element's
// data node count
if( eNodeType == DATA_NODE)
{
if( !bChangedTmpHeader)
{
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
bChangedTmpHeader = TRUE;
}
flmAssert( pTmpNode->getDataChildCount());
pTmpNode->setDataChildCount( pTmpNode->getDataChildCount() - 1);
}
if( !ui64OldPrevSib)
{
if( !bChangedTmpHeader)
{
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
bChangedTmpHeader = TRUE;
}
flmAssert( pTmpNode->canHaveChildren());
pTmpNode->setFirstChildId( ui64OldNextSib);
}
if( !ui64OldNextSib)
{
if( !bChangedTmpHeader)
{
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
bChangedTmpHeader = TRUE;
}
flmAssert( pTmpNode->canHaveChildren());
pTmpNode->setLastChildId( ui64OldPrevSib);
}
}
if( bChangedTmpHeader)
{
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
{
goto Exit;
}
}
if( !bChangedThisHeader)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
}
setParentId( 0);
bChangedThisHeader = TRUE;
}
// If this is a root node, the document list pointers may need
// to be updated
if( isRootNode())
{
if( eNodeType != DOCUMENT_NODE && eNodeType != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Get a pointer to the collection
if( RC_BAD( rc = pDb->m_pDict->getCollection(
getCollection(), &pCollection)))
{
goto Exit;
}
if( pCollection->ui64FirstDocId == getNodeId() ||
pCollection->ui64LastDocId == getNodeId())
{
// Clone the dictionary since the first/last document ID
// values of the collection will be changed
if( !(pDb->m_uiFlags & FDB_UPDATED_DICTIONARY))
{
if( RC_BAD( rc = pDb->dictClone()))
{
goto Exit;
}
}
// Get a pointer to the new collection
if( RC_BAD( rc = pDb->m_pDict->getCollection(
getCollection(), &pCollection)))
{
goto Exit;
}
// Change the first and/or last document IDs
if( pCollection->ui64FirstDocId == getNodeId())
{
pCollection->ui64FirstDocId = ui64OldNextSib;
pCollection->bNeedToUpdateNodes = TRUE;
}
if( pCollection->ui64LastDocId == getNodeId())
{
pCollection->ui64LastDocId = ui64OldPrevSib;
pCollection->bNeedToUpdateNodes = TRUE;
}
}
}
// If this is a data node, clear its name tag
if( eNodeType == DATA_NODE)
{
if( !bChangedThisHeader)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
}
setNameId( 0);
bChangedThisHeader = TRUE;
}
if( bChangedThisHeader)
{
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, uiFlags)))
{
goto Exit;
}
}
Exit:
if( pTmpNode)
{
pTmpNode->Release();
}
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::addModeFlags(
F_Db * pDb,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Only need to set flags if they are not all currently set.
if( (getModeFlags() & uiFlags) != uiFlags)
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->addModeFlags(
pDb, m_uiAttrNameId, uiFlags)))
{
goto Exit;
}
}
else
{
m_pCachedNode->setFlags( uiFlags);
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( pRfl->logNodeFlagsUpdate(
pDb, getCollection(), m_pCachedNode->getNodeId(),
m_uiAttrNameId, uiFlags, TRUE)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::removeModeFlags(
F_Db * pDb,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Only need to remove the flags if any of them are currently set.
if( getModeFlags() & uiFlags)
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->removeModeFlags(
pDb, m_uiAttrNameId, uiFlags)))
{
goto Exit;
}
}
else
{
m_pCachedNode->unsetFlags( uiFlags);
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( pRfl->logNodeFlagsUpdate(
pDb, getCollection(), m_pCachedNode->getNodeId(),
m_uiAttrNameId, uiFlags, FALSE)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getData(
F_Db * pDb,
FLMBYTE * pucBuffer,
FLMUINT * puiLength)
{
RCODE rc = NE_XFLM_OK;
IF_PosIStream * pIStream = NULL;
FLMBOOL bStartedTrans = FALSE;
F_NodeBufferIStream bufferIStream;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// If a NULL buffer is passed in, just return the
// data length
if( !pucBuffer)
{
rc = getDataLength( pDb, puiLength);
goto Exit;
}
if( RC_BAD( rc = getIStream( pDb, &bufferIStream, &pIStream)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsBinary( pIStream, pucBuffer,
*puiLength, 0, puiLength)))
{
goto Exit;
}
Exit:
if( pIStream)
{
pIStream->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getDataLength(
IF_Db * ifpDb,
FLMUINT * puiLength)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
eDomNodeType eNodeType;
F_Db * pDb = (F_Db *)ifpDb;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getDataLength(
m_uiAttrNameId, puiLength)))
{
goto Exit;
}
}
else if( (*puiLength = getDataLength()) == 0)
{
// If this is an element node, we will automatically search
// for the first data node (if any)
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
F_DOMNode * pNode = NULL;
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
*puiLength = pNode->getDataLength();
pNode->Release();
}
}
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::insertBefore(
IF_Db * ifpDb,
IF_DOMNode * ifpNewChild,
IF_DOMNode * ifpRefChild)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pFirstNewChild = NULL;
F_DOMNode * pLastNewChild = NULL;
F_DOMNode * pCurNewNode = NULL;
F_DOMNode * pNextSib = NULL;
F_DOMNode * pInsertBefore = NULL;
F_DOMNode * pTmpNode = NULL;
FLMBOOL bDescendant;
FLMBOOL bDone = FALSE;
FLMUINT64 ui64Tmp;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartOfUpdate;
F_DOMNode * pDataElementNode = NULL;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
F_DOMNode * pNewChild = (F_DOMNode *)ifpNewChild;
F_DOMNode * pRefChild = (F_DOMNode *)ifpRefChild;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bUpdatedNode = FALSE;
FLMUINT uiRflToken = 0;
FLMUINT64 ui64RefChildId = 0;
eDomNodeType eThisNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eThisNodeType = getNodeType();
if( eThisNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
if( !pNewChild)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = pNewChild->syncFromDb( pDb)))
{
goto Exit;
}
if( pRefChild)
{
if( RC_BAD( rc = pRefChild->syncFromDb( pDb)))
{
goto Exit;
}
if( pRefChild->getNodeType() == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
ui64RefChildId = pRefChild->getNodeId();
}
if( pNewChild->getDatabase() != getDatabase() ||
pNewChild->getCollection() != getCollection())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( pNewChild->getNodeType() == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// If this is a node whose children are all supposed to be unique,
// make sure that is the case, and find out where to insert the node.
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
{
FLMUINT uiInsertPos;
// Only element child nodes are allowed.
if( pNewChild->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
goto Exit;
}
// All of the element names must be unique.
if( m_pCachedNode->findChildElm( pNewChild->getNameId(),
&uiInsertPos))
{
rc = RC_SET( NE_XFLM_DOM_DUPLICATE_ELEMENT);
goto Exit;
}
// Element was not found, insert into the list of elements.
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bUpdatedNode = TRUE;
if( RC_BAD( rc = m_pCachedNode->insertChildElm( uiInsertPos,
pNewChild->getNameId(),
pNewChild->getNodeId())))
{
goto Exit;
}
}
// If a non-NULL reference child was passed in,
// do some basic sanity checks
if( pRefChild)
{
if( pRefChild->getDatabase() != getDatabase() ||
pRefChild->getCollection() != getCollection())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( pNewChild->getNodeId() == pRefChild->getNodeId())
{
rc = RC_SET( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
if( pRefChild->getParentId() != getNodeId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
}
pFirstNewChild = pNewChild;
pFirstNewChild->AddRef();
pLastNewChild = pNewChild;
pLastNewChild->AddRef();
if( pRefChild)
{
pInsertBefore = pRefChild;
pInsertBefore->AddRef();
}
pCurNewNode = pFirstNewChild;
pCurNewNode->AddRef();
bStartOfUpdate = TRUE;
for( ;;)
{
// Make sure it is legal for the new child node to be
// linked to this node
if( RC_BAD( rc = isChildTypeValid( pCurNewNode->getNodeType())))
{
goto Exit;
}
// If the node being inserted is not from the same document,
// we cannot perform the operation
if( pCurNewNode->getDocumentId() != getDocumentId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_WRONG_DOCUMENT_ERR);
goto Exit;
}
// A document node can only have one element node and one document type
// node.
if( eThisNodeType == DOCUMENT_NODE)
{
if( pCurNewNode->getNodeType() == ELEMENT_NODE &&
getFirstChildId())
{
if( RC_BAD( rc = getChild( ifpDb, ELEMENT_NODE,
(IF_DOMNode **)&pTmpNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
}
}
// Get the next sibling node (if any) before we
// change the tree
if( pNextSib)
{
pNextSib->Release();
pNextSib = NULL;
}
if( RC_BAD( rc = pCurNewNode->getNextSibling( pDb,
(IF_DOMNode **)&pNextSib)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
bDone = TRUE;
}
else
{
goto Exit;
}
}
bMustAbortOnError = TRUE;
if( pDataElementNode)
{
pDataElementNode->Release();
pDataElementNode = NULL;
}
// Do indexing work before making changes
if( pCurNewNode->getNameId())
{
if( pCurNewNode->getNodeType() == DATA_NODE)
{
if( pCurNewNode->getParentId())
{
if( RC_BAD( rc = pCurNewNode->getParentNode( pDb,
(IF_DOMNode **)&pDataElementNode)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), pDataElementNode,
IX_DEL_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
if( !getFirstChildId())
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
}
else
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), pCurNewNode, IX_UNLINK_NODE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
}
// Remove pCurNewNode from the tree
if( pCurNewNode->getModeFlags() & (FDOM_CANNOT_DELETE | FDOM_READ_ONLY))
{
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
goto Exit;
}
if( RC_BAD( rc = pCurNewNode->unlinkNode( pDb, 0)))
{
goto Exit;
}
if( pDataElementNode)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), pDataElementNode, IX_ADD_NODE_VALUE,
bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
}
// Make sure that "this" node is not a child of the node
// being inserted
if( RC_BAD( rc = isDescendantOf( pDb, pCurNewNode, &bDescendant)))
{
goto Exit;
}
if( bDescendant)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
// If the node being inserted isn't from the same document,
// we cannot perform the operation
if( pCurNewNode->getDocumentId() != getDocumentId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_WRONG_DOCUMENT_ERR);
goto Exit;
}
if( RC_BAD( rc = pCurNewNode->makeWriteCopy( pDb)))
{
goto Exit;
}
if( pInsertBefore)
{
if( RC_BAD( rc = pInsertBefore->makeWriteCopy( pDb)))
{
goto Exit;
}
// Insert the new child before the ref child
if( !pInsertBefore->getPrevSibId())
{
if( !bUpdatedNode)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bUpdatedNode = TRUE;
}
// Change the parent's first child pointer
setFirstChildId( pCurNewNode->getNodeId());
}
else
{
pCurNewNode->setPrevSibId( pInsertBefore->getPrevSibId());
// Get the prev sib and set its next sib value
if( RC_BAD( rc = pDb->getNode(
getCollection(), pInsertBefore->getPrevSibId(), &pTmpNode)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setNextSibId( pCurNewNode->getNodeId());
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
pTmpNode->Release();
pTmpNode = NULL;
}
pInsertBefore->setPrevSibId( pCurNewNode->getNodeId());
pCurNewNode->setNextSibId( pInsertBefore->getNodeId());
if( RC_BAD( rc = pDb->updateNode( pInsertBefore->m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
}
else
{
if( (ui64Tmp = getLastChildId()) != 0)
{
// Get the prev sib and set its next sib value
if( RC_BAD( rc = pDb->getNode(
getCollection(), getLastChildId(), &pTmpNode)))
{
goto Exit;
}
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setNextSibId( pCurNewNode->getNodeId());
pCurNewNode->setPrevSibId( getLastChildId());
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
pTmpNode->Release();
pTmpNode = NULL;
}
pCurNewNode->setPrevSibId( getLastChildId());
if( !bUpdatedNode)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bUpdatedNode = TRUE;
}
setLastChildId( pCurNewNode->getNodeId());
if( !ui64Tmp)
{
setFirstChildId( pCurNewNode->getNodeId());
}
}
// Need to increment the data child node count
if( pCurNewNode->getNodeType() == DATA_NODE &&
eThisNodeType == ELEMENT_NODE)
{
setDataChildCount( getDataChildCount() + 1);
bUpdatedNode = TRUE;
}
if( bUpdatedNode)
{
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
// Reset to FALSE for next time around in loop.
bUpdatedNode = FALSE;
}
pCurNewNode->setParentId( getNodeId());
// Need to set the naming tag and data type of the node.
if( pCurNewNode->getNodeType() == DATA_NODE &&
eThisNodeType == ELEMENT_NODE)
{
if( pCurNewNode->getDataType() == XFLM_NODATA_TYPE)
{
pCurNewNode->setDataType( getDataType());
}
else if( getDataType() != pCurNewNode->getDataType())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
pCurNewNode->setNameId( getNameId());
}
// An additional restriction on unique child elements is that they
// must have a node ID greater than the parent element. This allows
// them to be stored using a very compact representation.
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
{
if( pCurNewNode->getNodeId() < getNodeId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_CHILD_ELM_NODE_ID);
goto Exit;
}
}
if( RC_BAD( rc = pDb->updateNode( pCurNewNode->m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
if( pCurNewNode->getNodeId() == pLastNewChild->getNodeId())
{
bDone = TRUE;
}
// Do post-link indexing work
if( pCurNewNode->getNameId())
{
if( pCurNewNode->getNodeType() == DATA_NODE)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), pCurNewNode, IX_LINK_NODE, bStartOfUpdate)))
{
goto Exit;
}
}
bStartOfUpdate = FALSE;
}
pCurNewNode->Release();
pCurNewNode = pNextSib;
pNextSib = NULL;
if( bDone)
{
break;
}
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logInsertBefore(
pDb, getCollection(), getNodeId(), pNewChild->getNodeId(),
ui64RefChildId)))
{
goto Exit;
}
Exit:
// Release any nodes we are still holding
if( pFirstNewChild)
{
pFirstNewChild->Release();
}
if( pLastNewChild)
{
pLastNewChild->Release();
}
if( pCurNewNode)
{
pCurNewNode->Release();
}
if( pDataElementNode)
{
pDataElementNode->Release();
}
if( pNextSib)
{
pNextSib->Release();
}
if( pInsertBefore)
{
pInsertBefore->Release();
}
if( pTmpNode)
{
pTmpNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setNumber64(
IF_Db * ifpDb,
FLMINT64 i64Value,
FLMUINT64 ui64Value,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bNeg = FALSE;
F_Db * pDb = (F_Db*)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
IF_DOMNode * pNode = NULL;
FLMUINT uiCollection;
FLMUINT uiRflToken = 0;
FLMUINT uiNodeDataType;
FLMUINT uiValLen;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bIsIndexed = TRUE;
FLMBOOL bStartOfUpdate = TRUE;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = canSetValue( pDb, XFLM_NUMBER_TYPE)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Grab some information about the node
uiCollection = getCollection();
eNodeType = getNodeType();
// Special case for element nodes
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, &pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
bMustAbortOnError = TRUE;
rc = ((F_DOMNode *)pNode)->setNumber64( pDb, i64Value,
ui64Value, uiEncDefId);
goto Exit;
}
// If the number is less than zero, invert the sign
if( i64Value < 0)
{
bNeg = TRUE;
ui64Value = (FLMUINT64)(-i64Value);
}
else if( i64Value)
{
ui64Value = (FLMUINT64)i64Value;
}
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
if( RC_BAD( rc = m_pCachedNode->setNumber64( pDb,
m_uiAttrNameId, ui64Value, bNeg, uiEncDefId)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, m_uiAttrNameId)))
{
goto Exit;
}
goto Exit;
}
// Generate the storage value
uiNodeDataType = getDataType();
if( uiNodeDataType == XFLM_NUMBER_TYPE ||
uiNodeDataType == XFLM_NODATA_TYPE)
{
if( bNeg)
{
if( (getModeFlags() & FDOM_SIGNED_QUICK_VAL) &&
i64Value == getQuickINT64())
{
goto Exit;
}
}
else if( (getModeFlags() & FDOM_UNSIGNED_QUICK_VAL) &&
ui64Value == getQuickUINT64())
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
else
{
bIsIndexed = FALSE;
}
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
{
goto Exit;
}
if( getDataBufSize() < FLM_MAX_NUM_BUF_SIZE)
{
if( RC_BAD( rc = resizeDataBuffer( FLM_MAX_NUM_BUF_SIZE, FALSE)))
{
goto Exit;
}
}
uiValLen = FLM_MAX_NUM_BUF_SIZE;
if( RC_BAD( rc = flmNumber64ToStorage( ui64Value,
&uiValLen, getDataPtr(), bNeg, FALSE)))
{
goto Exit;
}
if( uiNodeDataType == XFLM_NODATA_TYPE)
{
uiNodeDataType = XFLM_NUMBER_TYPE;
setDataType( uiNodeDataType);
}
}
else if( uiNodeDataType == XFLM_TEXT_TYPE)
{
FLMBYTE ucNumBuf[ 64];
FLMBYTE * pucSen;
FLMUINT uiSenLen;
if( !bNeg)
{
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 1]);
}
else
{
f_i64toa( i64Value, (char *)&ucNumBuf[ 1]);
}
uiValLen = f_strlen( (const char *)ucNumBuf);
pucSen = &ucNumBuf[ 0];
uiSenLen = f_encodeSEN( uiValLen, &pucSen, (FLMUINT)0);
flmAssert( uiSenLen == 1);
uiValLen += uiSenLen + 1;
// If the value isn't being changed, there is no need to continue
if( getDataLength() == uiValLen &&
f_memcmp( getDataPtr(), ucNumBuf, uiValLen) == 0)
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
else
{
bIsIndexed = FALSE;
}
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
{
goto Exit;
}
// Allocate or re-allocate the buffer
if( calcDataBufSize( uiValLen) > getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
{
goto Exit;
}
}
if( uiValLen)
{
f_memcpy( getDataPtr(), ucNumBuf, uiValLen);
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
goto Exit;
}
setEncDefId( uiEncDefId);
setDataLength( uiValLen);
// Clear the "on disk" flag (if set), as well as the quick nums
unsetFlags( FDOM_VALUE_ON_DISK |
FDOM_FIXED_SIZE_HEADER |
FDOM_UNSIGNED_QUICK_VAL |
FDOM_SIGNED_QUICK_VAL);
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
if( !bNeg)
{
setUINT64( ui64Value);
}
else
{
setINT64( i64Value);
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( !uiEncDefId)
{
if( RC_BAD( rc = pRfl->logNodeSetNumberValue( pDb,
uiCollection, getNodeId(), ui64Value, bNeg)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pRfl->logEncryptedNodeUpdate( pDb, m_pCachedNode)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( pNode)
{
pNode->Release();
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setStorageValue(
F_Db * pDb,
void * pvValue,
FLMUINT uiValueLen,
FLMUINT uiEncDefId,
FLMBOOL bLast)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCollection;
eDomNodeType eNodeType;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bIsIndexed = TRUE;
F_Database * pDatabase = pDb->m_pDatabase;
FLMBOOL bFirst = pDatabase->m_pPendingInput ? FALSE : TRUE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getDataType() == XFLM_UNKNOWN_TYPE || (bStartedTrans && !bLast))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
bMustAbortOnError = TRUE;
uiCollection = getCollection();
eNodeType = getNodeType();
if( eNodeType == ELEMENT_NODE ||
eNodeType == DATA_NODE)
{
if( !getNameId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
if( bFirst)
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_DEL_NODE_VALUE, TRUE, &bIsIndexed)))
{
goto Exit;
}
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
}
if( eNodeType == ELEMENT_NODE ||
eNodeType == DATA_NODE ||
eNodeType == COMMENT_NODE)
{
FLMUINT uiBytesToCopy;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
if( bFirst)
{
setEncDefId( uiEncDefId);
}
if( bFirst && bLast)
{
if( calcDataBufSize( uiValueLen) != getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer( uiValueLen, FALSE)))
{
goto Exit;
}
}
setDataLength( uiValueLen);
if( uiValueLen)
{
f_memcpy( getDataPtr(), pvValue, uiValueLen);
}
}
else
{
if( bFirst)
{
if( RC_BAD( rc = m_pCachedNode->openPendingInput( pDb,
getDataType())))
{
goto Exit;
}
}
while( uiValueLen)
{
uiBytesToCopy = pDatabase->m_uiUpdBufferSize -
pDatabase->m_uiUpdByteCount;
uiBytesToCopy = uiBytesToCopy > uiValueLen
? uiValueLen
: uiBytesToCopy;
if( !uiBytesToCopy)
{
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
continue;
}
f_memcpy( &pDatabase->m_pucUpdBuffer[ pDatabase->m_uiUpdByteCount],
pucValue, uiBytesToCopy);
pucValue += uiBytesToCopy;
uiValueLen -= uiBytesToCopy;
pDatabase->m_uiUpdByteCount += uiBytesToCopy;
}
if( bLast)
{
if( pDatabase->m_bUpdFirstBuf)
{
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
}
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, TRUE)))
{
goto Exit;
}
pDatabase->endPendingInput();
}
}
}
else if( eNodeType == ATTRIBUTE_NODE)
{
if( !bLast)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->setStorageValue(
pDb, m_uiAttrNameId, pvValue, uiValueLen, uiEncDefId)))
{
goto Exit;
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( bLast)
{
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
this, IX_ADD_NODE_VALUE, FALSE)))
{
goto Exit;
}
}
}
Exit:
if( RC_BAD( rc))
{
if( bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
pDatabase->endPendingInput();
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::openPendingInput(
F_Db * pDb,
FLMUINT uiNewDataType)
{
RCODE rc = NE_XFLM_OK;
F_Database * pDatabase = pDb->m_pDatabase;
eDomNodeType eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// Set up the database to point to this node. Only one node
// is allowed to stream data into the B-Tree at a time.
if( RC_BAD( rc = pDatabase->startPendingInput( uiNewDataType, this)))
{
goto Exit;
}
// If the naming tag has already been set, make sure the
// new data type is compatible with the defined type for
// the tag.
if( getNameId())
{
switch( eNodeType)
{
case ELEMENT_NODE:
case DATA_NODE:
{
F_AttrElmInfo elmInfo;
if( RC_BAD( rc = pDb->m_pDict->getElement(
pDb, m_nodeInfo.uiNameId, &elmInfo)))
{
goto Exit;
}
if( elmInfo.getDataType() != uiNewDataType)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
break;
}
case ANNOTATION_NODE:
{
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
}
// Better be the latest version for update.
flmAssert( m_ui64LowTransId == pDb->m_ui64CurrTransID);
m_nodeInfo.uiDataLength = 0;
m_nodeInfo.uiDataType = uiNewDataType;
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
setFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
flmAssert( !pDatabase->m_uiUpdByteCount);
flmAssert( !pDatabase->m_uiUpdCharCount);
Exit:
if( RC_BAD( rc))
{
pDatabase->endPendingInput();
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::flushPendingInput(
F_Db * pDb,
FLMBOOL bLast)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection = NULL;
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMBYTE ucHeader[ MAX_DOM_HEADER_SIZE + 16];
FLMUINT uiKeyLen;
FLMUINT uiHeaderStorageSize;
F_Database * pDatabase = pDb->m_pDatabase;
FLMUINT uiOutputLength;
FLMUINT uiLeftoverLength;
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( m_nodeInfo.ui64NodeId,
&uiKeyLen, ucKey, FALSE, TRUE)))
{
goto Exit;
}
// Open the B-Tree
if( !pDatabase->m_pPendingBTree)
{
if( !pDatabase->m_bUpdFirstBuf)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree(
&pDatabase->m_pPendingBTree)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->m_pDict->getCollection(
m_nodeInfo.uiCollection, &pCollection)))
{
goto Exit;
}
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btOpen(
pDb, &pCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
}
// Better be the latest version for update.
flmAssert( m_ui64LowTransId == pDb->m_ui64CurrTransID);
uiOutputLength = pDatabase->m_uiUpdByteCount;
uiLeftoverLength = 0;
// Output the node header
if( pDatabase->m_bUpdFirstBuf)
{
FLMUINT uiIVLen = 0;
// This routine is designed to handle multi-block data streams.
// It shouldn't be called if everything fits within the a single
// update buffer.
flmAssert( !bLast);
// There shouldn't be any attributes at this point, because
// this shouldn't be an element node
flmAssert( !hasAttributes());
flmAssert( m_nodeInfo.eNodeType != ELEMENT_NODE);
// Build the node header
if( RC_BAD( rc = headerToBuf( TRUE, ucHeader,
&uiHeaderStorageSize, NULL, NULL)))
{
goto Exit;
}
if( getEncDefId())
{
F_ENCDEF * pEncDef;
if( RC_BAD( rc = pDb->m_pDict->getEncDef( getEncDefId(), &pEncDef)))
{
goto Exit;
}
uiIVLen = pEncDef->pCcs->getIVLen();
flmAssert( uiIVLen == 8 || uiIVLen == 16);
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, pDatabase->m_ucIV)))
{
goto Exit;
}
f_memcpy( &ucHeader[ uiHeaderStorageSize], pDatabase->m_ucIV, uiIVLen);
}
// Output the header
if( nodeIsNew())
{
// If this is a new entry, we need to insert it into the
// b-tree.
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btInsertEntry(
ucKey, uiKeyLen,
ucHeader, uiHeaderStorageSize + uiIVLen, TRUE, FALSE,
&m_ui32BlkAddr, &m_uiOffsetIndex)))
{
if( rc == NE_XFLM_NOT_UNIQUE)
{
rc = RC_SET( NE_XFLM_EXISTS);
}
goto Exit;
}
}
else
{
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
ucKey, uiKeyLen,
ucHeader, uiHeaderStorageSize + uiIVLen, TRUE, FALSE, TRUE,
&m_ui32BlkAddr, &m_uiOffsetIndex)))
{
goto Exit;
}
}
pDatabase->m_bUpdFirstBuf = FALSE;
}
// Output the data buffer
if( pDatabase->m_uiUpdByteCount || bLast)
{
// Encrypt the buffer if this node is encrypted. If encrypted,
// uiOutputLength will hold the length of the encrypted data.
// If not encrypted, it will hold the length of the non-encrypted data,
// i.e. pDatabase->m_uiUpdByteCount. the encrypted data will be returned
// in the input buffer.
if( getEncDefId())
{
// If this is not the last buffer, only encrypt to the nearest
// FLM_ENCRYPT_CHUNK_SIZE byte boundary. Move whatever we don't
// encrypt down to the beginning of the buffer after writing the
// encrypted part out to the B-tree (see below). This is necessary
// because the decryption algorithm assumes that all of the
// encrypted data is in FLM_ENRYPT_CHUNK_SIZE byte chunks - except
// for the last chunk, which may be encrypted to the nearest 16 byte
// boundary.
if( !bLast && (uiOutputLength & (FLM_ENCRYPT_CHUNK_SIZE - 1)))
{
uiLeftoverLength = uiOutputLength & (FLM_ENCRYPT_CHUNK_SIZE - 1);
uiOutputLength -= uiLeftoverLength;
}
if( RC_BAD( rc = pDb->encryptData( getEncDefId(), pDatabase->m_ucIV,
pDatabase->m_pucUpdBuffer, pDatabase->m_uiUpdBufferSize,
uiOutputLength, &uiOutputLength)))
{
goto Exit;
}
}
if( nodeIsNew())
{
// If this is a new entry, we need to continue calling the
// insert method to stream its data into the b-tree
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btInsertEntry(
ucKey, uiKeyLen,
pDatabase->m_pucUpdBuffer, uiOutputLength,
FALSE, bLast,
&m_ui32BlkAddr, &m_uiOffsetIndex)))
{
if( rc == NE_XFLM_NOT_UNIQUE)
{
rc = RC_SET( NE_XFLM_EXISTS);
}
goto Exit;
}
}
else
{
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
ucKey, uiKeyLen,
pDatabase->m_pucUpdBuffer, uiOutputLength,
FALSE, bLast, TRUE,
&m_ui32BlkAddr, &m_uiOffsetIndex)))
{
goto Exit;
}
}
}
m_nodeInfo.uiDataLength += uiOutputLength;
if( (pDatabase->m_uiUpdByteCount = uiLeftoverLength) != 0)
{
f_memmove( pDatabase->m_pucUpdBuffer,
pDatabase->m_pucUpdBuffer + uiOutputLength, uiLeftoverLength);
}
if( bLast)
{
// Clear the dirty flag and the new flag.
unsetNodeDirtyAndNew( pDb);
}
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::setMetaValue(
IF_Db * ifpDb,
FLMUINT64 ui64Value)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db*)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartedTrans = FALSE;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// Only allow meta values on element nodes.
if( eNodeType != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If the value isn't changing, don't do anything
if( ui64Value == getMetaValue())
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Make sure the node can be updated
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
// Set the value
setMetaValue( ui64Value);
// Update the node
if( RC_BAD( rc = pDb->updateNode(
m_pCachedNode, FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetMetaValue( pDb,
getCollection(), getNodeId(), ui64Value)))
{
goto Exit;
}
Exit:
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getMetaValue(
IF_Db * ifpDb,
FLMUINT64 * pui64Value)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db*)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
*pui64Value = getMetaValue();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::isDataLocalToNode(
IF_Db * ifpDb,
FLMBOOL * pbDataIsLocal)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db*)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (getNodeType() == ATTRIBUTE_NODE)
{
*pbDataIsLocal = TRUE;
}
else
{
*pbDataIsLocal = getDataLength() ? TRUE : FALSE;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Read from a text stream, outputting ASCII. If we encounter a
character that cannot be output as ASCII, we will return an error.
******************************************************************************/
RCODE F_AsciiIStream::read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
FLMUNICODE uzChar;
*puiBytesRead = 0;
while( *puiBytesRead < uiBytesToRead)
{
if( m_eTextType == XFLM_UNICODE_TEXT)
{
if( (m_pucEnd && ((FLMUINT)(m_pucEnd - m_pucCurrPtr) <
sizeof( FLMUNICODE))) ||
(uzChar = *((FLMUNICODE *)m_pucCurrPtr)) == 0)
{
break;
}
if( uzChar > 127)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
*pucBuffer++ = (FLMBYTE)uzChar;
m_pucCurrPtr += sizeof( FLMUNICODE);
}
else // UTF8
{
if( RC_BAD( rc = f_getCharFromUTF8Buf(
&m_pucCurrPtr, m_pucEnd, &uzChar)))
{
goto Exit;
}
if( !uzChar)
{
break;
}
if( uzChar > 127)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
*pucBuffer++ = (FLMBYTE)uzChar;
}
m_uiCurrChar++;
(*puiBytesRead)++;
}
if( *puiBytesRead < uiBytesToRead)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: This class converts a storage text stream to an ASCII
text stream.
******************************************************************************/
class F_AsciiStorageStream : public IF_IStream
{
public:
F_AsciiStorageStream()
{
m_pIStream = NULL;
}
~F_AsciiStorageStream()
{
close();
}
RCODE FLMAPI read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead);
FINLINE RCODE FLMAPI close( void)
{
if( m_pIStream)
{
m_pIStream->Release();
m_pIStream = NULL;
}
return( NE_XFLM_OK);
}
RCODE open(
IF_IStream * pIStream);
private:
IF_IStream * m_pIStream;
};
/*****************************************************************************
Desc: Open an Ascii storage stream.
******************************************************************************/
RCODE F_AsciiStorageStream::open(
IF_IStream * pIStream)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucSENBuf [16];
FLMUINT uiLen;
FLMUINT uiSENLen;
close();
m_pIStream = pIStream;
m_pIStream->AddRef();
// Skip over the SEN
uiLen = 1;
if( RC_BAD( rc = m_pIStream->read( (char *)&ucSENBuf [0], uiLen, &uiLen)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
if( (uiSENLen = f_getSENLength( ucSENBuf[ 0])) > 1)
{
uiLen = uiSENLen - 1;
if( RC_BAD( rc = m_pIStream->read(
(char *)&ucSENBuf [1], uiLen, &uiLen)))
{
goto Exit;
}
}
// We are now positioned to read UTF8
Exit:
if( RC_BAD( rc))
{
close();
}
return( rc);
}
/*****************************************************************************
Desc: Read from a storage text stream, outputting ASCII. If we encounter a
character that cannot be output as ASCII, we will return an error.
******************************************************************************/
RCODE F_AsciiStorageStream::read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE uzChar;
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
FLMUINT uiBytesRead = 0;
// Better have a stream that has been positioned by a call to open().
flmAssert( m_pIStream);
while( uiBytesRead < uiBytesToRead)
{
if( RC_BAD( rc = f_readUTF8CharAsUnicode( m_pIStream, &uzChar)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
else
{
goto Exit;
}
}
if( uzChar <= 127)
{
*pucBuffer++ = (FLMBYTE)uzChar;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
uiBytesRead++;
}
if( uiBytesRead < uiBytesToRead)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
Exit:
if( puiBytesRead)
{
*puiBytesRead = uiBytesRead;
}
return( rc);
}
/*****************************************************************************
Desc: This class converts a binary stream to an ASCII text storage
stream.
******************************************************************************/
class F_BinaryToTextStream : public IF_IStream
{
public:
F_BinaryToTextStream()
{
m_pEncoderStream = NULL;
}
~F_BinaryToTextStream()
{
close();
}
RCODE FLMAPI read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead);
FINLINE RCODE FLMAPI close( void)
{
if( m_pEncoderStream)
{
m_pEncoderStream->Release();
m_pEncoderStream = NULL;
}
return( NE_XFLM_OK);
}
RCODE open(
IF_IStream * pIStream,
FLMUINT uiDataLen,
FLMUINT * puiTextLength);
private:
FLMBYTE m_ucSENBuf [16];
FLMUINT m_uiSENLen;
FLMUINT m_uiCurrOffset;
IF_IStream * m_pEncoderStream;
};
/*****************************************************************************
Desc: Open a binary-to-text stream.
******************************************************************************/
RCODE F_BinaryToTextStream::open(
IF_IStream * pIStream,
FLMUINT uiDataLen,
FLMUINT * puiTextLength)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucSen;
FLMUINT uiOutputLen;
close();
// Set up the SEN buffer. Calculate length to be 4 bytes for every 3
// binary bytes.
uiOutputLen = (uiDataLen / 3) * 4;
// If number of bytes is not an exact multiple of 3, we will need 4
// more bytes.
if( uiDataLen % 3)
{
uiOutputLen += 4;
}
pucSen = &m_ucSENBuf [0];
m_uiSENLen = f_encodeSEN( (FLMUINT64)uiOutputLen, &pucSen, (FLMUINT)0);
m_uiCurrOffset = 0;
// Need to include the data length, SEN length, and the terminating null
// character.
*puiTextLength = uiOutputLen + m_uiSENLen + 1;
// Set up the encoder stream
if( RC_BAD( rc = FlmOpenBase64EncoderIStream( pIStream,
FALSE, &m_pEncoderStream)))
{
goto Exit;
}
Exit:
if( RC_BAD( rc))
{
close();
}
return( rc);
}
/*****************************************************************************
Desc: Read from a binary stream, outputting base 64 encoded ASCII.
******************************************************************************/
RCODE F_BinaryToTextStream::read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
FLMUINT uiBytesRead;
// Better have a stream that has been positioned by a call to open().
flmAssert( m_pEncoderStream);
*puiBytesRead = 0;
if( m_uiCurrOffset < m_uiSENLen)
{
if( uiBytesToRead >= m_uiSENLen - m_uiCurrOffset)
{
f_memcpy( pucBuffer, &m_ucSENBuf [m_uiCurrOffset],
m_uiSENLen - m_uiCurrOffset);
(*puiBytesRead) += (m_uiSENLen - m_uiCurrOffset);
pucBuffer += (m_uiSENLen - m_uiCurrOffset);
m_uiCurrOffset = m_uiSENLen;
}
else
{
f_memcpy( pucBuffer, &m_ucSENBuf [m_uiCurrOffset],
uiBytesToRead);
(*puiBytesRead) += uiBytesToRead;
m_uiCurrOffset += uiBytesToRead;
pucBuffer += uiBytesToRead;
}
}
// If we didn't get everything from the SEN buffer, read from the
// decoding stream.
if( *puiBytesRead < uiBytesToRead)
{
if( RC_BAD( rc = m_pEncoderStream->read( pucBuffer,
uiBytesToRead - *puiBytesRead, &uiBytesRead)))
{
if( rc == NE_XFLM_EOF_HIT)
{
(*puiBytesRead) += uiBytesRead;
}
goto Exit;
}
else
{
(*puiBytesRead) += uiBytesRead;
}
}
if( *puiBytesRead < uiBytesToRead)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Store text as a number.
******************************************************************************/
RCODE F_DOMNode::storeTextAsNumber(
F_Db * pDb,
void * pvValue,
FLMUINT uiNumBytesInBuffer,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucChar;
FLMUINT uiIncrAmount = 0;
FLMBOOL bNeg = FALSE;
FLMBOOL bHex = FALSE;
FLMUINT64 ui64Num = 0;
FLMUINT uiBytesRead;
FLMBOOL bFirstChar = TRUE;
F_AsciiIStream asciiStream( (FLMBYTE *)pvValue, uiNumBytesInBuffer, XFLM_UTF8_TEXT);
// Convert the text to a number.
for (;;)
{
if( RC_BAD( rc = asciiStream.read( &ucChar, 1, &uiBytesRead)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
// See if we can convert to a number.
if( ucChar >= ASCII_ZERO && ucChar <= ASCII_NINE)
{
uiIncrAmount = (FLMUINT)(ucChar - '0');
}
else if( ucChar >= ASCII_UPPER_A && ucChar <= ASCII_UPPER_F)
{
if( bHex)
{
uiIncrAmount = (FLMUINT)(ucChar - ASCII_UPPER_A + 10);
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( ucChar >= ASCII_LOWER_A && ucChar <= ASCII_LOWER_F)
{
if( bHex)
{
uiIncrAmount = (FLMUINT)(ucChar - ASCII_LOWER_A + 10);
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( ucChar == ASCII_LOWER_X || ucChar == ASCII_UPPER_X)
{
if( !ui64Num && !bHex)
{
bHex = TRUE;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( ucChar == ASCII_DASH && bFirstChar)
{
bNeg = TRUE;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
if( !bHex)
{
if( ui64Num > (~(FLMUINT64)0) / 10)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num *= (FLMUINT64)10;
}
else
{
if( ui64Num > (~(FLMUINT64)0) / 16)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num *= (FLMUINT64)16;
}
if( ui64Num > (~(FLMUINT64)0) - (FLMUINT64)uiIncrAmount)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num += (FLMUINT64)uiIncrAmount;
bFirstChar = FALSE;
}
// If the number is negative, make sure it doesn't
// overflow the maximum negative number.
if( bNeg)
{
if( ui64Num > gv_ui64MaxSignedIntVal + 1)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_UNDERFLOW);
goto Exit;
}
if( RC_BAD( rc = setINT64( (IF_Db *)pDb,
-((FLMINT64)ui64Num), uiEncDefId)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = setUINT64( (IF_Db *)pDb, ui64Num, uiEncDefId)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc: Store text as a binary value.
******************************************************************************/
RCODE F_DOMNode::storeTextAsBinary(
F_Db * pDb,
const void * pvValue,
FLMUINT uiNumBytesInBuffer,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucBuf[ 64];
F_AsciiIStream asciiStream( (FLMBYTE *)pvValue,
uiNumBytesInBuffer, XFLM_UTF8_TEXT);
IF_IStream * pDecoderStream = NULL;
FLMBYTE ucDynaBuf[ 64];
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
FLMUINT uiBytesRead;
if( RC_BAD( rc = FlmOpenBase64DecoderIStream(
&asciiStream, &pDecoderStream)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pDecoderStream->read( ucBuf, sizeof( ucBuf), &uiBytesRead)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
if( RC_BAD( rc = dynaBuf.appendData( ucBuf, uiBytesRead)))
{
goto Exit;
}
}
if( RC_BAD( rc = setBinary(
(IF_Db *)pDb, dynaBuf.getBufferPtr(),
dynaBuf.getDataLength(), uiEncDefId)))
{
goto Exit;
}
Exit:
if( pDecoderStream)
{
pDecoderStream->Release();
}
return( rc);
}
/*****************************************************************************
Desc: Store binary as a text value (base 64 encoded)
******************************************************************************/
RCODE F_DOMNode::storeBinaryAsText(
F_Db * pDb,
const void * pvValue,
FLMUINT uiLength,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucBuf[ 64];
IF_PosIStream * pIStream = NULL;
IF_IStream * pEncoderStream = NULL;
FLMBYTE ucDynaBuf[ 64];
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
FLMUINT uiBytesRead;
if( RC_BAD( rc = FlmOpenBufferIStream(
(const char *)pvValue, uiLength, &pIStream)))
{
goto Exit;
}
if( RC_BAD( rc = FlmOpenBase64EncoderIStream( pIStream,
FALSE, &pEncoderStream)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pEncoderStream->read(
ucBuf, sizeof( ucBuf), &uiBytesRead)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
if( RC_BAD( rc = dynaBuf.appendData( ucBuf, uiBytesRead)))
{
goto Exit;
}
}
if( RC_BAD( rc = setTextFastPath( pDb, dynaBuf.getBufferPtr(),
dynaBuf.getDataLength(), XFLM_UTF8_TEXT, uiEncDefId)))
{
goto Exit;
}
Exit:
if( pEncoderStream)
{
pEncoderStream->Release();
}
if( pIStream)
{
pIStream->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setTextStreaming(
F_Db * pDb,
const void * pvValue,
FLMUINT uiNumBytesInBuffer,
eXFlmTextType eTextType,
FLMBOOL bLast,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiLen;
FLMBYTE * pucUpdBuffer;
FLMUINT uiUpdBufferSize;
FLMBYTE * pucTmp;
FLMUINT uiSenLen;
FLMBYTE ucTmpSen[ FLM_MAX_NUM_BUF_SIZE];
F_Database * pDatabase = pDb->m_pDatabase;
F_Rfl * pRfl = pDatabase->m_pRfl;
F_DOMNode * pNode = NULL;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bFirst = pDatabase->m_pPendingInput ? FALSE : TRUE;
FLMUINT uiRflToken = 0;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// Not supported on attributes
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If this is an element node, we need to find or create
// the child data node
if( eNodeType == ELEMENT_NODE)
{
// The streaming interface is not directly supported on element nodes.
// If the node already has a value and does not already have a child data
// node, we can clear the value on the element, create a data node, and
// allow the operation to continue.
if( getDataLength())
{
if( getDataChildCount())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = clearNodeValue( pDb)))
{
goto Exit;
}
}
else if( getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
}
if( !pNode)
{
if( RC_BAD( rc = createNode( (IF_Db *)pDb, DATA_NODE,
getNameId(), XFLM_LAST_CHILD, (IF_DOMNode **)&pNode)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
}
if( RC_BAD( rc = pNode->setTextStreaming( pDb,
pvValue, uiNumBytesInBuffer, eTextType, bLast, uiEncDefId)))
{
goto Exit;
}
goto Exit;
}
// Make sure the state of the node and database
// allow a value to be set.
if( RC_BAD( rc = canSetValue( pDb, XFLM_TEXT_TYPE)))
{
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
bMustAbortOnError = TRUE;
// If we are in the middle of streaming data into a node,
// any error will probably leave the database in a bad
// state. Because of this, we want to force the
// transaction to abort.
if( pDatabase->m_pPendingInput)
{
if( pDatabase->m_pPendingInput != m_pCachedNode)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
pucUpdBuffer = pDatabase->m_pucUpdBuffer;
// NOTE: So that flushNode would not have to allocate a buffer for
// writing out data with a non-padded header, we reserve enough
// room in pDatabase->m_pucUpdBuffer so that it could hold a maximum
// header plus all of the data if it needed to.
// Also, make sure there is room to encrypt the data. That is why
// we subtract another 16 bytes.
uiUpdBufferSize = pDatabase->m_uiUpdBufferSize -
MAX_DOM_HEADER_SIZE - ENCRYPT_MIN_CHUNK_SIZE;
// Update the index keys
if( bFirst)
{
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_DEL_NODE_VALUE, TRUE)))
{
goto Exit;
}
}
}
// Open the pending input stream
if( bFirst)
{
if( RC_BAD( rc = openPendingInput( pDb, XFLM_TEXT_TYPE)))
{
goto Exit;
}
// Reserve 5 bytes for a SEN indicating the number of characters
// in the string. The SEN (representing a 32-bit number) will
// never require more than 5 bytes and will typically only
// require 1 or 2 bytes.
pDatabase->m_uiUpdByteCount += SEN_RESERVE_BYTES;
*pucUpdBuffer = 0;
// Save the encryption scheme
setEncDefId( uiEncDefId);
}
// Set the value
if( pvValue)
{
// If a zero was passed for the character count, change it to
// the UINT high value. We will output characters until a terminating
// null is found.
if( !uiNumBytesInBuffer)
{
uiNumBytesInBuffer = FLM_MAX_UINT;
}
switch( eTextType)
{
case XFLM_UNICODE_TEXT:
{
FLMUNICODE * puCurChar = (FLMUNICODE *)pvValue;
while( *puCurChar && uiNumBytesInBuffer >= sizeof( FLMUNICODE))
{
uiLen = uiUpdBufferSize - pDatabase->m_uiUpdByteCount;
if( RC_BAD( rc = f_uni2UTF8( *puCurChar,
&pucUpdBuffer[ pDatabase->m_uiUpdByteCount], &uiLen)))
{
if( rc == NE_XFLM_CONV_DEST_OVERFLOW)
{
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
continue;
}
goto Exit;
}
pDatabase->m_uiUpdByteCount += uiLen;
pDatabase->m_uiUpdCharCount++;
uiNumBytesInBuffer -= sizeof( FLMUNICODE);
puCurChar++;
}
break;
}
case XFLM_UTF8_TEXT:
{
FLMBYTE * pucCurByte = (FLMBYTE *)pvValue;
FLMBYTE * pucEnd = (FLMBYTE *)pvValue + uiNumBytesInBuffer;
for( ;;)
{
if( (uiUpdBufferSize - pDatabase->m_uiUpdByteCount) < 3)
{
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
}
if( RC_BAD( rc = f_getUTF8CharFromUTF8Buf( &pucCurByte,
pucEnd, &pucUpdBuffer[ pDatabase->m_uiUpdByteCount], &uiLen)))
{
goto Exit;
}
if( !uiLen)
{
break;
}
pDatabase->m_uiUpdByteCount += uiLen;
pDatabase->m_uiUpdCharCount++;
uiNumBytesInBuffer -= uiLen;
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
}
if( bLast)
{
// Terminate the buffer with a null byte
if( pDatabase->m_uiUpdCharCount)
{
// See if there is room for a single zero byte
if( pDatabase->m_uiUpdByteCount == uiUpdBufferSize)
{
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
}
pucUpdBuffer[ pDatabase->m_uiUpdByteCount++] = 0;
}
if( pDatabase->m_bUpdFirstBuf)
{
if( pDatabase->m_uiUpdCharCount)
{
FLMUINT uiValLen;
// Five bytes were reserved to encode the number of characters
// in the string. Since we didn't have to use multiple buffers
// to write the string to the database, we won't have to
// output a padded SEN.
pucTmp = ucTmpSen;
f_encodeSEN( pDatabase->m_uiUpdCharCount, &pucTmp);
uiSenLen = (FLMUINT)(pucTmp - ucTmpSen);
// Copy the value into the node
uiValLen = (pDatabase->m_uiUpdByteCount -
SEN_RESERVE_BYTES) + uiSenLen;
if( calcDataBufSize( uiValLen) > getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
{
goto Exit;
}
}
setDataLength( uiValLen);
f_memcpy( getDataPtr(), ucTmpSen, uiSenLen);
f_memcpy( getDataPtr() + uiSenLen,
&pucUpdBuffer[ SEN_RESERVE_BYTES],
pDatabase->m_uiUpdByteCount - SEN_RESERVE_BYTES);
}
else
{
setDataLength( 0);
}
// Clear flags
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
setDataLength( 0);
goto Exit;
}
}
else
{
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMUINT uiHeaderStorageSize;
FLMUINT32 ui32BlkAddr;
FLMUINT uiOffsetIndex;
// Flush anything that is in the current buffer and end the
// pending input stream.
if( RC_BAD( rc = flushPendingInput( pDb, TRUE)))
{
goto Exit;
}
pucTmp = ucTmpSen;
f_encodeSEN( pDatabase->m_uiUpdCharCount,
&pucTmp, SEN_RESERVE_BYTES);
flmAssert( (FLMUINT)(pucTmp - ucTmpSen) == SEN_RESERVE_BYTES);
// Output the header
if( RC_BAD( rc = headerToBuf( TRUE, pDatabase->m_pucUpdBuffer,
&uiHeaderStorageSize, NULL, NULL)))
{
goto Exit;
}
// Copy the SEN into the update buffer
f_memcpy( &pDatabase->m_pucUpdBuffer[ uiHeaderStorageSize],
ucTmpSen, SEN_RESERVE_BYTES);
// Replace the header
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( getNodeId(), &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
ui32BlkAddr = getBlkAddr();
uiOffsetIndex = getOffsetIndex();
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
ucKey, uiKeyLen,
pDatabase->m_pucUpdBuffer, uiHeaderStorageSize + SEN_RESERVE_BYTES,
TRUE, TRUE, FALSE, &ui32BlkAddr, &uiOffsetIndex)))
{
goto Exit;
}
setBlkAddr( ui32BlkAddr);
setOffsetIndex( uiOffsetIndex);
// Clear the dirty flag and the new flag.
unsetNodeDirtyAndNew( pDb);
}
pDatabase->endPendingInput();
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_ADD_NODE_VALUE, FALSE)))
{
goto Exit;
}
}
// Log the node to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
RFL_NODE_SET_TEXT_VALUE_PACKET, m_pCachedNode)))
{
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( RC_BAD( rc))
{
pDatabase->endPendingInput();
if( bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setTextFastPath(
F_Db * pDb,
const void * pvValue,
FLMUINT uiNumBytesInBuffer,
eXFlmTextType eTextType,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiNumCharsInBuffer = 0;
FLMBYTE ucUTFCharBuf[ 3];
F_Database * pDatabase = pDb->m_pDatabase;
F_Rfl * pRfl = pDatabase->m_pRfl;
F_DOMNode * pNode = NULL;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
FLMUINT uiValLen;
FLMUINT uiReadLen;
FLMBOOL bIsIndexed = TRUE;
FLMBYTE ucDynaBuf[ 64];
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
FLMBOOL bStartOfUpdate = TRUE;
eDomNodeType eNodeType;
// Make sure a transaction is active
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Cannot set a value if input is still pending
if( pDatabase->m_pPendingInput)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// Convert the text to UTF-8 if needed
if( eTextType == XFLM_UNICODE_TEXT)
{
FLMUNICODE * puCurChar = (FLMUNICODE *)pvValue;
if( puCurChar)
{
if( !uiNumBytesInBuffer)
{
uiNumBytesInBuffer = FLM_MAX_UINT;
}
while( *puCurChar && uiNumBytesInBuffer >= sizeof( FLMUNICODE))
{
if( *puCurChar <= 0x007F)
{
if( RC_BAD( rc = dynaBuf.appendByte( (FLMBYTE)*puCurChar)))
{
goto Exit;
}
}
else
{
uiReadLen = sizeof( ucUTFCharBuf);
if( RC_BAD( rc = f_uni2UTF8( *puCurChar,
ucUTFCharBuf, &uiReadLen)))
{
goto Exit;
}
if( RC_BAD( rc = dynaBuf.appendData( ucUTFCharBuf, uiReadLen)))
{
goto Exit;
}
}
puCurChar++;
uiNumBytesInBuffer -= sizeof( FLMUNICODE);
uiNumCharsInBuffer++;
}
}
if( RC_BAD( rc = dynaBuf.appendByte( 0)))
{
goto Exit;
}
eTextType = XFLM_UTF8_TEXT;
pvValue = dynaBuf.getBufferPtr();
uiNumBytesInBuffer = dynaBuf.getDataLength();
}
else if( eTextType == XFLM_UTF8_TEXT)
{
if( RC_BAD( rc = f_getUTF8Length( (FLMBYTE *)pvValue, uiNumBytesInBuffer,
&uiNumBytesInBuffer, &uiNumCharsInBuffer)))
{
goto Exit;
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If this is an element node, we need to see if there is a
// child data node
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
bMustAbortOnError = TRUE;
if( getDataChildCount() == 1)
{
// If this node only has one data child, delete the child and
// store the value directly on the element
if( RC_BAD( rc = pNode->deleteNode( pDb)))
{
goto Exit;
}
pNode->Release();
pNode = NULL;
}
else
{
rc = pNode->setTextFastPath( pDb, pvValue, uiNumBytesInBuffer,
eTextType, uiEncDefId);
goto Exit;
}
}
// Make sure the states of the node and database
// allow a value to be set.
if( RC_BAD( rc = canSetValue( pDb, XFLM_TEXT_TYPE)))
{
goto Exit;
}
// If this is an attribute node, need to use the
// attribute list object to set the value
if( eNodeType == ATTRIBUTE_NODE)
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate,
&bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
if( RC_BAD( rc = m_pCachedNode->setUTF8( pDb,
m_uiAttrNameId, pvValue, uiNumBytesInBuffer,
uiNumCharsInBuffer, uiEncDefId)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
}
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
setDataLength( 0);
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, m_uiAttrNameId)))
{
goto Exit;
}
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
bMustAbortOnError = TRUE;
// Update the index keys
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
else
{
bIsIndexed = FALSE;
}
// Verify and save the encryption scheme
if( uiEncDefId)
{
if( RC_BAD( rc = pDb->m_pDict->getEncDef( uiEncDefId, NULL)))
{
flmAssert( 0);
goto Exit;
}
}
setEncDefId( uiEncDefId);
// Set the value
uiValLen = 0;
if( pvValue && uiNumBytesInBuffer)
{
FLMUINT uiSenLen;
FLMBYTE * pucTmp;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
FLMBOOL bNullTerminate = FALSE;
if( pucValue[ uiNumBytesInBuffer - 1] != 0)
{
bNullTerminate = TRUE;
}
uiSenLen = f_getSENByteCount( uiNumCharsInBuffer);
uiValLen = uiNumBytesInBuffer + uiSenLen + (bNullTerminate ? 1 : 0);
if( calcDataBufSize( uiValLen) > getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
{
goto Exit;
}
}
pucTmp = getDataPtr();
f_encodeSENKnownLength( uiNumCharsInBuffer, uiSenLen, &pucTmp);
f_memcpy( pucTmp, pucValue, uiNumBytesInBuffer);
if( bNullTerminate)
{
pucTmp[ uiNumBytesInBuffer] = 0;
}
}
setDataLength( uiValLen);
// Clear flags
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
setDataLength( 0);
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
// Log the node to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
RFL_NODE_SET_TEXT_VALUE_PACKET, m_pCachedNode)))
{
goto Exit;
}
Exit:
if( pNode)
{
pNode->Release();
}
if( RC_BAD( rc))
{
if( bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setBinaryStreaming(
IF_Db * ifpDb,
const void * pvValue,
FLMUINT uiLength,
FLMBOOL bLast,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_Database * pDatabase = pDb->m_pDatabase;
F_Rfl * pRfl = pDatabase->m_pRfl;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
FLMBYTE * pucUpdBuffer;
FLMUINT uiUpdBufferSize;
FLMUINT uiTmp;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pNode = NULL;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// Not supported on attribute nodes
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If this is an element node, we need to find or create
// the child data node
if( eNodeType == ELEMENT_NODE)
{
// The streaming interface is not directly supported on element nodes.
// If the node already has a value and does not already have a child data
// node, we can clear the value on the element, create a data node, and
// allow the operation to continue.
if( getDataLength())
{
if( getDataChildCount())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = clearNodeValue( pDb)))
{
goto Exit;
}
}
else if( getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
}
if( !pNode)
{
if( RC_BAD( rc = createNode( (IF_Db *)pDb, DATA_NODE,
getNameId(), XFLM_LAST_CHILD, (IF_DOMNode **)&pNode)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
}
if( RC_BAD( rc = pNode->setBinary( ifpDb, pucValue, uiLength, bLast,
uiEncDefId)))
{
goto Exit;
}
goto Exit;
}
// Make sure the state of the node and database
// allow a value to be set.
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
bMustAbortOnError = TRUE;
// If we are in the middle of streaming data into a node,
// any error will probably leave the database in a bad
// state. Because of this, we want to force the
// transaction to abort.
if( pDatabase->m_pPendingInput)
{
if( pDatabase->m_pPendingInput != m_pCachedNode)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
pucUpdBuffer = pDatabase->m_pucUpdBuffer;
// NOTE: So that flushNode would not have to allocate a buffer for
// writing out data with a non-padded header, we reserve enough
// room in pDatabase->m_pucUpdBuffer so that it could hold a maximum
// header plus all of the data if it needed to.
//
// Also, make sure there is room to encrypt the data. That is why
// we subtract another 16 bytes.
uiUpdBufferSize = pDatabase->m_uiUpdBufferSize -
MAX_DOM_HEADER_SIZE - ENCRYPT_MIN_CHUNK_SIZE;
// Open the pending input stream
if( !pDatabase->m_pPendingInput)
{
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
this, IX_DEL_NODE_VALUE, TRUE)))
{
goto Exit;
}
}
if( RC_BAD( rc = openPendingInput( pDb, XFLM_BINARY_TYPE)))
{
goto Exit;
}
}
// Save the encryption scheme
setEncDefId( uiEncDefId);
while( uiLength)
{
if( (uiTmp = f_min( uiLength,
uiUpdBufferSize - pDatabase->m_uiUpdByteCount)) == 0)
{
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
{
goto Exit;
}
continue;
}
f_memcpy( &pucUpdBuffer[ pDatabase->m_uiUpdByteCount], pucValue, uiTmp);
pDatabase->m_uiUpdByteCount += uiTmp;
pucValue += uiTmp;
uiLength -= uiTmp;
}
if( bLast)
{
if( pDatabase->m_bUpdFirstBuf)
{
if( pDatabase->m_uiUpdByteCount)
{
if( calcDataBufSize( pDatabase->m_uiUpdByteCount) > getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer(
pDatabase->m_uiUpdByteCount, FALSE)))
{
goto Exit;
}
}
}
setDataLength( pDatabase->m_uiUpdByteCount);
if( pDatabase->m_uiUpdByteCount)
{
f_memcpy( getDataPtr(), pucUpdBuffer, pDatabase->m_uiUpdByteCount);
}
// Clear unwanted flags
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
}
else
{
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMUINT uiHeaderStorageSize;
FLMUINT32 ui32BlkAddr;
FLMUINT uiOffsetIndex;
// Flush anything that is in the current buffer
if( RC_BAD( rc = flushPendingInput( pDb, TRUE)))
{
goto Exit;
}
// Output the header
if( RC_BAD( rc = headerToBuf( TRUE, pDatabase->m_pucUpdBuffer,
&uiHeaderStorageSize, NULL, NULL)))
{
goto Exit;
}
// Replace the header
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( getNodeId(), &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
ui32BlkAddr = getBlkAddr();
uiOffsetIndex = getOffsetIndex();
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
ucKey, uiKeyLen,
pDatabase->m_pucUpdBuffer, uiHeaderStorageSize,
TRUE, TRUE, FALSE, &ui32BlkAddr, &uiOffsetIndex)))
{
goto Exit;
}
setBlkAddr( ui32BlkAddr);
setOffsetIndex( uiOffsetIndex);
// Clear the dirty flag and the new flag.
unsetNodeDirtyAndNew( pDb);
}
pDatabase->endPendingInput();
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
this, IX_ADD_NODE_VALUE, FALSE)))
{
goto Exit;
}
}
// Log the node to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
RFL_NODE_SET_BINARY_VALUE_PACKET, m_pCachedNode)))
{
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDatabase->endPendingInput();
}
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setBinaryFastPath(
IF_Db * ifpDb,
const void * pvValue,
FLMUINT uiLength,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_Database * pDatabase = pDb->m_pDatabase;
F_Rfl * pRfl = pDatabase->m_pRfl;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pNode = NULL;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
eDomNodeType eNodeType;
FLMBOOL bIsIndexed = TRUE;
FLMBOOL bStartOfUpdate = TRUE;
// Make sure a transaction is active
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Cannot set a value if input is still pending
if( pDatabase->m_pPendingInput)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// If this is an element node, we need to find or create
// the child data node
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
bMustAbortOnError = TRUE;
if( getDataChildCount() == 1)
{
// If this node only has one data child, delete the child and
// store the value directly on the element
if( RC_BAD( rc = pNode->deleteNode( ifpDb)))
{
goto Exit;
}
pNode->Release();
pNode = NULL;
}
else
{
rc = pNode->setBinaryFastPath( ifpDb, pucValue, uiLength, uiEncDefId);
goto Exit;
}
}
else if( eNodeType == ATTRIBUTE_NODE)
{
// Make sure the state of the node and database
// allow a value to be set.
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
{
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
if( RC_BAD( rc = m_pCachedNode->setBinary(
pDb, m_uiAttrNameId, pvValue, uiLength, uiEncDefId)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, m_uiAttrNameId)))
{
goto Exit;
}
goto Exit;
}
// If node is a text data type, convert the binary to base 64 encoding
// and store as text.
if( getDataType() == XFLM_TEXT_TYPE)
{
// Convert to base64 text and call the routine to set as native.
rc = storeBinaryAsText( (F_Db *)ifpDb, pvValue, uiLength, uiEncDefId);
goto Exit;
}
// Make sure the state of the node and database
// allow a value to be set.
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
if( getNameId())
{
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
else
{
bIsIndexed = FALSE;
}
setEncDefId( uiEncDefId);
if( calcDataBufSize( uiLength) > getDataBufSize())
{
if( RC_BAD( rc = resizeDataBuffer( uiLength, FALSE)))
{
goto Exit;
}
}
setDataLength( uiLength);
if( uiLength)
{
f_memcpy( getDataPtr(), pvValue, uiLength);
}
// Clear unwanted flags
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
// Log the node to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
RFL_NODE_SET_BINARY_VALUE_PACKET, m_pCachedNode)))
{
goto Exit;
}
Exit:
if( pNode)
{
pNode->Release();
}
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::clearNodeValue(
F_Db * pDb)
{
RCODE rc = NE_XFLM_OK;
F_Database * pDatabase = pDb->m_pDatabase;
F_Rfl * pRfl = pDatabase->m_pRfl;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
// Make sure a transaction is active
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Cannot clear a value if input is still pending
if( pDatabase->m_pPendingInput)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
bMustAbortOnError = TRUE;
if( RC_BAD( rc = setStorageValue( pDb, NULL, 0, 0, TRUE)))
{
goto Exit;
}
// Log the update to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeClearValue( pDb, getCollection(),
getNodeId(), m_uiAttrNameId)))
{
goto Exit;
}
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getIStream(
F_Db * pDb,
F_NodeBufferIStream * pStackStream,
IF_PosIStream ** ppIStream,
FLMUINT * puiDataType,
FLMUINT * puiDataLength)
{
RCODE rc = NE_XFLM_OK;
IF_PosIStream * pIStream = NULL;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode = this;
eDomNodeType eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
if( m_uiFlags & FDOM_VALUE_ON_DISK)
{
F_BTreeIStream * pBTreeIStream;
F_ENCDEF * pEncDef;
FLMUINT uiIVLen;
FLMUINT uiLen;
F_NODE_INFO nodeInfo;
FLMUINT uiTmpFlags;
if( eNodeType == ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = pDb->flushDirtyNode( this)))
{
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pNodePool->allocBTreeIStream(
&pBTreeIStream)))
{
goto Exit;
}
pIStream = pBTreeIStream;
if( RC_BAD( rc = pBTreeIStream->open( pDb, getCollection(),
getNodeId(), getBlkAddr(), getOffsetIndex())))
{
goto Exit;
}
// Skip the node header
if( RC_BAD( rc = flmReadNodeInfo( getCollection(), getNodeId(),
pBTreeIStream, (FLMUINT)pBTreeIStream->remainingSize(), TRUE,
&nodeInfo, &uiTmpFlags)))
{
goto Exit;
}
// Read the IV if data is encrypted
if( getEncDefId())
{
if( RC_BAD( rc = pDb->m_pDict->getEncDef( getEncDefId(), &pEncDef)))
{
goto Exit;
}
uiIVLen = pEncDef->pCcs->getIVLen();
flmAssert( uiIVLen == 8 || uiIVLen == 16);
if( RC_BAD( rc = pBTreeIStream->read( (char *)pBTreeIStream->m_ucIV,
uiIVLen, &uiLen)))
{
goto Exit;
}
flmAssert( uiLen == uiIVLen);
pBTreeIStream->m_bDataEncrypted = TRUE;
}
pBTreeIStream->m_uiEncDefId = getEncDefId();
pBTreeIStream->m_uiDataLength = getDataLength();
}
else
{
F_NodeBufferIStream * pNodeBufferIStream;
FLMUINT64 ui64TmpNodeId;
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
ui64TmpNodeId = getFirstChildId();
for( ;;)
{
if( !ui64TmpNodeId)
{
break;
}
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
getCollection(), ui64TmpNodeId, (IF_DOMNode **)&pNode)))
{
goto Exit;
}
if( pNode->getNodeType() == DATA_NODE)
{
pCachedNode = pNode->m_pCachedNode;
break;
}
ui64TmpNodeId = pNode->getNextSibId();
}
}
if( pStackStream)
{
pNodeBufferIStream = pStackStream;
pStackStream->AddRef();
flmAssert( !pStackStream->m_pCachedNode);
}
else
{
if( (pNodeBufferIStream = f_new F_NodeBufferIStream) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
pIStream = pNodeBufferIStream;
if( RC_BAD( rc = pNodeBufferIStream->open(
(const char *)pCachedNode->getDataPtr(),
pCachedNode->getDataLength())))
{
goto Exit;
}
if( !pStackStream)
{
pNodeBufferIStream->m_pCachedNode = pCachedNode;
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
pCachedNode->incrNodeUseCount();
pCachedNode->incrStreamUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
}
if( puiDataType)
{
*puiDataType = pCachedNode->getDataType();
}
if( puiDataLength)
{
*puiDataLength = pCachedNode->getDataLength();
}
*ppIStream = pIStream;
pIStream = NULL;
Exit:
if( pIStream)
{
pIStream->Release();
}
if( pNode)
{
pNode->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getRawIStream(
F_Db * pDb,
IF_PosIStream ** ppIStream)
{
RCODE rc = NE_XFLM_OK;
IF_PosIStream * pIStream = NULL;
F_BTreeIStream * pBTreeIStream;
eDomNodeType eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// Flush all dirty nodes out to the B-Tree
if( RC_BAD( rc = pDb->flushDirtyNode( this)))
{
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pNodePool->allocBTreeIStream(
&pBTreeIStream)))
{
goto Exit;
}
pIStream = pBTreeIStream;
if( RC_BAD( rc = pBTreeIStream->open( pDb, getCollection(),
getNodeId(), getBlkAddr(), getOffsetIndex())))
{
goto Exit;
}
*ppIStream = pIStream;
pIStream = NULL;
Exit:
if( pIStream)
{
pIStream->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getIStream(
F_Db * pDb,
F_NodeBufferIStream * pStackStream,
IF_PosIStream ** ppIStream,
FLMUINT * puiDataType,
FLMUINT * puiDataLength)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, NULL)))
{
goto Exit;
}
// Sync the node to make sure it is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
switch( getNodeType())
{
case DATA_NODE:
case COMMENT_NODE:
case ANNOTATION_NODE:
case CDATA_SECTION_NODE:
{
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb, pStackStream,
ppIStream, puiDataType, puiDataLength)))
{
goto Exit;
}
break;
}
case ELEMENT_NODE:
{
if( getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if( RC_BAD( rc = pNode->m_pCachedNode->getIStream( pDb,
pStackStream, ppIStream, puiDataType, puiDataLength)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb,
pStackStream, ppIStream, puiDataType, puiDataLength)))
{
goto Exit;
}
}
break;
}
case ATTRIBUTE_NODE:
{
if( RC_BAD( rc = m_pCachedNode->getIStream(
pDb, m_uiAttrNameId, pStackStream, ppIStream,
puiDataType, puiDataLength)))
{
goto Exit;
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getTextIStream(
F_Db * pDb,
F_NodeBufferIStream * pStackStream,
IF_PosIStream ** ppIStream,
FLMUINT * puiNumChars)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDataType;
*ppIStream = NULL;
*puiNumChars = 0;
if( RC_BAD( rc = getIStream( pDb, pStackStream, ppIStream, &uiDataType)))
{
goto Exit;
}
if( uiDataType != XFLM_TEXT_TYPE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
goto Exit;
}
// Skip the leading SEN so that the stream is positioned to
// read raw utf8.
if( (*ppIStream)->remainingSize())
{
if( RC_BAD( rc = f_readSEN( *ppIStream, puiNumChars)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc) && *ppIStream)
{
(*ppIStream)->Release();
*ppIStream = NULL;
*puiNumChars = 0;
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getNumber64(
F_Db * pDb,
FLMUINT64 * pui64Num,
FLMBOOL * pbNeg)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDataType;
FLMUINT64 ui64Num;
FLMBOOL bNeg;
F_DOMNode * pNode = NULL;
eDomNodeType eNodeType;
IF_PosIStream * pIStream = NULL;
F_NodeBufferIStream bufferIStream;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getNumber64(
pDb, m_uiAttrNameId, &ui64Num, &bNeg)))
{
goto Exit;
}
}
else if ( !getQuickNumber64( &ui64Num, &bNeg))
{
if( eNodeType == ELEMENT_NODE && getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
rc = pNode->getNumber64( pDb, pui64Num, pbNeg);
goto Exit;
}
else
{
if( RC_BAD( rc = getIStream( pDb, &bufferIStream,
&pIStream, &uiDataType)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsNumber( pIStream, uiDataType,
&ui64Num, &bNeg)))
{
goto Exit;
}
}
}
if( pui64Num)
{
*pui64Num = ui64Num;
}
if( pbNeg)
{
*pbNeg = bNeg;
}
Exit:
if( pIStream)
{
pIStream->Release();
}
if( pNode)
{
pNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Allocate data for a unicode element and retrieve it.
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getUnicode(
IF_Db * ifpDb,
FLMUNICODE ** ppuzUnicode)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiLen;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Get the unicode length (does not include NULL terminator)
if( RC_BAD( rc = getUnicodeChars( pDb, &uiLen)))
{
goto Exit;
}
if( uiLen)
{
FLMUINT uiBufSize = (uiLen + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = f_alloc( uiBufSize, ppuzUnicode)))
{
goto Exit;
}
if( RC_BAD( rc = getUnicode( pDb,
*ppuzUnicode, uiBufSize, 0, uiLen, &uiLen)))
{
goto Exit;
}
}
else
{
*ppuzUnicode = NULL;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getUnicode(
IF_Db * ifpDb,
FLMUNICODE * puzBuffer,
FLMUINT uiBufSize,
FLMUINT uiCharOffset,
FLMUINT uiMaxCharsRequested,
FLMUINT * puiCharsReturned,
FLMUINT * puiBufferBytesUsed)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDataType;
FLMUINT uiDataLength;
F_NodeBufferIStream bufferStream;
IF_PosIStream * pIStream = NULL;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = getIStream( pDb, &bufferStream,
&pIStream, &uiDataType, &uiDataLength)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsText(
pIStream, NULL, uiDataLength, uiDataType, puzBuffer,
uiBufSize, XFLM_UNICODE_TEXT,
uiMaxCharsRequested, uiCharOffset, puiCharsReturned,
puiBufferBytesUsed)))
{
goto Exit;
}
Exit:
if( pIStream)
{
pIStream->Release();
}
if( bStartedTrans)
{
pDb->abortTrans();
}
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getUnicode(
IF_Db * ifpDb,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiBufSize;
FLMUINT uiChars;
void * pvBuffer = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
pBuffer->truncateData( 0);
if( RC_BAD( rc = getUnicode( ifpDb, NULL, 0, 0, ~((FLMUINT)0), &uiChars)))
{
goto Exit;
}
uiBufSize = (uiChars + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getUnicode( ifpDb, (FLMUNICODE *)pvBuffer, uiBufSize, 0,
~((FLMUINT)0), NULL)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getUTF8(
IF_Db * ifpDb,
FLMBYTE * pszValue,
FLMUINT uiBufferSize,
FLMUINT uiCharOffset,
FLMUINT uiMaxCharsRequested,
FLMUINT * puiCharsReturned,
FLMUINT * puiBufferBytesUsed)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDataType;
FLMUINT uiDataLength;
F_DOMNode * pNode = NULL;
IF_PosIStream * pIStream = NULL;
F_NodeBufferIStream bufferIStream;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
switch( getNodeType())
{
case DATA_NODE:
case COMMENT_NODE:
case ANNOTATION_NODE:
case CDATA_SECTION_NODE:
{
pNode = this;
pNode->AddRef();
break;
}
case ATTRIBUTE_NODE:
{
pNode = this;
pNode->AddRef();
goto SlowDecode;
}
case ELEMENT_NODE:
{
if( getDataChildCount())
{
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
}
else
{
pNode = this;
pNode->AddRef();
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
if( (pNode->getModeFlags() & FDOM_VALUE_ON_DISK) ||
pNode->getDataType() != XFLM_TEXT_TYPE || uiCharOffset)
{
SlowDecode:
if( RC_BAD( rc = pNode->getIStream( pDb, &bufferIStream, &pIStream,
&uiDataType, &uiDataLength)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsText(
pIStream, NULL, uiDataLength,
uiDataType, pszValue, uiBufferSize, XFLM_UTF8_TEXT,
uiMaxCharsRequested, uiCharOffset, puiCharsReturned,
puiBufferBytesUsed)))
{
goto Exit;
}
}
else
{
const FLMBYTE * pucBuffer = pNode->getDataPtr();
const FLMBYTE * pucEnd = pucBuffer + pNode->getDataLength();
FLMUINT uiCharCount = 0;
FLMUINT uiStrByteLen = 0;
if( pucBuffer)
{
if( RC_BAD( rc = f_decodeSEN( &pucBuffer, pucEnd, &uiCharCount)))
{
goto Exit;
}
uiStrByteLen = (FLMUINT)(pucEnd - pucBuffer);
}
if( uiCharCount > uiMaxCharsRequested ||
(pszValue && uiBufferSize < uiStrByteLen))
{
goto SlowDecode;
}
if( pszValue)
{
if( uiStrByteLen)
{
f_memcpy( pszValue, pucBuffer, uiStrByteLen);
}
else if( uiBufferSize > 0)
{
*pszValue = 0;
}
}
if( puiCharsReturned)
{
*puiCharsReturned = uiCharCount;
}
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = uiStrByteLen;
}
}
Exit:
if( pIStream)
{
pIStream->Release();
}
if( pNode)
{
pNode->Release();
}
if( bStartedTrans)
{
pDb->abortTrans();
}
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getUTF8(
IF_Db * ifpDb,
FLMBYTE ** ppszUTF8)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiBufSize;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getUTF8( ifpDb, NULL, 0, 0,
FLM_MAX_UINT, NULL, &uiBufSize)))
{
goto Exit;
}
if( uiBufSize)
{
if( RC_BAD( rc = f_alloc( uiBufSize, ppszUTF8)))
{
goto Exit;
}
if( RC_BAD( rc = getUTF8( ifpDb, *ppszUTF8, uiBufSize, 0,
FLM_MAX_UINT, NULL, NULL)))
{
goto Exit;
}
}
else
{
*ppszUTF8 = NULL;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getUTF8(
IF_Db * ifpDb,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiBufSize;
void * pvBuffer = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
pBuffer->truncateData( 0);
if( RC_BAD( rc = getUTF8( ifpDb, NULL, 0, 0,
FLM_MAX_UINT, NULL, &uiBufSize)))
{
goto Exit;
}
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getUTF8( ifpDb, (FLMBYTE *)pvBuffer, uiBufSize, 0,
FLM_MAX_UINT, NULL, NULL)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getBinary(
IF_Db * ifpDb,
void * pvValue,
FLMUINT uiByteOffset,
FLMUINT uiBytesRequested,
FLMUINT * puiBytesReturned)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
IF_PosIStream * pIStream = NULL;
IF_IStream * pDecoderStream = NULL;
F_NodeBufferIStream bufferIStream;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiTmp;
FLMUINT uiDataType;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// If a NULL buffer is passed in, just return the
// data length
if( !pucValue)
{
if( RC_BAD( rc = getDataLength( pDb, &uiTmp)))
{
goto Exit;
}
if( uiByteOffset <= uiTmp)
{
*puiBytesReturned = uiTmp - uiByteOffset;
}
else
{
*puiBytesReturned = 0;
}
goto Exit;
}
if( RC_BAD( rc = getIStream( pDb, &bufferIStream, &pIStream, &uiDataType)))
{
goto Exit;
}
if( uiDataType == XFLM_TEXT_TYPE)
{
F_AsciiStorageStream asciiStream;
if( RC_BAD( rc = asciiStream.open( pIStream)))
{
goto Exit;
}
else
{
if( RC_BAD( rc = FlmOpenBase64DecoderIStream(
&asciiStream, &pDecoderStream)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsBinary(
pDecoderStream, (FLMBYTE *)pucValue,
uiBytesRequested, uiByteOffset, puiBytesReturned)))
{
goto Exit;
}
}
}
else
{
if( RC_BAD( rc = flmReadStorageAsBinary(
pIStream, (FLMBYTE *)pucValue,
uiBytesRequested, uiByteOffset, puiBytesReturned)))
{
goto Exit;
}
}
Exit:
if( pDecoderStream)
{
pDecoderStream->Release();
}
if( pIStream)
{
pIStream->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getBinary(
IF_Db * ifpDb,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiBufSize;
void * pvBuffer = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
pBuffer->truncateData( 0);
if( RC_BAD( rc = getBinary( ifpDb, NULL, 0, FLM_MAX_UINT, &uiBufSize)))
{
goto Exit;
}
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getBinary( ifpDb, pvBuffer, 0, uiBufSize, NULL)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getAttributeValueNumber(
F_Db * pDb,
FLMUINT uiAttrName,
FLMUINT64 * pui64Num,
FLMBOOL * pbNeg)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->getNumber64( pDb, uiAttrName,
pui64Num, pbNeg)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getAttributeValueText(
IF_Db * ifpDb,
FLMUINT uiAttrName,
eXFlmTextType eTextType,
void * pvBuffer,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned,
FLMUINT * puiBufferBytesUsed)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucStorageData = NULL;
FLMUINT uiDataType;
FLMUINT uiDataLength;
F_AttrItem * pAttrItem;
IF_PosIStream * pIStream = NULL;
F_NodeBufferIStream bufferIStream;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( (pAttrItem = m_pCachedNode->getAttribute( uiAttrName, NULL)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( !pAttrItem->m_uiEncDefId)
{
pucStorageData = pAttrItem->getAttrDataPtr();
uiDataLength = pAttrItem->getAttrDataLength();
uiDataType = pAttrItem->m_uiDataType;
if( uiDataType == XFLM_TEXT_TYPE && eTextType == XFLM_UTF8_TEXT)
{
const FLMBYTE * pucStart = pucStorageData;
const FLMBYTE * pucEnd = pucStart + uiDataLength;
FLMUINT uiCharCount = 0;
FLMUINT uiStrByteLen = 0;
if( pucStart)
{
if( RC_BAD( rc = f_decodeSEN( &pucStart, pucEnd, &uiCharCount)))
{
goto Exit;
}
uiStrByteLen = (FLMUINT)(pucEnd - pucStart);
if( uiBufSize < uiStrByteLen)
{
goto SlowDecode;
}
f_memcpy( pvBuffer, pucStart, uiStrByteLen);
}
if( puiCharsReturned)
{
*puiCharsReturned = uiCharCount;
}
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = uiStrByteLen;
}
goto Exit;
}
}
else
{
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb, uiAttrName,
&bufferIStream, &pIStream, &uiDataType, &uiDataLength)))
{
goto Exit;
}
}
SlowDecode:
if( RC_BAD( rc = flmReadStorageAsText(
pIStream, pucStorageData, uiDataLength, uiDataType, pvBuffer,
uiBufSize, eTextType, FLM_MAX_UINT, 0, puiCharsReturned,
puiBufferBytesUsed)))
{
goto Exit;
}
Exit:
if( pIStream)
{
pIStream->Release();
}
if( bStartedTrans)
{
pDb->abortTrans();
}
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueUnicode(
IF_Db * ifpDb,
FLMUINT uiAttrName,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBufSize;
void * pvBuffer = NULL;
pBuffer->truncateData( 0);
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
NULL, 0, NULL, &uiBufSize)))
{
goto Exit;
}
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
(FLMUNICODE *)pvBuffer, uiBufSize, NULL)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueUnicode(
IF_Db * ifpDb,
FLMUINT uiAttrName,
FLMUNICODE ** ppuzUnicode)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBufSize;
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
NULL, 0, NULL, &uiBufSize)))
{
goto Exit;
}
if( uiBufSize)
{
if( RC_BAD( rc = f_alloc( uiBufSize, ppuzUnicode)))
{
goto Exit;
}
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
*ppuzUnicode, uiBufSize)))
{
goto Exit;
}
}
else
{
*ppuzUnicode = NULL;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueUTF8(
IF_Db * ifpDb,
FLMUINT uiAttrName,
FLMBYTE ** ppszValue)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBufSize;
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
NULL, 0, NULL, &uiBufSize)))
{
goto Exit;
}
if( uiBufSize)
{
if( RC_BAD( rc = f_alloc( uiBufSize, ppszValue)))
{
goto Exit;
}
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
*ppszValue, uiBufSize)))
{
goto Exit;
}
}
else
{
*ppszValue = NULL;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueUTF8(
IF_Db * ifpDb,
FLMUINT uiAttrName,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBufSize;
void * pvBuffer = NULL;
pBuffer->truncateData( 0);
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
NULL, 0, NULL, &uiBufSize)))
{
goto Exit;
}
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
(FLMBYTE *)pvBuffer, uiBufSize)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueBinary(
IF_Db * ifpDb,
FLMUINT uiAttrName,
void * pvValue,
FLMUINT uiBufferSize,
FLMUINT * puiLength)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->getBinary( pDb, uiAttrName,
pvValue, uiBufferSize, puiLength)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->abortTrans();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getAttributeValueBinary(
IF_Db * ifpDb,
FLMUINT uiAttrName,
F_DynaBuf * pBuffer)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiBufSize;
void * pvBuffer = NULL;
pBuffer->truncateData( 0);
if( RC_BAD( rc = getAttributeValueBinary( ifpDb, uiAttrName, NULL, 0,
&uiBufSize)))
{
goto Exit;
}
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = getAttributeValueBinary( ifpDb, uiAttrName, pvBuffer,
uiBufSize, &uiBufSize)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
ifpDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::setAttributeValueNumber(
IF_Db * ifpDb,
FLMUINT uiAttrName,
FLMINT64 i64Value,
FLMUINT64 ui64Value,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pAttribute = NULL;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
FLMBOOL bNeg = FALSE;
FLMBOOL bIsInIndexDef = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
{
goto Exit;
}
if( bIsInIndexDef)
{
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
(IF_DOMNode **)&pAttribute)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pAttribute->setNumber64( pDb, i64Value,
ui64Value, uiEncDefId)))
{
goto Exit;
}
}
else
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( !ui64Value)
{
if( i64Value < 0)
{
bNeg = TRUE;
ui64Value = (FLMUINT64)-i64Value;
}
else
{
ui64Value = (FLMUINT64)i64Value;
}
}
if( RC_BAD( rc = m_pCachedNode->setNumber64( pDb,
uiAttrName, ui64Value, bNeg, uiEncDefId)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, uiAttrName)))
{
goto Exit;
}
}
if( bStartedTrans)
{
bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if( pAttribute)
{
pAttribute->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::setAttributeValueUnicode(
IF_Db * ifpDb,
FLMUINT uiAttrName,
const FLMUNICODE * puzValue,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pAttribute = NULL;
FLMBOOL bStartedTrans = FALSE;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bMustAbortOnError = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
(IF_DOMNode **)&pAttribute)))
{
goto Exit;
}
if( RC_BAD( rc = pAttribute->setUnicode( (IF_Db *)pDb, puzValue, 0,
TRUE, uiEncDefId)))
{
goto Exit;
}
if( bStartedTrans)
{
bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if( pAttribute)
{
pAttribute->Release();
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::setAttributeValueBinary(
IF_Db * ifpDb,
FLMUINT uiAttrName,
const void * pvValue,
FLMUINT uiLength,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pAttribute = NULL;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
FLMBOOL bIsInIndexDef = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
{
goto Exit;
}
if( bIsInIndexDef)
{
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
(IF_DOMNode **)&pAttribute)))
{
goto Exit;
}
if( RC_BAD( rc = pAttribute->setBinary(
(IF_Db *)pDb, (FLMBYTE *)pvValue, uiLength, TRUE, uiEncDefId)))
{
goto Exit;
}
}
else
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = m_pCachedNode->setBinary( pDb,
uiAttrName, pvValue, uiLength, uiEncDefId)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, uiAttrName)))
{
goto Exit;
}
}
if( bStartedTrans)
{
bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if( pAttribute)
{
pAttribute->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::setAttributeValueUTF8(
IF_Db * ifpDb,
FLMUINT uiAttrName,
const FLMBYTE * pucValue,
FLMUINT uiLength,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pAttribute = NULL;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiNumCharsInBuffer;
FLMUINT uiRflToken = 0;
FLMBOOL bIsInIndexDef = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
{
goto Exit;
}
if( bIsInIndexDef)
{
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
(IF_DOMNode **)&pAttribute)))
{
goto Exit;
}
if( RC_BAD( rc = pAttribute->setUTF8(
(IF_Db *)pDb, pucValue, uiLength, TRUE, uiEncDefId)))
{
goto Exit;
}
}
else
{
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = f_getUTF8Length( pucValue, uiLength,
&uiLength, &uiNumCharsInBuffer)))
{
goto Exit;
}
if( RC_BAD( m_pCachedNode->setUTF8( pDb, uiAttrName, pucValue,
uiLength, uiNumCharsInBuffer, uiEncDefId)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the value to the RFL
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
m_pCachedNode, uiAttrName)))
{
goto Exit;
}
}
if( bStartedTrans)
{
bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if( pAttribute)
{
pAttribute->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Delete a node and all of its child/descendant-nodes.
NOTE: If the cannot-delete bit or read-only bit is set on the node, the delete
is not allowed. However, the child/descendant-nodes cannot-delete and
read-only bits will NOT be checked. If a parent node can be deleted,
then by definition all of its child/descendant nodes can also be deleted.
******************************************************************************/
RCODE F_DOMNode::deleteNode(
IF_Db * ifpDb)
{
RCODE rc = NE_XFLM_OK;
FLMUINT64 ui64CurNode;
F_DOMNode * pCurNode = NULL;
F_DOMNode * pParentNode = NULL;
F_DOMNode * pTmpNode = NULL;
FLMBOOL bMustAbortOnError = FALSE;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMBOOL bStartOfUpdate;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCollection;
FLMUINT uiFlags = 0;
FLMUINT uiRflToken = 0;
FLMUINT64 ui64MyNodeId;
FLMBOOL bIsIndexed;
eDomNodeType eNodeType;
// Start a transaction if necessary
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
uiCollection = getCollection();
eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = pDb->getNode( uiCollection, getParentId(), &pCurNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
rc = pCurNode->deleteAttribute( pDb, m_uiAttrNameId);
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// See if the node can be deleted
if( getModeFlags() & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE))
{
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
goto Exit;
}
if( isRootNode())
{
// Set flags to FLM_UPD_INTERNAL_CHANGE to prevent the node
// from being added to the document list or constraint
// checking list - no need since we are deleting the root node.
uiFlags = FLM_UPD_INTERNAL_CHANGE;
// If we are deleting the root node of a document in the dictionary
// collection, before deleting it, we must allow the dictionary
// to be updated.
if( uiCollection == XFLM_DICT_COLLECTION)
{
// Call dictDocumentDone with bDeleting flag set to TRUE.
if( RC_BAD( rc = pDb->dictDocumentDone(
getNodeId(), TRUE, NULL)))
{
goto Exit;
}
pDb->m_pDatabase->m_DocumentList.removeNode( uiCollection,
getNodeId(), 0);
}
}
bMustAbortOnError = TRUE;
// Traverse the tree and delete all nodes below and including the
// node we are starting on.
ui64MyNodeId = ui64CurNode = getNodeId();
bStartOfUpdate = TRUE;
for (;;)
{
if (RC_BAD( rc = pDb->getNode( uiCollection, ui64CurNode, &pCurNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
// If the current node has children, go to those children
if( pCurNode->getLastChildId())
{
ui64CurNode = pCurNode->getLastChildId();
}
else if( pCurNode->hasAttributes())
{
if( pCurNode->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
flmAssert( pCurNode->m_pCachedNode->m_uiAttrCount);
if( RC_BAD( rc = pCurNode->deleteAttributes( pDb, 0, uiFlags)))
{
goto Exit;
}
}
else if (pCurNode->getAnnotationId())
{
ui64CurNode = pCurNode->getAnnotationId();
}
else
{
// Node has no children, no attributes, and no annotations. It is
// therefore a leaf node that can be purged.
FLMUINT64 ui64ParentId;
FLMBOOL bWasDataNode = FALSE;
// Save the node's parent node before purging it. That is the
// node we want to return to.
if( RC_BAD( rc = pCurNode->getParentId( pDb, &ui64ParentId)))
{
goto Exit;
}
// Update the index
if( pCurNode->getNodeType() == DATA_NODE)
{
bWasDataNode = TRUE;
// Data nodes MUST be children to an element node.
flmAssert( ui64ParentId);
if (RC_BAD( rc = pDb->getNode( uiCollection, ui64ParentId,
(IF_DOMNode **)&pParentNode)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pParentNode, IX_DEL_NODE_VALUE,
bStartOfUpdate)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pCurNode, IX_DEL_NODE_VALUE,
bStartOfUpdate, &bIsIndexed)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
if( bIsIndexed)
{
if (RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pCurNode, IX_UNLINK_NODE,
bStartOfUpdate)))
{
goto Exit;
}
}
}
bStartOfUpdate = FALSE;
flmAssert( pCurNode->getNodeType() != ATTRIBUTE_NODE);
if (RC_BAD( rc = pCurNode->unlinkNode( pDb, uiFlags)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->purgeNode( uiCollection, ui64CurNode)))
{
goto Exit;
}
pCurNode->Release();
pCurNode = NULL;
if( bWasDataNode)
{
flmAssert( pParentNode);
if( RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pParentNode, IX_ADD_NODE_VALUE,
bStartOfUpdate)))
{
goto Exit;
}
bStartOfUpdate = FALSE;
}
// Did we just delete the primary target or root node?
// Do NOT access m_pCachedNode after this point, because it
// may have been set to NULL by the call to purgeNode.
if (ui64CurNode == ui64MyNodeId || !ui64ParentId)
{
break;
}
// Go back to the parent node.
ui64CurNode = ui64ParentId;
}
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeDelete( pDb, uiCollection, ui64MyNodeId)))
{
goto Exit;
}
Exit:
if( pTmpNode)
{
pTmpNode->Release();
}
if( pCurNode)
{
pCurNode->Release();
}
if( pParentNode)
{
pParentNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::deleteChildren(
IF_Db * ifpDb,
FLMUINT uiNameId)
{
RCODE rc = NE_XFLM_OK;
FLMUINT64 ui64NextNode;
F_DOMNode * pCurNode = NULL;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiCollection;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiRflToken = 0;
eDomNodeType eNodeType;
// Start a transaction if necessary
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
uiCollection = getCollection();
eNodeType = getNodeType();
// Not supported on attribute nodes
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// See if the node can be deleted
if( getModeFlags() & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE))
{
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
goto Exit;
}
// Turn of RFL logging
pRfl->disableLogging( &uiRflToken);
// Iterate over the children
bMustAbortOnError = TRUE;
ui64NextNode = getFirstChildId();
while( ui64NextNode)
{
if( RC_BAD( rc = pDb->getNode( uiCollection,
ui64NextNode, XFLM_EXACT, &pCurNode)))
{
goto Exit;
}
ui64NextNode = pCurNode->getNextSibId();
if( !uiNameId || uiNameId == pCurNode->getNameId())
{
if( RC_BAD( rc = pCurNode->deleteNode( pDb)))
{
goto Exit;
}
}
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeChildrenDelete(
pDb, uiCollection, getNodeId(), uiNameId)))
{
goto Exit;
}
Exit:
if( pCurNode)
{
pCurNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::_syncFromDb(
F_Db * pDb)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDOMNode = this;
// If we get to this point, we are going to read the node
// from the database. This instance of the node should
// not be dirty.
flmAssert( !nodeIsDirty());
// Should not have any input streams open on the cached node
if( getStreamUseCount())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->retrieveNode( pDb,
getCollection(), m_pCachedNode->getNodeId(), &pDOMNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DOM_NODE_DELETED);
}
goto Exit;
}
if( m_uiAttrNameId)
{
if( !m_pCachedNode->m_uiAttrCount ||
!m_pCachedNode->getAttribute( m_uiAttrNameId, NULL))
{
rc = RC_SET( NE_XFLM_DOM_NODE_DELETED);
goto Exit;
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getFirstAttribute(
IF_Db * ifpDb,
IF_DOMNode ** ifppAttr)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pAttrNode = NULL;
F_AttrItem * pAttrItem;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( (pAttrItem = m_pCachedNode->getFirstAttribute()) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttrNode->m_pCachedNode = m_pCachedNode;
m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
if( ifppAttr)
{
if( *ifppAttr)
{
(*ifppAttr)->Release();
}
*ifppAttr = (IF_DOMNode *)pAttrNode;
pAttrNode = NULL;
}
Exit:
if( pAttrNode)
{
pAttrNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getLastAttribute(
IF_Db * ifpDb,
IF_DOMNode ** ifppAttr)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pAttrNode = NULL;
F_AttrItem * pAttrItem;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( (pAttrItem = m_pCachedNode->getLastAttribute()) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttrNode->m_pCachedNode = m_pCachedNode;
m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
if( ifppAttr)
{
if( *ifppAttr)
{
(*ifppAttr)->Release();
}
*ifppAttr = (IF_DOMNode *)pAttrNode;
pAttrNode = NULL;
}
Exit:
if( pAttrNode)
{
pAttrNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::deleteAttribute(
IF_Db * ifpDb,
FLMUINT uiAttrName)
{
RCODE rc = NE_XFLM_OK;
if( !uiAttrName)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = deleteAttributes( (F_Db *)ifpDb,
uiAttrName, 0)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::deleteAttributes(
F_Db * pDb,
FLMUINT uiAttrToDelete,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiCollection;
FLMUINT uiAttrName;
F_DOMNode * pAttrNode = NULL;
F_AttrItem * pAttrItem;
FLMUINT uiPos;
FLMBOOL bIsIndexed;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Disable logging
pRfl->disableLogging( &uiRflToken);
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( !m_pCachedNode->m_uiAttrCount)
{
goto Exit;
}
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
uiCollection = getCollection();
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttrNode->m_pCachedNode = m_pCachedNode;
m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
for( ;;)
{
if( !uiAttrToDelete)
{
pAttrItem = m_pCachedNode->getFirstAttribute();
uiPos = 0;
}
else
{
if( (pAttrItem = m_pCachedNode->getAttribute( uiAttrToDelete,
&uiPos)) == NULL)
{
break;
}
}
if( uiAttrToDelete &&
(pAttrItem->m_uiFlags & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
goto Exit;
}
uiAttrName = pAttrItem->m_uiNameId;
pAttrNode->m_uiAttrNameId = uiAttrName;
if( RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pAttrNode, IX_DEL_NODE_VALUE,
TRUE, &bIsIndexed)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
uiCollection, pAttrNode, IX_UNLINK_NODE, FALSE)))
{
goto Exit;
}
}
// Free the attribute
if (RC_BAD( rc = m_pCachedNode->freeAttribute( pAttrItem, uiPos)))
{
goto Exit;
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttributeDelete( pDb, uiCollection,
getNodeId(), uiAttrName)))
{
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
if( !m_pCachedNode->m_uiAttrCount)
{
break;
}
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, uiFlags)))
{
goto Exit;
}
if( bStartedTrans)
{
bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if( pAttrNode)
{
pAttrNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::hasAttribute(
IF_Db * ifpDb,
FLMUINT uiNameId,
IF_DOMNode ** ifppAttr)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_DOMNode * pAttrNode = NULL;
F_AttrItem * pAttrItem;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if (RC_BAD( rc = checkAttrList()))
{
goto Exit;
}
if( (pAttrItem = m_pCachedNode->getAttribute( uiNameId, NULL)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( ifppAttr)
{
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttrNode->m_pCachedNode = m_pCachedNode;
m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
if( *ifppAttr)
{
(*ifppAttr)->Release();
}
*ifppAttr = (IF_DOMNode *)pAttrNode;
pAttrNode = NULL;
}
Exit:
if( pAttrNode)
{
pAttrNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::insertChildElm(
FLMUINT uiChildElmOffset,
FLMUINT uiChildElmNameId,
FLMUINT64 ui64ChildElmNodeId)
{
RCODE rc = NE_XFLM_OK;
NODE_ITEM * pChildElmNode;
if( RC_BAD( rc = resizeChildElmList( m_nodeInfo.uiChildElmCount + 1, FALSE)))
{
goto Exit;
}
// Remember, m_nodeInfo.uiChildElmCount has been incremented by
// resizeChildElmList, so there really isn't anything in the
// m_nodeInfo.uiChildElmCount - 1 slot.
pChildElmNode = &m_pNodeList [ uiChildElmOffset];
if( m_nodeInfo.uiChildElmCount > 1 &&
uiChildElmOffset < m_nodeInfo.uiChildElmCount - 1)
{
f_memmove( &m_pNodeList [ uiChildElmOffset + 1], pChildElmNode,
sizeof( NODE_ITEM) * (m_nodeInfo.uiChildElmCount -
uiChildElmOffset - 1));
}
pChildElmNode->uiNameId = uiChildElmNameId;
pChildElmNode->ui64NodeId = ui64ChildElmNodeId;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::createAttribute(
IF_Db * ifpDb,
FLMUINT uiNameId,
IF_DOMNode ** ifppAttr)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartedTrans = FALSE;
F_AttrElmInfo attrInfo;
F_DOMNode * pAttr = NULL;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMUINT uiRflToken = 0;
F_AttrItem * pAttrItem = NULL;
FLMBOOL bCreatedNewAttr = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Disable logging
pRfl->disableLogging( &uiRflToken);
// Make sure our copy of the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// If this isn't an element node, return an error
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Force the transaction to abort on error beyond this point
bMustAbortOnError = TRUE;
// Check the attribute state
if( RC_BAD( rc = pDb->checkAndUpdateState(
ATTRIBUTE_NODE, uiNameId)))
{
goto Exit;
}
// Retrieve or create the attribute list node
if( !m_pCachedNode->m_uiAttrCount ||
(pAttrItem = m_pCachedNode->getAttribute( uiNameId, NULL)) == NULL)
{
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->createAttribute(
pDb, uiNameId, &pAttrItem)))
{
goto Exit;
}
bCreatedNewAttr = TRUE;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttr->m_pCachedNode = m_pCachedNode;
m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
pAttr->m_uiAttrNameId = uiNameId;
if( bCreatedNewAttr)
{
// Update the element.
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
// Update the indexes
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
pAttr, IX_LINK_AND_ADD_NODE, TRUE)))
{
goto Exit;
}
// Log the attribute create
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logAttributeCreate(
pDb, getCollection(), getNodeId(), uiNameId, 0)))
{
goto Exit;
}
}
if( ifppAttr)
{
if( *ifppAttr)
{
(*ifppAttr)->Release();
}
*ifppAttr = (IF_DOMNode *)pAttr;
pAttr = NULL;
}
Exit:
if( pAttr)
{
pAttr->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( RC_BAD( rc) && bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::createNode(
IF_Db * ifpDb,
eDomNodeType eNodeType,
FLMUINT uiNameId,
eNodeInsertLoc eLocation,
IF_DOMNode ** ifppNewNode,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
F_DOMNode * pNewNode = NULL;
F_CachedNode * pNewCachedNode;
F_DOMNode * pRefNode = NULL;
F_DOMNode * pNewParent = NULL;
FLMUINT uiDataType = XFLM_NODATA_TYPE;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiRflToken = 0;
// Not supported for attributes
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// Make sure an update transaction is active
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of this node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Make sure the node type is valid
if( eLocation == XFLM_FIRST_CHILD || eLocation == XFLM_LAST_CHILD)
{
if( RC_BAD( rc = isChildTypeValid( eNodeType)))
{
goto Exit;
}
}
else if( eLocation == XFLM_PREV_SIB || eLocation == XFLM_NEXT_SIB)
{
if( eNodeType != ELEMENT_NODE && eNodeType != DATA_NODE &&
eNodeType != COMMENT_NODE && eNodeType != CDATA_SECTION_NODE &&
eNodeType != PROCESSING_INSTRUCTION_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If the user is requesting a specific nodeId, then make sure
// the node is not already in use.
if( pui64NodeId)
{
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
{
if( RC_BAD( rc = pDb->getNode( getCollection(), *pui64NodeId, &pNewNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
else
{
// Already in use
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
else if( *pui64NodeId)
{
// Set to zero so we don't use it. We will return the
// new nodeId.
*pui64NodeId = 0;
}
}
// Look at the node's state (checking, etc.) and verify that
// the node's name ID is valid
//
// IMPORTANT NOTE: checkAndUpdateState may change m_pDict if it ends
// up calling changeItemState
if( RC_BAD( rc = pDb->checkAndUpdateState( eNodeType, uiNameId)))
{
goto Exit;
}
// Create the new node.
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
getCollection(),
(FLMUINT64)(pui64NodeId
? *pui64NodeId
: (FLMUINT64)0),
&pNewNode)))
{
goto Exit;
}
pNewCachedNode = pNewNode->m_pCachedNode;
if( eNodeType == DATA_NODE)
{
flmAssert( getNodeType() == ELEMENT_NODE);
uiNameId = getNameId();
}
if( eNodeType == ELEMENT_NODE || eNodeType == DATA_NODE)
{
F_AttrElmInfo elmInfo;
if( RC_BAD( rc = pDb->m_pDict->getElement( pDb, uiNameId, &elmInfo)))
{
goto Exit;
}
uiDataType = elmInfo.m_uiDataType;
// Is this a node whose child elements must all be unique?
if( eNodeType == ELEMENT_NODE &&
elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
{
flmAssert( uiDataType == XFLM_NODATA_TYPE);
pNewCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
}
}
else
{
uiDataType = XFLM_NODATA_TYPE;
uiNameId = 0;
}
pNewCachedNode->setNodeType( eNodeType);
pNewCachedNode->setDocumentId( getDocumentId());
pNewCachedNode->setDataType( uiDataType);
if( uiNameId)
{
pNewCachedNode->setNameId( uiNameId);
}
if( RC_BAD( rc = pDb->updateNode( pNewCachedNode, FLM_UPD_ADD)))
{
goto Exit;
}
if( eNodeType == ELEMENT_NODE)
{
if( RC_BAD( rc = pDb->updateIndexKeys(
pNewCachedNode->getCollection(),
pNewNode, IX_ADD_NODE_VALUE, TRUE)))
{
goto Exit;
}
}
switch( eLocation)
{
case XFLM_FIRST_CHILD:
{
pNewParent = this;
pNewParent->AddRef();
if( getFirstChildId())
{
if( RC_BAD( rc = pDb->getNode(
getCollection(),
getFirstChildId(), &pRefNode)))
{
goto Exit;
}
}
break;
}
case XFLM_LAST_CHILD:
{
pNewParent = this;
pNewParent->AddRef();
break;
}
case XFLM_PREV_SIB:
{
if( !getParentId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
&pNewParent)))
{
goto Exit;
}
pRefNode = this;
pRefNode->AddRef();
break;
}
case XFLM_NEXT_SIB:
{
if( !getParentId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
&pNewParent)))
{
goto Exit;
}
if( getNextSibId())
{
if( RC_BAD( rc = pDb->getNode( getCollection(),
getNextSibId(), &pRefNode)))
{
goto Exit;
}
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
if( RC_BAD( rc = pNewParent->insertBefore( pDb, pNewNode, pRefNode)))
{
goto Exit;
}
if( pui64NodeId)
{
*pui64NodeId = pNewCachedNode->getNodeId();
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeCreate(
pDb, pNewNode->getCollection(), getNodeId(),
eNodeType, uiNameId, eLocation, pNewNode->getNodeId())))
{
goto Exit;
}
if( ifppNewNode)
{
if( *ifppNewNode)
{
(*ifppNewNode)->Release();
}
*ifppNewNode = (IF_DOMNode *)pNewNode;
pNewNode = NULL;
}
Exit:
if( pNewNode)
{
pNewNode->Release();
}
if( pRefNode)
{
pRefNode->Release();
}
if( pNewParent)
{
pNewParent->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::createChildElement(
IF_Db * ifpDb,
FLMUINT uiNameId,
eNodeInsertLoc eLocation,
IF_DOMNode ** ifppNewNode,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
F_DOMNode * pTmpNode = NULL;
F_DOMNode * pNewNode = NULL;
F_CachedNode * pNewCachedNode;
F_AttrElmInfo elmInfo;
eDomNodeType eThisNodeType;
FLMUINT uiCollection;
FLMUINT uiDataType = XFLM_NODATA_TYPE;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiRflToken = 0;
FLMBOOL bIsIndexed;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of this node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// Make sure the insert location is supported
if( eLocation != XFLM_FIRST_CHILD && eLocation != XFLM_LAST_CHILD)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Make sure the node type is valid
eThisNodeType = getNodeType();
if( eThisNodeType != ELEMENT_NODE && eThisNodeType != DOCUMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// A document node can only have one element node
if( eThisNodeType == DOCUMENT_NODE && getFirstChildId())
{
if( RC_BAD( rc = getChild( ifpDb, ELEMENT_NODE,
(IF_DOMNode **)&pTmpNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
goto Exit;
}
}
// Setup misc. variables
uiCollection = getCollection();
// If the user is requesting a specific nodeId, then make sure
// the node is not already in use.
if( pui64NodeId)
{
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
{
if( RC_OK( rc = pDb->getNode( uiCollection, *pui64NodeId, &pNewNode)))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
else if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
else if( *pui64NodeId)
{
*pui64NodeId = 0;
}
}
// Check the element's state
if( RC_BAD( rc = pDb->checkAndUpdateState( ELEMENT_NODE, uiNameId)))
{
goto Exit;
}
// Create the new node.
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
uiCollection,
(FLMUINT64)(pui64NodeId
? *pui64NodeId
: (FLMUINT64)0),
&pNewNode)))
{
goto Exit;
}
pNewCachedNode = pNewNode->m_pCachedNode;
// Make sure the parent node (this) can be updated
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
// Does the parent expect all children to be unique?
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
{
FLMUINT uiInsertPos;
if( m_pCachedNode->findChildElm( uiNameId, &uiInsertPos))
{
rc = RC_SET( NE_XFLM_DOM_DUPLICATE_ELEMENT);
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->insertChildElm( uiInsertPos,
uiNameId, pNewCachedNode->getNodeId())))
{
goto Exit;
}
}
// Update the element's state
if( RC_BAD( rc = pDb->m_pDict->getElement( pDb, uiNameId, &elmInfo)))
{
goto Exit;
}
uiDataType = elmInfo.m_uiDataType;
// Is this a node whose children must all be unique?
if( elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
{
flmAssert( uiDataType == XFLM_NODATA_TYPE);
pNewCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
}
pNewCachedNode->setNodeType( ELEMENT_NODE);
pNewCachedNode->setParentId( getNodeId());
pNewCachedNode->setDocumentId( getDocumentId());
pNewCachedNode->setDataType( uiDataType);
pNewCachedNode->setNameId( uiNameId);
// Set the sibling pointers
if( eLocation == XFLM_LAST_CHILD)
{
if( getLastChildId())
{
if( RC_BAD( rc = pDb->getNode( uiCollection,
getLastChildId(), &pTmpNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
flmAssert( pTmpNode->getNextSibId() == 0);
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setNextSibId( pNewCachedNode->getNodeId());
pNewCachedNode->setPrevSibId( getLastChildId());
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, 0)))
{
goto Exit;
}
}
else
{
setFirstChildId( pNewCachedNode->getNodeId());
}
setLastChildId( pNewCachedNode->getNodeId());
}
else
{
flmAssert( eLocation == XFLM_FIRST_CHILD);
if( getFirstChildId())
{
if( RC_BAD( rc = pDb->getNode(
uiCollection, getFirstChildId(), &pTmpNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
flmAssert( pTmpNode->getPrevSibId() == 0);
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
{
goto Exit;
}
pTmpNode->setPrevSibId( pNewCachedNode->getNodeId());
pNewCachedNode->setNextSibId( getFirstChildId());
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, 0)))
{
goto Exit;
}
}
else
{
setLastChildId( pNewCachedNode->getNodeId());
}
setFirstChildId( pNewCachedNode->getNodeId());
}
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateNode( pNewCachedNode, FLM_UPD_ADD)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
pNewNode, IX_ADD_NODE_VALUE, TRUE, &bIsIndexed)))
{
goto Exit;
}
if( bIsIndexed)
{
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
pNewNode, IX_LINK_NODE, FALSE, &bIsIndexed)))
{
goto Exit;
}
}
if( pui64NodeId)
{
*pui64NodeId = pNewCachedNode->getNodeId();
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeCreate( pDb, uiCollection,
pNewCachedNode->getParentId(),
ELEMENT_NODE, uiNameId, XFLM_LAST_CHILD, pNewCachedNode->getNodeId())))
{
goto Exit;
}
if( ifppNewNode)
{
if( *ifppNewNode)
{
(*ifppNewNode)->Release();
}
*ifppNewNode = (IF_DOMNode *)pNewNode;
pNewNode = NULL;
}
Exit:
if( pNewNode)
{
pNewNode->Release();
}
if( pTmpNode)
{
pTmpNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::createAnnotation(
IF_Db * ifpDb,
IF_DOMNode ** ifppAnnotation,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode;
FLMBOOL bMustAbortOnError = FALSE;
F_Db * pDb = (F_Db *)ifpDb;
F_DOMNode ** ppAnnotation = (F_DOMNode **)ifppAnnotation;
FLMBOOL bStartedTrans = FALSE;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure our copy of this node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
// Not supported on attribute nodes
if( eNodeType == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
// If the node already has an annotation, return an error
if( getAnnotationId())
{
rc = RC_SET( NE_XFLM_EXISTS);
goto Exit;
}
// If the user is requesting a specific nodeId, then make sure
// the node is not already in use.
if( pui64NodeId)
{
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
{
if( RC_BAD( rc = pDb->getNode( getCollection(), *pui64NodeId, &pNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
else
{
// Already in use
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
else if( *pui64NodeId)
{
// Set to zero so we don't use it. We will return the
// new nodeId.
*pui64NodeId = 0;
}
}
// Create the new node.
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
getCollection(),
(FLMUINT64)(pui64NodeId
? *pui64NodeId
: (FLMUINT64)0),
&pNode)))
{
goto Exit;
}
pCachedNode = pNode->m_pCachedNode;
pCachedNode->setNodeType( ANNOTATION_NODE);
pCachedNode->setDocumentId( getDocumentId());
pCachedNode->setParentId( getNodeId());
pCachedNode->setDataType( XFLM_NODATA_TYPE);
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pDb->updateNode( pCachedNode, FLM_UPD_ADD)))
{
goto Exit;
}
// Link the annotation to this node
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
setAnnotationId( pCachedNode->getNodeId());
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
if( bStartedTrans)
{
if( RC_BAD( rc = pDb->transCommit()))
{
goto Exit;
}
bStartedTrans = FALSE;
}
if( pui64NodeId)
{
*pui64NodeId = pCachedNode->getNodeId();
}
// Release any node that the passed-in parameter may be
// pointing at
if( *ppAnnotation)
{
(*ppAnnotation)->Release();
}
*ppAnnotation = pNode;
pNode = NULL;
Exit:
if( pNode)
{
pNode->Release();
}
if( RC_BAD( rc))
{
if( bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
if( bStartedTrans)
{
pDb->transAbort();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::hasAnnotation(
IF_Db * ifpDb,
FLMBOOL * pbHasAnnotation)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
*pbHasAnnotation = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
{
goto Exit;
}
if( getAnnotationId())
{
*pbHasAnnotation = TRUE;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getAnnotation(
IF_Db * ifpDb,
IF_DOMNode ** ifppAnnotation)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
{
goto Exit;
}
if( !getAnnotationId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( getCollection(), getAnnotationId(),
ifppAnnotation)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getDocumentId(
IF_Db * ifpDb,
FLMUINT64 * pui64DocId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
*pui64DocId = m_pCachedNode->getDocumentId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getNodeId(
IF_Db * ifpDb,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pui64NodeId = m_pCachedNode->getNodeId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: puiAttrNameId returns 0 if the node isn't an attribute.
******************************************************************************/
RCODE F_DOMNode::getNodeId(
F_Db * pDb,
FLMUINT64 * pui64NodeId,
FLMUINT * puiAttrNameId)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
*pui64NodeId = m_pCachedNode->getNodeId();
if( getNodeType() == ATTRIBUTE_NODE)
{
*puiAttrNameId = m_uiAttrNameId;
}
else
{
*puiAttrNameId = 0;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getParentId(
IF_Db * ifpDb,
FLMUINT64 * pui64ParentId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
*pui64ParentId = getParentId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: COM version of the getPrevSibId method. This method ensures that
the DOM node is up-to-date.
******************************************************************************/
RCODE FLMAPI F_DOMNode::getPrevSibId(
IF_Db * ifpDb,
FLMUINT64 * pui64PrevSibId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pui64PrevSibId = getPrevSibId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return rc;
}
/*****************************************************************************
Desc: COM version of the getNextSibId method. This method ensures that
the DOM node is up-to-date.
******************************************************************************/
RCODE FLMAPI F_DOMNode::getNextSibId(
IF_Db * ifpDb,
FLMUINT64 * pui64NextSibId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pui64NextSibId = getNextSibId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return rc;
}
/*****************************************************************************
Desc: COM version of the getFirstChildId method. This method ensures that
the DOM node is up-to-date.
******************************************************************************/
RCODE FLMAPI F_DOMNode::getFirstChildId(
IF_Db * ifpDb,
FLMUINT64 * pui64FirstChildId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pui64FirstChildId = getFirstChildId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return rc;
}
/*****************************************************************************
Desc: COM version of the getLastChildId method. This method ensures that
the DOM node is up-to-date.
******************************************************************************/
RCODE FLMAPI F_DOMNode::getLastChildId(
IF_Db * ifpDb,
FLMUINT64 * pui64LastChildId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pui64LastChildId = getLastChildId();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return rc;
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::isNamespaceDecl(
IF_Db * ifpDb,
FLMBOOL * pbIsNamespaceDecl)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
*pbIsNamespaceDecl = isNamespaceDecl();
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::hasChildren(
IF_Db * ifpDb,
FLMBOOL * pbHasChildren)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
{
goto Exit;
}
if (getNodeType() == ATTRIBUTE_NODE)
{
*pbHasChildren = FALSE;
}
else
{
*pbHasChildren = getFirstChildId() ? TRUE : FALSE;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getNameId(
IF_Db * ifpDb,
FLMUINT * puiNameId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
if( eNodeType == ATTRIBUTE_NODE)
{
*puiNameId = m_uiAttrNameId;
}
else if( m_pCachedNode)
{
*puiNameId = getNameId();
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getEncDefId(
IF_Db * ifpDb,
FLMUINT * puiEncDefNumber)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getEncDefId(
m_uiAttrNameId, puiEncDefNumber)))
{
goto Exit;
}
}
else if( m_pCachedNode)
{
*puiEncDefNumber = getEncDefId();
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getAnnotationId(
IF_Db * ifpDb,
FLMUINT64 * pui64AnnotationId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
*pui64AnnotationId = 0;
}
else if( m_pCachedNode)
{
*pui64AnnotationId = getAnnotationId();
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::getDataType(
IF_Db * ifpDb,
FLMUINT * puiDataType)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getDataType(
m_uiAttrNameId, puiDataType)))
{
goto Exit;
}
}
else
{
*puiDataType = m_pCachedNode->getDataType();
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getPrefixId(
IF_Db * ifpDb,
FLMUINT * puiPrefixId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiPrefix = 0;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
m_uiAttrNameId, &uiPrefix)))
{
goto Exit;
}
}
else
{
if( (uiPrefix = m_pCachedNode->getPrefixId()) != 0)
{
if( RC_BAD( rc = pDb->m_pDict->getPrefix( uiPrefix, NULL)))
{
if( rc != NE_XFLM_BAD_PREFIX)
{
goto Exit;
}
rc = NE_XFLM_OK;
uiPrefix = 0;
}
}
}
*puiPrefixId = uiPrefix;
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::hasAttributes(
IF_Db * ifpDb,
FLMBOOL * pbHasAttrs)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
*pbHasAttrs = FALSE;
goto Exit;
}
*pbHasAttrs = m_pCachedNode->m_uiAttrCount ? TRUE : FALSE;
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::hasNextSibling(
IF_Db * ifpDb,
FLMBOOL * pbHasNextSibling)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pbHasNextSibling = (m_pCachedNode->getNextSibId() &&
getParentId())
? TRUE
: FALSE;
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_DOMNode::hasPreviousSibling(
IF_Db * ifpDb,
FLMBOOL * pbHasPreviousSibling)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
*pbHasPreviousSibling = (m_pCachedNode->getPrevSibId() &&
getParentId())
? TRUE
: FALSE;
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getAncestorElement(
IF_Db * ifpDb,
FLMUINT uiNameId,
IF_DOMNode ** ifppAncestor)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_DOMNode * pTmpNode = NULL;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCollection;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
pTmpNode = this;
pTmpNode->AddRef();
uiCollection = getCollection();
while( pTmpNode)
{
if( !pTmpNode->getParentId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = pDb->getNode(
uiCollection, pTmpNode->getParentId(), &pTmpNode)))
{
goto Exit;
}
if( pTmpNode->getNameId() == uiNameId)
{
break;
}
}
if( !pTmpNode)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( *ifppAncestor)
{
(*ifppAncestor)->Release();
}
*ifppAncestor = pTmpNode;
pTmpNode = NULL;
Exit:
if( pTmpNode)
{
pTmpNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getDescendantElement(
IF_Db * ifpDb,
FLMUINT uiNameId,
IF_DOMNode ** ifppDescendant)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_DOMNode * pContextNode = NULL;
F_DOMNode * pFoundNode = NULL;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCollection;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
pContextNode = this;
pContextNode->AddRef();
uiCollection = getCollection();
while( pContextNode)
{
if( pContextNode->getFirstChildId())
{
if( RC_BAD( rc = pDb->getNode( uiCollection,
pContextNode->getFirstChildId(), &pContextNode)))
{
goto Exit;
}
}
else if( pContextNode->getNextSibId())
{
Get_Next_Sib:
if( pContextNode->getNodeId() == getNodeId())
{
break;
}
if( RC_BAD( rc = pDb->getNode( uiCollection,
pContextNode->getNextSibId(), &pContextNode)))
{
goto Exit;
}
}
else
{
if( pContextNode->getNodeId() == getNodeId())
{
break;
}
if( RC_BAD( rc = pDb->getNode( uiCollection,
pContextNode->getParentId(), &pContextNode)))
{
goto Exit;
}
goto Get_Next_Sib;
}
if( pContextNode->getNodeType() != ELEMENT_NODE)
{
continue;
}
if( pContextNode->getNameId() == uiNameId)
{
pFoundNode = pContextNode;
pFoundNode->AddRef();
break;
}
}
if( *ifppDescendant)
{
(*ifppDescendant)->Release();
}
*ifppDescendant = pFoundNode;
pFoundNode = NULL;
Exit:
if( pContextNode)
{
pContextNode->Release();
}
if( pFoundNode)
{
pFoundNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getDocumentNode(
IF_Db * ifpDb,
IF_DOMNode ** ifppDoc)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( isRootNode())
{
IF_DOMNode * pTmpNode = *ifppDoc;
*ifppDoc = this;
(*ifppDoc)->AddRef();
if( pTmpNode)
{
pTmpNode->Release();
}
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
getDocumentId(), ifppDoc)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getParentNode(
IF_Db * ifpDb,
IF_DOMNode ** ifppParent)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( !getParentId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode(
getCollection(), getParentId(), ifppParent)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getFirstChild(
IF_Db * ifpDb,
IF_DOMNode ** ifppChild)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( !getFirstChildId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
getFirstChildId(), ifppChild)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getLastChild(
IF_Db * ifpDb,
IF_DOMNode ** ifppChild)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( !getLastChildId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
getLastChildId(), ifppChild)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getChild(
IF_Db * ifpDb,
eDomNodeType eNodeType,
IF_DOMNode ** ppChild)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pCurNode = NULL;
FLMUINT64 ui64NodeId;
F_Db * pDb = (F_Db *)ifpDb;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// We can do a quick lookup if this node is an element where we are
// maintaining a child element list.
if( eNodeType == ELEMENT_NODE &&
(getModeFlags() & FDOM_HAVE_CELM_LIST))
{
if( getChildElmCount())
{
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
getCollection(), getChildElmNodeId( 0), ppChild)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
}
}
else
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
ui64NodeId = getFirstChildId();
for( ;;)
{
if( !ui64NodeId)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
getCollection(), ui64NodeId, (IF_DOMNode **)&pCurNode)))
{
goto Exit;
}
if( pCurNode->getNodeType() == eNodeType)
{
if( *ppChild)
{
(*ppChild)->Release();
}
*ppChild = pCurNode;
pCurNode = NULL;
break;
}
ui64NodeId = pCurNode->getNextSibId();
}
Exit:
if( pCurNode)
{
pCurNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getChildElement(
IF_Db * ifpDb,
FLMUINT uiNameId,
IF_DOMNode ** ppChild,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pCurNode = NULL;
FLMUINT64 ui64NodeId;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiCollection;
FLMUINT uiElmPos;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// We can do a quick lookup if this node is an element where we are
// maintaining a child element list.
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
{
if( !getChildElmCount())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( !findChildElm( uiNameId, &uiElmPos) &&
(!uiFlags || (uiFlags & XFLM_EXACT) ||
uiElmPos >= getChildElmCount()))
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
// At this point, if we did an exact match, we will be on the node.
// If we did an inclusive match, we will be either on the node or
// past it. If we did an exclusive match, we need to determine if
// we are on the node or past it. If we are on the node, we need
// to try to move past it, unless we are at the end of the list, in
// which case we cannot go exclusive.
if( uiFlags & XFLM_EXCL)
{
// If we found the node, we need to go one past it, if there
// is one past it to go to. If not, we must return
// not found.
if( getChildElmNameId( uiElmPos) == uiNameId)
{
if( uiElmPos == getChildElmCount() - 1)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
else
{
uiElmPos++;
}
}
}
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode( getCollection(),
getChildElmNodeId( uiElmPos), ppChild)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
}
else
{
// Cannot set uiFlags for nodes that are not unique-child nodes.
if( uiFlags)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_FLAG);
goto Exit;
}
ui64NodeId = getFirstChildId();
uiCollection = getCollection();
for( ;;)
{
if( !ui64NodeId)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
uiCollection, ui64NodeId, (IF_DOMNode **)&pCurNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if( pCurNode->getNodeType() == ELEMENT_NODE &&
pCurNode->getNameId() == uiNameId)
{
if( *ppChild)
{
(*ppChild)->Release();
}
*ppChild = pCurNode;
pCurNode = NULL;
break;
}
ui64NodeId = pCurNode->getNextSibId();
}
}
Exit:
if( pCurNode)
{
pCurNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getSiblingElement(
IF_Db * ifpDb,
FLMUINT uiNameId,
FLMBOOL bNext,
IF_DOMNode ** ppSibling)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pCurNode = NULL;
FLMUINT64 ui64NodeId;
F_Db * pDb = (F_Db *)ifpDb;
FLMUINT uiCollection;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( bNext)
{
ui64NodeId = getNextSibId();
}
else
{
ui64NodeId = getPrevSibId();
}
uiCollection = getCollection();
for( ;;)
{
if( !ui64NodeId)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
uiCollection, ui64NodeId, (IF_DOMNode **)&pCurNode)))
{
goto Exit;
}
if( pCurNode->getNodeType() == ELEMENT_NODE &&
pCurNode->getNameId() == uiNameId)
{
if( *ppSibling)
{
(*ppSibling)->Release();
}
*ppSibling = pCurNode;
pCurNode = NULL;
break;
}
if( bNext)
{
ui64NodeId = pCurNode->getNextSibId();
}
else
{
ui64NodeId = pCurNode->getPrevSibId();
}
}
Exit:
if( pCurNode)
{
pCurNode->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getPreviousSibling(
IF_Db * ifpDb,
IF_DOMNode ** ifppSib)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( !(*ifppSib))
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->getPrevSiblingNode(
m_uiAttrNameId, ifppSib)))
{
goto Exit;
}
}
else
{
if( !getPrevSibId() || !getParentId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode(
getCollection(), getPrevSibId(), ifppSib)))
{
goto Exit;
}
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getNextSibling(
IF_Db * ifpDb,
IF_DOMNode ** ifppSib)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( getNodeType() == ATTRIBUTE_NODE)
{
if( !(*ifppSib))
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = m_pCachedNode->getNextSiblingNode(
m_uiAttrNameId, ifppSib)))
{
goto Exit;
}
}
else
{
if( !getNextSibId() || !getParentId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
getNextSibId(), ifppSib)))
{
goto Exit;
}
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getPreviousDocument(
IF_Db * ifpDb,
IF_DOMNode ** ifppDoc)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pNode = NULL;
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMUINT64 ui64StartDocId;
FLMUINT64 ui64DocumentId;
FLMBOOL bNeg;
FLMUINT uiBytesProcessed;
F_Btree * pBTree = NULL;
FLMUINT uiCollection;
F_COLLECTION * pCollection;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
uiCollection = getCollection();
if( RC_BAD( rc = syncFromDb( pDb)))
{
if( rc != NE_XFLM_DOM_NODE_DELETED)
{
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
ui64DocumentId = ui64StartDocId = getDocumentId();
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( ui64StartDocId, &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btLocateEntry(
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_INCL)))
{
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
for (;;)
{
// Need to go to the previous node.
if( RC_BAD( rc = pBTree->btPrevEntry( ucKey, uiKeyLen, &uiKeyLen)))
{
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_BOF_HIT)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
&ui64DocumentId, &bNeg, &uiBytesProcessed)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->getNode( uiCollection, ui64DocumentId, &pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// Better be able to find the node at this point!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
// If the node is a root node, we have a document we can
// process.
if( pNode->isRootNode() && pNode->getNodeId() < ui64StartDocId)
{
if( *ifppDoc)
{
(*ifppDoc)->Release();
}
// Just use the reference on pNode for *ifppDoc
*ifppDoc = pNode;
pNode = NULL;
goto Exit;
}
}
}
else
{
// If we are not at the root node of the document,
// jump to the root.
if( !isRootNode())
{
if( RC_BAD( rc = pDb->getNode( uiCollection, getDocumentId(), &pNode)))
{
goto Exit;
}
}
else
{
pNode = this;
pNode->AddRef();
}
if( !pNode->getPrevSibId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode( uiCollection,
pNode->getPrevSibId(), ifppDoc)))
{
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( pBTree)
{
pBTree->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_DOMNode::getNextDocument(
IF_Db * ifpDb,
IF_DOMNode ** ifppDoc)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
F_DOMNode * pNode = NULL;
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMUINT64 ui64DocumentId;
FLMBOOL bNeg;
FLMUINT uiBytesProcessed;
F_Btree * pBTree = NULL;
FLMUINT uiCollection;
F_COLLECTION * pCollection;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
uiCollection = getCollection();
if( RC_BAD( rc = syncFromDb( pDb)))
{
if( rc != NE_XFLM_DOM_NODE_DELETED)
{
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
ui64DocumentId = getDocumentId();
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( ui64DocumentId, &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btLocateEntry(
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_EXCL)))
{
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
for (;;)
{
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
&ui64DocumentId, &bNeg, &uiBytesProcessed)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->getNode(
uiCollection, ui64DocumentId, &pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// Better be able to find the node at this point!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
// If the node is a root node, we have a document we can
// process.
if( pNode->isRootNode())
{
if( *ifppDoc)
{
(*ifppDoc)->Release();
}
// Just use the reference on pNode for *ifppDoc
*ifppDoc = pNode;
pNode = NULL;
goto Exit;
}
// Need to go to the next node.
if( RC_BAD( rc = pBTree->btNextEntry( ucKey, uiKeyLen, &uiKeyLen)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
}
}
else
{
// If we are not at the root node of the document,
// jump to the root.
if( !isRootNode())
{
if( RC_BAD( rc = pDb->getNode( uiCollection, getDocumentId(), &pNode)))
{
goto Exit;
}
}
else
{
pNode = this;
pNode->AddRef();
}
if( !pNode->getNextSibId())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = ifpDb->getNode(
uiCollection, getNextSibId(), ifppDoc)))
{
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( pBTree)
{
pBTree->Release();
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE flmReadStorageAsText(
IF_IStream * pIStream,
FLMBYTE * pucStorageData,
FLMUINT uiDataLen,
FLMUINT uiDataType,
void * pvBuffer,
FLMUINT uiBufLen,
eXFlmTextType eTextType,
FLMUINT uiMaxCharsToRead,
FLMUINT uiCharOffset,
FLMUINT * puiCharsRead,
FLMUINT * puiBufferBytesUsed)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucByte;
FLMUINT uiCharsDecoded = 0;
FLMUINT uiSENLen;
FLMUINT uiNumChars;
FLMUINT uiCharsOutput = 0;
FLMUNICODE * puzOutBuf = NULL;
FLMBYTE * pszOutBuf = NULL;
void * pvEnd = ((char *)pvBuffer) + uiBufLen;
const FLMBYTE * pucTmp;
FLMUINT uiLen;
FLMBYTE ucSENBuf[ 16];
FLMBYTE ucConvBuf[ 64];
FLMUINT uiLastUTFLen = 0;
IF_IStream * pStream = pIStream;
IF_BufferIStream * pConvStream = NULL;
F_BinaryToTextStream binaryToTextStream;
// If the value is a number, convert to text
if( uiDataType == XFLM_NUMBER_TYPE)
{
FLMBYTE ucNumBuf[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiNumBufLen;
// Read the entire number into the temporary buffer.
// NOTE: Numbers are not encoded with a length. It
// is expected that the number of bytes remaining
// in the stream will be equal to the exact number of
// bytes representing the number. If this is not the case,
// either a corruption error or an incorrect value will
// be returned.
uiNumBufLen = sizeof( ucNumBuf);
if( pStream)
{
if( RC_BAD( rc = pStream->read( (char *)ucNumBuf,
uiNumBufLen, &uiNumBufLen)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
}
else
{
f_memcpy( ucNumBuf, pucStorageData, f_max( uiNumBufLen, uiDataLen));
}
// Convert the storage number to storage text
uiDataLen = sizeof( ucConvBuf);
if( RC_BAD( rc = flmStorageNum2StorageText( ucNumBuf, uiNumBufLen,
ucConvBuf, &uiDataLen)))
{
goto Exit;
}
if( RC_BAD( rc = FlmAllocBufferIStream( &pConvStream)))
{
goto Exit;
}
if( RC_BAD( rc = pConvStream->open( (const char *)ucConvBuf, uiDataLen)))
{
goto Exit;
}
pStream = pConvStream;
pucStorageData = NULL;
}
else if( uiDataType == XFLM_BINARY_TYPE)
{
if( !pStream)
{
if( RC_BAD( rc = FlmAllocBufferIStream( &pConvStream)))
{
goto Exit;
}
if( RC_BAD( rc = pConvStream->open(
(const char *)pucStorageData, uiDataLen)))
{
goto Exit;
}
pStream = pConvStream;
}
if( RC_BAD( rc = binaryToTextStream.open( pStream,
uiDataLen, &uiDataLen)))
{
goto Exit;
}
pStream = &binaryToTextStream;
pucStorageData = NULL;
}
else if( uiDataType == XFLM_NODATA_TYPE)
{
goto Empty_String;
}
else if( uiDataType != XFLM_TEXT_TYPE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
// Determine the SEN length
if( pStream)
{
uiLen = 1;
if( RC_BAD( rc = pStream->read( (char *)&ucSENBuf[ 0], uiLen, &uiLen)))
{
if( rc == NE_XFLM_EOF_HIT)
{
Empty_String:
rc = NE_XFLM_OK;
if( eTextType == XFLM_UTF8_TEXT)
{
if( pvBuffer)
{
*((FLMBYTE *)pvBuffer) = 0;
}
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = 1;
}
}
else
{
flmAssert( eTextType == XFLM_UNICODE_TEXT);
if( pvBuffer)
{
*((FLMUNICODE *)pvBuffer) = 0;
}
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = sizeof( FLMUNICODE);
}
}
}
goto Exit;
}
uiDataLen -= uiLen;
}
else
{
if( !uiDataLen)
{
goto Empty_String;
}
ucSENBuf[ 0] = *pucStorageData++;
uiDataLen--;
}
if( (uiSENLen = f_getSENLength( ucSENBuf[ 0])) > 1)
{
uiLen = uiSENLen - 1;
if( pStream)
{
if( RC_BAD( rc = pStream->read(
(char *)&ucSENBuf[ 1], uiLen, &uiLen)))
{
goto Exit;
}
}
else
{
if( uiDataLen < uiLen)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_EOF_HIT);
goto Exit;
}
f_memcpy( &ucSENBuf[ 1], pucStorageData, uiLen);
pucStorageData += uiLen;
}
uiDataLen -= uiLen;
}
pucTmp = &ucSENBuf[ 0];
if( RC_BAD( rc = f_decodeSEN(
&pucTmp, &ucSENBuf[ uiSENLen], &uiNumChars)))
{
goto Exit;
}
// If only a length is needed (number of bytes), we can
// return that without parsing the string
if( !pvBuffer)
{
uiCharsOutput = uiCharOffset >= uiNumChars
? 0
: uiNumChars - uiCharOffset;
if( puiBufferBytesUsed)
{
if( eTextType == XFLM_UNICODE_TEXT)
{
*puiBufferBytesUsed = (uiCharsOutput + 1) * sizeof( FLMUNICODE);
}
else // UTF-8
{
*puiBufferBytesUsed = uiDataLen;
}
}
goto Exit;
}
if( eTextType == XFLM_UTF8_TEXT)
{
if( !uiBufLen)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
pszOutBuf = (FLMBYTE *)pvBuffer;
}
else
{
flmAssert( eTextType == XFLM_UNICODE_TEXT);
if( uiBufLen < sizeof( FLMUNICODE))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
puzOutBuf = (FLMUNICODE *)pvBuffer;
}
// If we have a zero-length string, jump to exit.
if( !uiNumChars)
{
// Read the null terminator
if( pStream)
{
uiLen = 1;
if( RC_BAD( rc = pStream->read( (char *)&ucByte, uiLen, &uiLen)))
{
goto Exit;
}
}
else
{
if( !uiDataLen)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
ucByte = *pucStorageData++;
uiDataLen--;
}
if( ucByte != 0)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
goto Empty_String;
}
// Parse through the string, outputting data to the buffer as we go.
uiCharsDecoded = 0;
if( eTextType == XFLM_UNICODE_TEXT)
{
FLMUNICODE uChar;
while( uiCharsOutput < uiMaxCharsToRead)
{
if( pStream)
{
if( RC_BAD( rc = f_readUTF8CharAsUnicode( pStream, &uChar)))
{
if( rc == NE_XFLM_EOF_HIT)
{
Unicode_EOF_Hit:
if( uiCharsDecoded != uiNumChars)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
}
else
{
FLMBYTE ucTmpUni[ 3];
if( !uiDataLen)
{
goto Unicode_EOF_Hit;
}
ucTmpUni[ 0] = *pucStorageData++;
uiDataLen--;
if( ucTmpUni[ 0] <= 0x7F)
{
if( !ucTmpUni[ 0])
{
goto Unicode_EOF_Hit;
}
uChar = (FLMUNICODE)ucTmpUni[ 0];
}
else
{
if( !uiDataLen)
{
goto Unicode_EOF_Hit;
}
ucTmpUni[ 1] = *pucStorageData++;
uiDataLen--;
if( (ucTmpUni[ 1] >> 6) != 0x02)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
goto Exit;
}
if( (ucTmpUni[ 0] >> 5) == 0x06)
{
uChar = ((FLMUNICODE)( ucTmpUni[ 0] - 0xC0) << 6) +
(FLMUNICODE)(ucTmpUni[ 1] - 0x80);
}
else
{
if( !uiDataLen)
{
goto Unicode_EOF_Hit;
}
ucTmpUni[ 2] = *pucStorageData++;
uiDataLen--;
if( (ucTmpUni[ 0] >> 4) != 0x0E ||
(ucTmpUni[ 2] >> 6) != 0x02)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
goto Exit;
}
uChar = ((FLMUNICODE)(ucTmpUni[ 0] - 0xE0) << 12) +
((FLMUNICODE)(ucTmpUni[ 1] - 0x80) << 6) +
(FLMUNICODE)(ucTmpUni[ 2] - 0x80);
}
}
}
if( ++uiCharsDecoded > uiNumChars)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( uiCharOffset)
{
uiCharOffset--;
continue;
}
if( puzOutBuf)
{
if( puzOutBuf + 1 >= pvEnd)
{
goto Overflow_Error;
}
*puzOutBuf++ = uChar;
uiCharsOutput++;
}
else
{
if( uChar <= 0xFF)
{
if( pszOutBuf + 1 >= pvEnd)
{
goto Overflow_Error;
}
*pszOutBuf++ = f_tonative( (FLMBYTE)uChar);
uiCharsOutput++;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
}
}
}
else // UTF-8
{
flmAssert( eTextType == XFLM_UTF8_TEXT);
while( uiCharsOutput < uiMaxCharsToRead)
{
if( (uiLen = ((FLMBYTE *)pvEnd) - pszOutBuf) == 0)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Overflow_Error;
}
if( pStream)
{
if( RC_BAD( rc = f_readUTF8CharAsUTF8(
pStream, pszOutBuf, &uiLen)))
{
if( rc == NE_XFLM_CONV_DEST_OVERFLOW)
{
goto Overflow_Error;
}
if( rc == NE_XFLM_EOF_HIT)
{
UTF8_EOF_Hit:
if( uiCharsDecoded != uiNumChars)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
}
else
{
if( !uiDataLen)
{
goto UTF8_EOF_Hit;
}
pszOutBuf[ 0] = *pucStorageData++;
uiDataLen--;
if( pszOutBuf[ 0] <= 0x7F)
{
if( !pszOutBuf[ 0])
{
goto UTF8_EOF_Hit;
}
uiLen = 1;
}
else
{
if( uiLen < 2)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Overflow_Error;
}
if( !uiDataLen)
{
goto UTF8_EOF_Hit;
}
pszOutBuf[ 1] = *pucStorageData++;
uiDataLen--;
if( (pszOutBuf[ 1] >> 6) != 0x02)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
goto Exit;
}
if( (pszOutBuf[ 0] >> 5) == 0x06)
{
uiLen = 2;
}
else
{
if( uiLen < 3)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Overflow_Error;
}
if( !uiDataLen)
{
goto UTF8_EOF_Hit;
}
pszOutBuf[ 2] = *pucStorageData++;
uiDataLen--;
if( (pszOutBuf[ 0] >> 4) != 0x0E ||
(pszOutBuf[ 2] >> 6) != 0x02)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
goto Exit;
}
uiLen = 3;
}
}
}
if( ++uiCharsDecoded > uiNumChars)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( uiCharOffset)
{
uiCharOffset--;
continue;
}
if( pszOutBuf + uiLen >= pvEnd)
{
goto Overflow_Error;
}
pszOutBuf += uiLen;
uiLastUTFLen = uiLen;
uiCharsOutput++;
}
}
// There is room for the 0 terminating character, but we
// will not increment the return length, but we will output the
// number of buffer bytes used
if( eTextType == XFLM_UTF8_TEXT && pszOutBuf < pvEnd)
{
*pszOutBuf = 0;
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = (FLMUINT)(pszOutBuf - (FLMBYTE *)pvBuffer) + 1;
}
}
else if( eTextType == XFLM_UNICODE_TEXT && &puzOutBuf[ 1] <= pvEnd)
{
*puzOutBuf = 0;
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = (FLMUINT)((FLMBYTE *)puzOutBuf -
(FLMBYTE *)pvBuffer) + sizeof( FLMUNICODE);
}
}
else
{
Overflow_Error:
if( uiCharsOutput)
{
uiCharsOutput--;
if( puzOutBuf)
{
*(puzOutBuf - 1) = 0;
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = (FLMUINT)((FLMBYTE *)puzOutBuf -
(FLMBYTE *)pvBuffer);
}
}
else
{
pszOutBuf -= uiLastUTFLen;
*pszOutBuf = 0;
if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = (FLMUINT)(pszOutBuf -
(FLMBYTE *)pvBuffer) + 1;
}
}
}
else if( puiBufferBytesUsed)
{
*puiBufferBytesUsed = 0;
}
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
Exit:
if( pConvStream)
{
pConvStream->Release();
}
if( puiCharsRead)
{
*puiCharsRead = uiCharsOutput;
}
if( rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE flmReadStorageAsBinary(
IF_IStream * pIStream,
void * pvBuffer,
FLMUINT uiBufLen,
FLMUINT uiByteOffset,
FLMUINT * puiBytesRead)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
// Position to the requested offset
if( uiByteOffset)
{
if( RC_BAD( rc = pIStream->read(
NULL, uiByteOffset, &uiByteOffset)))
{
goto Exit;
}
}
// Read the requested bytes
rc = pIStream->read( pucBuffer, uiBufLen, &uiBufLen);
if( puiBytesRead)
{
*puiBytesRead = uiBufLen;
}
if( RC_BAD( rc))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE flmReadStorageAsNumber(
IF_IStream * pIStream,
FLMUINT uiDataType,
FLMUINT64 * pui64Number,
FLMBOOL * pbNeg)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bNeg = FALSE;
FLMUINT64 ui64Num = 0;
switch( uiDataType)
{
case XFLM_NUMBER_TYPE :
{
FLMBYTE ucNumBuf[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiNumBufLen;
// Read the entire number into the temporary buffer.
// NOTE: Numbers are not encoded with a length. It
// is expected that the number of bytes remaining
// in the stream will be equal to the exact number of
// bytes representing the number. If this is not the case,
// either a corruption error or an incorrect value will
// be returned.
uiNumBufLen = sizeof( ucNumBuf);
if( RC_BAD( rc = pIStream->read(
(char *)ucNumBuf, uiNumBufLen, &uiNumBufLen)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
if( RC_BAD( rc = flmStorageNumberToNumber(
ucNumBuf, uiNumBufLen, &ui64Num, &bNeg)))
{
goto Exit;
}
break;
}
case XFLM_TEXT_TYPE :
{
FLMUNICODE uChar;
FLMUINT uiLoop;
FLMBOOL bHex = FALSE;
FLMUINT uiIncrAmount = 0;
// Skip the character count
if( RC_BAD( rc = f_readSEN64( pIStream, NULL, NULL)))
{
if( rc == NE_XFLM_EOF_HIT)
{
// Empty string
rc = NE_XFLM_OK;
}
goto Exit;
}
for( uiLoop = 0;; uiLoop++)
{
if( RC_BAD( rc = f_readUTF8CharAsUnicode(
pIStream, &uChar)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
else
{
goto Exit;
}
}
if( uChar >= FLM_UNICODE_0 && uChar <= FLM_UNICODE_9)
{
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_0);
}
else if( uChar >= FLM_UNICODE_A && uChar <= FLM_UNICODE_F)
{
if( bHex)
{
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_A + 10);
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( uChar >= FLM_UNICODE_a && uChar <= FLM_UNICODE_f)
{
if( bHex)
{
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_a + 10);
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( uChar == FLM_UNICODE_X || uChar == FLM_UNICODE_x)
{
if( !ui64Num && !bHex)
{
bHex = TRUE;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
else if( uChar == FLM_UNICODE_HYPHEN && !uiLoop)
{
bNeg = TRUE;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
if( !bHex)
{
if( ui64Num > (~(FLMUINT64)0) / 10)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num *= (FLMUINT64)10;
}
else
{
if( ui64Num > (~(FLMUINT64)0) / 16)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num *= (FLMUINT64)16;
}
if( ui64Num > (~(FLMUINT64)0) - (FLMUINT64)uiIncrAmount)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
ui64Num += (FLMUINT64)uiIncrAmount;
}
break;
}
default :
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
goto Exit;
}
}
*pui64Number = ui64Num;
*pbNeg = bNeg;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE flmReadLine(
IF_IStream * pIStream,
FLMBYTE * pszBuffer,
FLMUINT * puiSize)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiMaxBytes = *puiSize;
FLMUINT uiOffset = 0;
FLMBYTE ucByte;
*puiSize = 0;
for( ;;)
{
if( RC_BAD( rc = pIStream->read( (char *)&ucByte, 1, NULL)))
{
if( rc == NE_FLM_IO_END_OF_FILE)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
if( ucByte == 0x0A || ucByte == 0x0D)
{
if( uiOffset)
{
break;
}
continue;
}
else
{
if( (uiOffset + 1) == uiMaxBytes)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BUFFER_OVERFLOW);
goto Exit;
}
pszBuffer[ uiOffset++] = (char)ucByte;
}
}
pszBuffer[ uiOffset] = 0;
*puiSize = uiOffset;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_BTreeIStream::open(
F_Db * pDb,
FLMUINT uiCollection,
FLMUINT64 ui64NodeId,
FLMUINT32 ui32BlkAddr,
FLMUINT uiOffsetIndex)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
F_Dict * pDict = pDb->m_pDict;
F_Btree * pBTree = NULL;
if( RC_BAD( rc = pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
{
goto Exit;
}
// Set up the btree object
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = open( pDb, pBTree, XFLM_EXACT, uiCollection, ui64NodeId,
ui32BlkAddr, uiOffsetIndex)))
{
goto Exit;
}
pBTree = NULL;
m_bReleaseBTree = TRUE;
Exit:
if( pBTree)
{
gv_XFlmSysData.pBtPool->btpReturnBtree( &pBTree);
}
if( RC_BAD( rc))
{
close();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_BTreeIStream::open(
F_Db * pDb,
F_Btree * pBTree,
FLMUINT uiFlags,
FLMUINT uiCollection,
FLMUINT64 ui64NodeId,
FLMUINT32 ui32BlkAddr,
FLMUINT uiOffsetIndex)
{
RCODE rc = NE_XFLM_OK;
flmAssert( !m_pBTree);
m_pDb = pDb;
m_uiCollection = uiCollection;
m_pBTree = pBTree;
// Save the key and key length
m_uiKeyLength = sizeof( m_ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId, &m_uiKeyLength,
m_ucKey, FALSE, TRUE)))
{
goto Exit;
}
m_ui32BlkAddr = ui32BlkAddr;
m_uiOffsetIndex = uiOffsetIndex;
if( RC_BAD( rc = m_pBTree->btLocateEntry(
m_ucKey, sizeof( m_ucKey), &m_uiKeyLength, uiFlags,
NULL, &m_uiStreamSize, &m_ui32BlkAddr, &m_uiOffsetIndex)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
if( uiFlags == XFLM_EXACT)
{
m_ui64NodeId = ui64NodeId;
}
else
{
if( RC_BAD( rc = flmCollation2Number( m_uiKeyLength, m_ucKey,
&m_ui64NodeId, NULL, NULL)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc))
{
close();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_BTreeIStream::positionTo(
FLMUINT64 ui64Position)
{
RCODE rc = NE_XFLM_OK;
if( ui64Position >= m_uiBufferStartOffset &&
ui64Position <= m_uiBufferStartOffset + m_uiBufferBytes)
{
m_uiBufferOffset = (FLMUINT)(ui64Position - m_uiBufferStartOffset);
}
else
{
if( !m_bDataEncrypted)
{
if( RC_BAD( rc = m_pBTree->btSetReadPosition( m_ucKey,
m_uiKeyLength, (FLMUINT)ui64Position)))
{
goto Exit;
}
m_uiBufferStartOffset = (FLMUINT)ui64Position;
m_uiBufferOffset = 0;
m_uiBufferBytes = 0;
}
else
{
// When the data is encrypted, we can't just position the btree to a
// new read position. We must read the data chunk by chunk until we
// get to the buffer that holds the specified position. Then we can
// decrypt the buffer and set the correct position.
m_bBufferDecrypted = FALSE;
if( ui64Position > m_uiBufferStartOffset + m_uiBufferBytes)
{
while( ui64Position > m_uiBufferStartOffset + m_uiBufferBytes)
{
m_uiBufferStartOffset += m_uiBufferBytes;
}
}
else
{
while( ui64Position < m_uiBufferStartOffset)
{
m_uiBufferStartOffset -= f_min( m_uiBufferStartOffset,
FLM_ENCRYPT_CHUNK_SIZE);
}
}
flmAssert( ui64Position >= m_uiBufferStartOffset &&
ui64Position <= m_uiBufferStartOffset + m_uiBufferBytes);
// If the new position uis out of range, we will get an error returned.
if( RC_BAD( rc = m_pBTree->btSetReadPosition( m_ucKey,
m_uiKeyLength, m_uiBufferStartOffset)))
{
goto Exit;
}
if( RC_BAD( rc = m_pBTree->btGetEntry(
m_ucKey, m_uiKeyLength, m_uiKeyLength,
m_pucBuffer, m_uiBufferSize, &m_uiBufferBytes)))
{
if( rc == NE_XFLM_EOF_HIT)
{
if( !m_uiBufferBytes)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
m_pucBuffer, m_uiBufferBytes, m_pucBuffer, m_uiBufferSize)))
{
goto Exit;
}
// Check to see if we are at the end of the encrypted data.
if( m_uiBufferStartOffset + m_uiBufferBytes >= m_uiDataLength)
{
// Trim back to the valid decrypted data.
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
extraEncBytes( m_uiDataLength));
}
m_bBufferDecrypted = TRUE;
m_uiBufferOffset = (FLMUINT)(ui64Position - m_uiBufferStartOffset);
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_BTreeIStream::read(
void * pvBuffer,
FLMUINT uiBytesToRead,
FLMUINT * puiBytesRead)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
FLMUINT uiBufBytesAvail;
FLMUINT uiTmp;
FLMUINT uiOffset = 0;
flmAssert( m_pBTree);
if( m_bDataEncrypted && !m_bBufferDecrypted)
{
if( (m_uiBufferBytes - m_uiBufferOffset) > 0)
{
// Since we are now looking at encrypted data that was not
// decrypted, we will need to move the data to the front of the
// buffer, then read in enough data to fill the buffer (if there
// is any there) before we can decrypt it.
f_memmove( &m_ucBuffer[0], &m_ucBuffer[ m_uiBufferOffset],
(m_uiBufferBytes - m_uiBufferOffset));
m_uiBufferBytes -= m_uiBufferOffset;
m_uiBufferOffset = 0;
// Fill the remainder of the buffer
if( RC_BAD( rc = m_pBTree->btGetEntry(
m_ucKey, m_uiKeyLength, m_uiKeyLength,
&m_ucBuffer[ m_uiBufferBytes], m_uiBufferSize - m_uiBufferBytes,
&uiTmp)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
m_uiBufferBytes += uiTmp;
flmAssert( extraEncBytes( m_uiBufferBytes) == 0);
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
// Now decrypt what we have.
uiTmp = m_uiBufferBytes;
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
m_ucBuffer, m_uiBufferBytes, m_ucBuffer, m_uiBufferSize)))
{
goto Exit;
}
// Check for the end of the data.
if( m_uiBufferStartOffset + m_uiBufferBytes > m_uiDataLength)
{
// Trim back the buffer to valid data only.
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
extraEncBytes( m_uiDataLength));
}
m_bBufferDecrypted = TRUE;
}
}
while( uiBytesToRead)
{
if( (uiBufBytesAvail = m_uiBufferBytes - m_uiBufferOffset) != 0)
{
uiTmp = f_min( uiBufBytesAvail, uiBytesToRead);
if( pucBuffer)
{
f_memcpy( &pucBuffer[ uiOffset],
&m_pucBuffer[ m_uiBufferOffset], uiTmp);
}
m_uiBufferOffset += uiTmp;
uiOffset += uiTmp;
if( (uiBytesToRead -= uiTmp) == 0)
{
break;
}
}
else
{
m_uiBufferStartOffset += m_uiBufferBytes;
m_uiBufferOffset = 0;
if( RC_BAD( rc = m_pBTree->btGetEntry(
m_ucKey, m_uiKeyLength, m_uiKeyLength,
m_pucBuffer, m_uiBufferSize, &m_uiBufferBytes)))
{
if( rc == NE_XFLM_EOF_HIT)
{
if( !m_uiBufferBytes)
{
goto Exit;
}
rc = NE_XFLM_OK;
continue;
}
goto Exit;
}
// Check for encryption.
if( m_bDataEncrypted)
{
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
m_pucBuffer, m_uiBufferBytes, m_pucBuffer, m_uiBufferSize)))
{
goto Exit;
}
// Check to see if we are at the end of the encrypted data.
if( m_uiBufferStartOffset + m_uiBufferBytes > m_uiDataLength)
{
// Trim back to the valid decrypted data.
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
extraEncBytes( m_uiDataLength));
}
m_bBufferDecrypted = TRUE;
}
}
}
Exit:
if( puiBytesRead)
{
*puiBytesRead = uiOffset;
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::decryptData(
FLMUINT uiEncDefId,
FLMBYTE * pucIV,
void * pvInBuf,
FLMUINT uiInLen,
void * pvOutBuf,
FLMUINT uiOutBufSize)
{
RCODE rc = NE_XFLM_OK;
F_Dict * pDict;
F_ENCDEF * pEncDef = NULL;
FLMBYTE * pucInBuf = (FLMBYTE *)pvInBuf;
FLMBYTE * pucOutBuf = (FLMBYTE *)pvOutBuf;
FLMUINT uiEncLen;
FLMUINT uiOutLen;
if( m_pDatabase->m_bInLimitedMode)
{
rc = RC_SET( m_pDatabase->m_rcLimitedCode);
goto Exit;
}
flmAssert( extraEncBytes( uiInLen) == 0);
flmAssert( uiEncDefId);
// Need the dictionary and encryption definition.
if( RC_BAD( rc = getDictionary( &pDict)))
{
goto Exit;
}
if( RC_BAD( rc = pDict->getEncDef( uiEncDefId, &pEncDef)))
{
goto Exit;
}
flmAssert( pEncDef);
flmAssert( pEncDef->pCcs);
flmAssert( pEncDef->uiEncKeySize);
while( uiInLen)
{
uiEncLen = f_min( uiInLen, FLM_ENCRYPT_CHUNK_SIZE);
uiOutLen = uiOutBufSize;
if( RC_BAD( rc = pEncDef->pCcs->decryptFromStore(
pucInBuf, uiEncLen, pucOutBuf, &uiOutLen, pucIV)))
{
goto Exit;
}
flmAssert( uiOutLen == uiEncLen);
pucInBuf += uiEncLen;
uiInLen -= uiEncLen;
pucOutBuf += uiEncLen;
uiOutBufSize -= uiEncLen;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
F_NodePool::~F_NodePool()
{
F_BTreeIStream * pTmpBTreeIStream;
while( (pTmpBTreeIStream = m_pFirstBTreeIStream) != NULL)
{
m_pFirstBTreeIStream = m_pFirstBTreeIStream->m_pNextInPool;
pTmpBTreeIStream->m_refCnt = 0;
pTmpBTreeIStream->m_pNextInPool = NULL;
delete pTmpBTreeIStream;
}
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hMutex);
}
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_NodePool::setup( void)
{
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
void F_NodeCacheMgr::insertDOMNode(
F_DOMNode * pNode)
{
flmAssert( pNode->m_refCnt == 1);
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
pNode->resetDOMNode( TRUE);
pNode->m_pNextInPool = m_pFirstNode;
m_pFirstNode = pNode;
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_NodePool::allocBTreeIStream(
F_BTreeIStream ** ppBTreeIStream)
{
RCODE rc = NE_XFLM_OK;
if( m_pFirstBTreeIStream)
{
f_mutexLock( m_hMutex);
if( !m_pFirstBTreeIStream)
{
f_mutexUnlock( m_hMutex);
}
else
{
f_resetStackInfo( m_pFirstBTreeIStream);
*ppBTreeIStream = m_pFirstBTreeIStream;
m_pFirstBTreeIStream = m_pFirstBTreeIStream->m_pNextInPool;
(*ppBTreeIStream)->m_pNextInPool = NULL;
f_mutexUnlock( m_hMutex);
goto Exit;
}
}
if( (*ppBTreeIStream = f_new F_BTreeIStream) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
void F_NodePool::insertBTreeIStream(
F_BTreeIStream * pBTreeIStream)
{
flmAssert( pBTreeIStream->m_refCnt == 1);
pBTreeIStream->reset();
f_mutexLock( m_hMutex);
pBTreeIStream->m_pNextInPool = m_pFirstBTreeIStream;
m_pFirstBTreeIStream = pBTreeIStream;
f_mutexUnlock( m_hMutex);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE F_DOMNode::getNamespaceURI(
FLMBOOL bUnicode,
IF_Db * ifpDb,
void * pvNamespaceURI,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiTag;
FLMUNICODE * puzNamespaceURI;
char * pszNamespaceURI;
FLMUINT uiChars = 0;
F_NameTable * pNameTable = NULL;
FLMUINT uiNameId;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
pNameTable = pDb->m_pDict->getNameTable();
eNodeType = getNodeType();
if( eNodeType == ELEMENT_NODE)
{
uiTag = ELM_ELEMENT_TAG;
uiNameId = getNameId();
}
else if( eNodeType == ATTRIBUTE_NODE)
{
uiTag = ELM_ATTRIBUTE_TAG;
uiNameId = m_uiAttrNameId;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
uiChars = uiBufSize;
if( bUnicode)
{
puzNamespaceURI = (FLMUNICODE *)pvNamespaceURI;
pszNamespaceURI = NULL;
}
else
{
puzNamespaceURI = NULL;
pszNamespaceURI = (char *)pvNamespaceURI;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum(
pDb, uiTag, uiNameId, NULL, NULL, NULL, NULL,
puzNamespaceURI, pszNamespaceURI, &uiChars, FALSE)))
{
goto Exit;
}
Exit:
if( puiCharsReturned)
{
*puiCharsReturned = uiChars;
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE F_DOMNode::getLocalName(
FLMBOOL bUnicode,
IF_Db * ifpDb,
void * pvLocalName,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiTag;
F_NameTable * pNameTable = NULL;
FLMUINT uiChars = 0;
FLMUINT uiNameId;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
pNameTable = pDb->m_pDict->getNameTable();
eNodeType = getNodeType();
if( eNodeType == ELEMENT_NODE)
{
uiTag = ELM_ELEMENT_TAG;
uiNameId = getNameId();
}
else if( eNodeType == ATTRIBUTE_NODE)
{
uiTag = ELM_ATTRIBUTE_TAG;
uiNameId = m_uiAttrNameId;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
uiChars = uiBufSize;
if( bUnicode)
{
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum( pDb,
uiTag, uiNameId, (FLMUNICODE *)pvLocalName, NULL, &uiChars)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum( pDb,
uiTag, uiNameId, NULL, (char *)pvLocalName, &uiChars)))
{
goto Exit;
}
}
Exit:
if( puiCharsReturned)
{
*puiCharsReturned = uiChars;
}
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc: Return the prefix name, either as Unicode or as Native.
*****************************************************************************/
RCODE F_DOMNode::getPrefix(
FLMBOOL bUnicode,
IF_Db * ifpDb,
void * pvPrefix,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiPrefix;
FLMUNICODE * puzPrefix = (FLMUNICODE *)pvPrefix;
char * pszPrefix = (char *)pvPrefix;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
eNodeType = getNodeType();
if( eNodeType == ELEMENT_NODE)
{
uiPrefix = getPrefixId();
}
else if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
m_uiAttrNameId, &uiPrefix)))
{
goto Exit;
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( uiPrefix)
{
if( bUnicode)
{
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
uiPrefix, puzPrefix, uiBufSize, puiCharsReturned)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
uiPrefix, pszPrefix, uiBufSize, puiCharsReturned)))
{
goto Exit;
}
}
}
else
{
if( uiBufSize)
{
if( puzPrefix)
{
*puzPrefix = 0;
}
}
if( puiCharsReturned)
{
*puiCharsReturned = 0;
}
goto Exit;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getQualifiedName(
IF_Db * ifpDb,
FLMUNICODE * puzQualifiedName,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCharsReturned;
FLMUINT uiTmp;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = getPrefix( ifpDb, puzQualifiedName,
uiBufSize, &uiCharsReturned)))
{
goto Exit;
}
if( uiCharsReturned)
{
if( puzQualifiedName)
{
uiBufSize -= (sizeof( FLMUNICODE) * uiCharsReturned);
if( uiBufSize < sizeof( FLMUNICODE) * 2)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
puzQualifiedName[ uiCharsReturned] = FLM_UNICODE_COLON;
uiCharsReturned++;
puzQualifiedName += uiCharsReturned;
uiBufSize -= sizeof( FLMUNICODE);
}
else
{
uiCharsReturned++;
}
}
if( RC_BAD( rc = getLocalName( ifpDb, puzQualifiedName, uiBufSize, &uiTmp)))
{
goto Exit;
}
uiCharsReturned += uiTmp;
if( puiCharsReturned)
{
*puiCharsReturned = uiCharsReturned;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::getQualifiedName(
IF_Db * ifpDb,
char * pszQualifiedName,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCharsReturned;
FLMUINT uiTmp;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
if( RC_BAD( rc = getPrefix( ifpDb,
pszQualifiedName, uiBufSize, &uiCharsReturned)))
{
goto Exit;
}
if( uiCharsReturned)
{
if( pszQualifiedName)
{
uiBufSize -= uiCharsReturned;
if( uiBufSize < 2)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
pszQualifiedName[ uiCharsReturned] = ASCII_COLON;
uiCharsReturned++;
pszQualifiedName += uiCharsReturned;
uiBufSize--;
}
else
{
uiCharsReturned++;
}
}
if( RC_BAD( rc = getLocalName( ifpDb,
pszQualifiedName, uiBufSize, &uiTmp)))
{
goto Exit;
}
uiCharsReturned += uiTmp;
if( puiCharsReturned)
{
*puiCharsReturned = uiCharsReturned;
}
Exit:
if( bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc: Method to set the prefix on a DOM node. Either a unicode or native
buffer may be used. ** private **
*****************************************************************************/
RCODE F_DOMNode::setPrefix(
FLMBOOL bUnicode,
IF_Db * ifpDb,
void * pvPrefix)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiPrefixId;
F_Db * pDb = (F_Db *)ifpDb;
FLMBOOL bStartedTrans = FALSE;
char * pszPrefix = (char *)pvPrefix;
FLMUNICODE * puzPrefix = (FLMUNICODE *)pvPrefix;
eDomNodeType eNodeType;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// If the node is read-only, don't allow it to be changed
if( getModeFlags() & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
eNodeType = getNodeType();
// Make sure this is an element or attribute node
if( eNodeType != ELEMENT_NODE && eNodeType != ATTRIBUTE_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
uiPrefixId = 0;
if( puzPrefix && bUnicode)
{
// Find the prefix ID
if( RC_BAD( rc = pDb->m_pDict->getPrefixId( pDb,
puzPrefix, &uiPrefixId)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_PREFIX);
}
goto Exit;
}
}
else if( pszPrefix)
{
// Find the prefix ID
if( RC_BAD( rc = pDb->m_pDict->getPrefixId( pDb,
pszPrefix, &uiPrefixId)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_PREFIX);
}
goto Exit;
}
}
// Set the prefix
if( RC_BAD( rc = setPrefixId( ifpDb, uiPrefixId)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_DOMNode::setPrefixId(
IF_Db * ifpDb,
FLMUINT uiPrefixId)
{
RCODE rc = NE_XFLM_OK;
F_Db * pDb = (F_Db *)ifpDb;
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
FLMUINT uiRflToken = 0;
eDomNodeType eNodeType;
FLMUINT uiTmp;
if( RC_BAD( rc = pDb->checkTransaction(
XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Make sure the node is current
if( RC_BAD( rc = syncFromDb( pDb)))
{
goto Exit;
}
// If the node is read-only, don't allow it to be changed
if( getModeFlags() & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
eNodeType = getNodeType();
// If the prefix isn't changing, don't do anything
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
m_uiAttrNameId, &uiTmp)))
{
goto Exit;
}
if( uiPrefixId == uiTmp)
{
goto Exit;
}
}
else if( eNodeType == ELEMENT_NODE)
{
if( uiPrefixId == getPrefixId())
{
goto Exit;
}
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Verify that the prefix is valid
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
uiPrefixId, (char *)NULL, 0, NULL)))
{
goto Exit;
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
// Set the new prefix
if( RC_BAD( rc = makeWriteCopy( pDb)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( eNodeType == ATTRIBUTE_NODE)
{
if( RC_BAD( rc = m_pCachedNode->setPrefixId( pDb,
m_uiAttrNameId, uiPrefixId)))
{
goto Exit;
}
}
else
{
setPrefixId( uiPrefixId);
}
// Update the node
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
{
goto Exit;
}
// Log the update
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeSetPrefixId( pDb,
getCollection(), getIxNodeId(),
m_uiAttrNameId, uiPrefixId)))
{
goto Exit;
}
Exit:
if( RC_BAD( rc) && bMustAbortOnError)
{
if( bMustAbortOnError)
{
pDb->setMustAbortTrans( rc);
}
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
pDb->transAbort();
}
else
{
rc = pDb->transCommit();
}
}
return( rc);
}
/****************************************************************************
Desc: Method to compare two dom nodes.
*****************************************************************************/
FLMUINT FLMAPI F_DOMNode::compareNode(
IF_DOMNode * pNode,
IF_Db * pDb1,
IF_Db * pDb2,
char * pszErrBuff,
FLMUINT uiErrBuffLen)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiEqual = 0;
F_DOMNode * pLeftNode = (F_DOMNode *)this;
F_DOMNode * pRightNode = (F_DOMNode *)pNode;
char szBuffer[ 100];
FLMUNICODE * puzVal1 = NULL;
FLMUNICODE * puzVal2 = NULL;
char * pucBinary1 = NULL;
char * pucBinary2 = NULL;
FLMUINT uiBytesReturned1;
FLMUINT uiBytesReturned2;
FLMUINT uiDataLen1;
FLMUINT uiDataLen2;
FLMUINT uiTmp1;
FLMUINT uiTmp2;
FLMUINT64 ui64Tmp1;
FLMUINT64 ui64Tmp2;
#define NODE_NOT_EQUAL 1
szBuffer[0] = '\0';
if( pLeftNode->getNodeType() != pRightNode->getNodeType())
{
f_sprintf( szBuffer, "Node Type mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getDataType( pDb1, &uiTmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getDataType( pDb2, &uiTmp2)))
{
goto Exit;
}
if( uiTmp1 != uiTmp2)
{
f_sprintf( szBuffer, "Data Type mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( pLeftNode->getCollection() != pRightNode->getCollection())
{
f_sprintf( szBuffer, "Collection mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getPrefixId( pDb1, &uiTmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getPrefixId( pDb2, &uiTmp2)))
{
goto Exit;
}
if( uiTmp1 != uiTmp2)
{
f_sprintf( szBuffer, "Prefix mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getNameId( pDb1, &uiTmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getNameId( pDb2, &uiTmp2)))
{
goto Exit;
}
if( uiTmp1 != uiTmp2)
{
f_sprintf( szBuffer, "Name Id mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getEncDefId( pDb1, &uiTmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getEncDefId( pDb2, &uiTmp2)))
{
goto Exit;
}
if( uiTmp1 != uiTmp2)
{
f_sprintf( szBuffer, "Encryption Id mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( (pLeftNode->getModeFlags() & FDOM_PERSISTENT_FLAGS) !=
(pRightNode->getModeFlags() & FDOM_PERSISTENT_FLAGS))
{
f_sprintf( szBuffer, "Flags mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getNodeId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getNodeId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Node Id mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getDocumentId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getDocumentId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Root Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getParentId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getParentId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Parent Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getFirstChildId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getFirstChildId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "First Child Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getLastChildId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getLastChildId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Last Child Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getPrevSibId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getPrevSibId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Previous Sibling Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getNextSibId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getNextSibId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Next Sibling Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getAnnotationId( pDb1, &ui64Tmp1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getAnnotationId( pDb2, &ui64Tmp2)))
{
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Annotation Node mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getDataLength( pDb1, &uiDataLen1)))
{
goto Exit;
}
if( RC_BAD( rc = pRightNode->getDataLength( pDb2, &uiDataLen2)))
{
goto Exit;
}
if( uiDataLen1 != uiDataLen2)
{
f_sprintf( szBuffer, "Data Length mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( uiDataLen1)
{
switch( pLeftNode->getDataType())
{
case XFLM_NODATA_TYPE:
{
goto Exit;
}
case XFLM_TEXT_TYPE:
{
if( RC_BAD( rc = pLeftNode->getUnicode( pDb1, &puzVal1)))
{
f_sprintf( szBuffer, "getUnicode failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pRightNode->getUnicode( pDb2, &puzVal2)))
{
f_sprintf( szBuffer, "getUnicode failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( f_unicmp( puzVal1, puzVal2) != 0)
{
f_sprintf( szBuffer, "Data Value mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
break;
}
case XFLM_NUMBER_TYPE:
{
if( RC_BAD( rc = pLeftNode->getUINT64( pDb1, &ui64Tmp1)))
{
f_sprintf( szBuffer, "getUINT64 failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pRightNode->getUINT64( pDb2, &ui64Tmp2)))
{
f_sprintf( szBuffer, "getUINT64 failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( ui64Tmp1 != ui64Tmp2)
{
f_sprintf( szBuffer, "Data Value mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
break;
}
case XFLM_BINARY_TYPE:
{
if( RC_BAD( rc = f_alloc( uiDataLen1 + 1, &pucBinary1)))
{
goto Exit;
}
if( RC_BAD( rc = f_alloc( uiDataLen2 + 1, &pucBinary2)))
{
goto Exit;
}
if( RC_BAD( rc = pLeftNode->getBinary( pDb1, pucBinary1,
0, uiDataLen1, &uiBytesReturned1)))
{
f_sprintf( szBuffer, "getBinary failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( RC_BAD( rc = pRightNode->getBinary(
pDb2, pucBinary2, 0, uiDataLen2, &uiBytesReturned2)))
{
f_sprintf( szBuffer, "getBinary failed with rc==0x%04X.",
(unsigned)rc);
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( uiBytesReturned1 != uiBytesReturned2)
{
f_sprintf( szBuffer, "Return data length mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
if( f_memcmp( pucBinary1, pucBinary2, uiBytesReturned1) != 0)
{
f_strcpy( szBuffer, "Data Value mismatch");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
break;
}
default:
{
f_strcpy( szBuffer, "Invalid Data Type");
uiEqual = NODE_NOT_EQUAL;
goto Exit;
}
}
}
Exit:
f_memcpy( pszErrBuff, szBuffer, f_min( uiErrBuffLen, f_strlen( szBuffer)));
pszErrBuff[ f_min( uiErrBuffLen, f_strlen( szBuffer))] = '\0';
if( puzVal1)
{
f_free( &puzVal1);
}
if( puzVal2)
{
f_free( &puzVal2);
}
if( pucBinary1)
{
f_free( &pucBinary1);
}
if( pucBinary2)
{
f_free( &pucBinary2);
}
return( uiEqual);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_Db::getDictionaryDef(
FLMUINT uiDictType,
FLMUINT uiDictNumber,
IF_DOMNode ** ppDocumentNode)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
F_DataVector searchKey;
F_DataVector foundKey;
searchKey.reset();
foundKey.reset();
if( RC_BAD( rc = checkTransaction(
XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = searchKey.setUINT( 0, uiDictType)))
{
goto Exit;
}
if( RC_BAD( rc = searchKey.setUINT( 1, uiDictNumber)))
{
goto Exit;
}
if( RC_BAD( rc = keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
if( RC_BAD( rc = getNode( XFLM_DICT_COLLECTION,
foundKey.getDocumentID(), ppDocumentNode)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getElementNameId(
const FLMUNICODE * puzNamespaceURI,
const FLMUNICODE * puzElementName,
FLMUINT * puiElementNameId)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_ELEMENT_TAG, puzElementName, NULL,
TRUE, puzNamespaceURI, puiElementNameId)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getElementNameId(
const char * pszNamespaceURI,
const char * pszElementName,
FLMUINT * puiElementNameId)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE * puzNamespaceURI = NULL;
FLMUNICODE * puzTmp;
const char * pszTmp;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( pszNamespaceURI && *pszNamespaceURI)
{
if( RC_BAD( rc = f_alloc( (f_strlen( pszNamespaceURI) + 1) *
sizeof( FLMUNICODE), &puzNamespaceURI)))
{
goto Exit;
}
pszTmp = pszNamespaceURI;
puzTmp = puzNamespaceURI;
while (*pszTmp)
{
*puzTmp = (FLMUNICODE)(*pszTmp);
pszTmp++;
puzTmp++;
}
*puzTmp = 0;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_ELEMENT_TAG, NULL, pszElementName,
TRUE, puzNamespaceURI, puiElementNameId)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
if( puzNamespaceURI)
{
f_free( &puzNamespaceURI);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getAttributeNameId(
const FLMUNICODE * puzNamespaceURI,
const FLMUNICODE * puzAttributeName,
FLMUINT * puiAttributeNameId)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_ATTRIBUTE_TAG, puzAttributeName, NULL,
TRUE, puzNamespaceURI, puiAttributeNameId)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getAttributeNameId(
const char * pszNamespaceURI,
const char * pszAttributeName,
FLMUINT * puiAttributeNameId)
{
RCODE rc = NE_XFLM_OK;
FLMUNICODE * puzNamespaceURI = NULL;
FLMUNICODE * puzTmp;
const char * pszTmp;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( pszNamespaceURI && *pszNamespaceURI)
{
if( RC_BAD( rc = f_alloc( (f_strlen( pszNamespaceURI) + 1) *
sizeof( FLMUNICODE), &puzNamespaceURI)))
{
goto Exit;
}
pszTmp = pszNamespaceURI;
puzTmp = puzNamespaceURI;
while (*pszTmp)
{
*puzTmp = (FLMUNICODE)(*pszTmp);
pszTmp++;
puzTmp++;
}
*puzTmp = 0;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_ATTRIBUTE_TAG, NULL, pszAttributeName,
TRUE, puzNamespaceURI, puiAttributeNameId)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
if( puzNamespaceURI)
{
f_free( &puzNamespaceURI);
}
return( rc);
}
/*****************************************************************************
Desc: Get a collection number from collection name.
******************************************************************************/
RCODE FLMAPI F_Db::getCollectionNumber(
const char * pszCollectionName,
FLMUINT * puiCollectionNumber)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_COLLECTION_TAG, NULL, pszCollectionName,
FALSE, NULL, puiCollectionNumber)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Get a collection number from collection name.
******************************************************************************/
RCODE FLMAPI F_Db::getCollectionNumber(
const FLMUNICODE * puzCollectionName,
FLMUINT * puiCollectionNumber)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_COLLECTION_TAG, puzCollectionName, NULL,
FALSE, NULL, puiCollectionNumber)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Get an index number from index name.
******************************************************************************/
RCODE FLMAPI F_Db::getIndexNumber(
const char * pszIndexName,
FLMUINT * puiIndexNumber)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_INDEX_TAG, NULL, pszIndexName,
FALSE, NULL, puiIndexNumber)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Get an index number from index name.
******************************************************************************/
RCODE FLMAPI F_Db::getIndexNumber(
const FLMUNICODE * puzIndexName,
FLMUINT * puiIndexNumber)
{
RCODE rc = NE_XFLM_OK;
F_NameTable * pNameTable = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this, ELM_INDEX_TAG, puzIndexName, NULL,
FALSE, NULL, puiIndexNumber)))
{
goto Exit;
}
Exit:
if( pNameTable)
{
pNameTable->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createDocument(
FLMUINT uiCollection,
IF_DOMNode ** ppDocument,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
if( uiCollection == XFLM_MAINT_COLLECTION)
{
// Users are not allowed to create documents in the
// maintenance collection
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = createRootNode( uiCollection, 0,
DOCUMENT_NODE, (F_DOMNode **)ppDocument, pui64NodeId)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createRootElement(
FLMUINT uiCollection,
FLMUINT uiNameId,
IF_DOMNode ** ppElement,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
if( uiCollection == XFLM_MAINT_COLLECTION)
{
// Users are not allowed to create documents in the
// maintenance collection
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = createRootNode( uiCollection, uiNameId,
ELEMENT_NODE, (F_DOMNode **)ppElement, pui64NodeId)))
{
goto Exit;
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::checkAndUpdateState(
eDomNodeType eNodeType,
FLMUINT uiNameId)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bUserDefined = FALSE;
FLMUINT uiDictType = 0;
F_AttrElmInfo defInfo;
// The F_AttrElmInfo constructor should have set the state
// to active.
flmAssert( defInfo.m_uiState == ATTR_ELM_STATE_ACTIVE);
if( eNodeType == ATTRIBUTE_NODE)
{
uiDictType = ELM_ATTRIBUTE_TAG;
if( RC_BAD( rc = m_pDict->getAttribute( this, uiNameId, &defInfo)))
{
goto Exit;
}
bUserDefined = attributeIsUserDefined( uiNameId);
}
else if( eNodeType == ELEMENT_NODE)
{
uiDictType = ELM_ELEMENT_TAG;
if( RC_BAD( rc = m_pDict->getElement( this, uiNameId, &defInfo)))
{
goto Exit;
}
bUserDefined = elementIsUserDefined( uiNameId);
}
else if( eNodeType == DATA_NODE)
{
if( uiNameId)
{
uiDictType = ELM_ELEMENT_TAG;
if( RC_BAD( rc = m_pDict->getElement( this, uiNameId, &defInfo)))
{
goto Exit;
}
bUserDefined = elementIsUserDefined( uiNameId);
}
}
else if( eNodeType != COMMENT_NODE &&
eNodeType != DOCUMENT_NODE &&
eNodeType != ANNOTATION_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
if( bUserDefined && defInfo.m_uiState != ATTR_ELM_STATE_ACTIVE)
{
if( defInfo.m_uiState == ATTR_ELM_STATE_PURGE )
{
// Marked as 'purged'. So, user is not allowed to add
// new instances of this field.
rc = (RCODE)(eNodeType == ELEMENT_NODE
? RC_SET( NE_XFLM_ELEMENT_PURGED)
: RC_SET( NE_XFLM_ATTRIBUTE_PURGED));
goto Exit;
}
else if( defInfo.m_uiState == ATTR_ELM_STATE_CHECKING)
{
// Because an occurance is being added, update the
// state to be 'active'
if( RC_BAD( rc = changeItemState( uiDictType, uiNameId,
XFLM_ACTIVE_OPTION_STR)))
{
goto Exit;
}
}
}
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::_updateNode(
F_CachedNode * pCachedNode,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCollection = pCachedNode->getCollection();
F_COLLECTION * pCollection;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bAdd = (uiFlags & FLM_UPD_ADD) ? TRUE : FALSE;
F_AttrElmInfo defInfo;
// Logging should be done at a higher level
flmAssert( !m_pDatabase->m_pRfl->isLoggingEnabled());
flmAssert( uiCollection);
// Mark the node as being dirty
pCachedNode->setNodeDirty( this, bAdd);
if( bAdd)
{
// Get a pointer to the collection
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
// If the nodeId is greater than or equal to the next nodeId, we
// will set the next nodeId to 1 greater than the new nodeId to avoid
// running into the same nodeId later.
//
// Node ID should already be set at this point.
flmAssert( pCachedNode->getNodeId());
if( pCachedNode->getNodeId() >= pCollection->ui64NextNodeId)
{
pCollection->ui64NextNodeId = pCachedNode->getNodeId() + 1;
pCollection->bNeedToUpdateNodes = TRUE;
}
bMustAbortOnError = TRUE;
}
else if( !pCachedNode->getNodeId())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_TRANS_OP);
goto Exit;
}
// Add the document to the list of documents that need to have
// documentDone called at commit time.
if( !(uiFlags & FLM_UPD_INTERNAL_CHANGE) &&
uiCollection == XFLM_DICT_COLLECTION)
{
if( RC_BAD( rc = m_pDatabase->m_DocumentList.addNode(
pCachedNode->getCollection(), pCachedNode->getDocumentId(), 0)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc) && bMustAbortOnError)
{
setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::getCachedBTree(
FLMUINT uiCollection,
F_Btree ** ppBTree)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( m_pCachedBTree)
{
flmAssert( m_pCachedBTree->getRefCount() == 1);
m_pCachedBTree->btClose();
}
else
{
// Reserve a B-Tree from the pool
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree(
&m_pCachedBTree)))
{
goto Exit;
}
}
// Set up the btree object
if( RC_BAD( rc = m_pCachedBTree->btOpen( this,
&pCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
m_pCachedBTree->AddRef();
*ppBTree = m_pCachedBTree;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::flushNode(
F_Btree * pBTree,
F_CachedNode * pCachedNode)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
FLMUINT64 ui64NodeId = pCachedNode->getNodeId();
FLMBYTE ucKeyBuf[ FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMUINT uiHeaderStorageSize;
F_DynaBuf dynaBuf( m_pDatabase->m_pucUpdBuffer, m_pDatabase->m_uiUpdBufferSize);
FLMBOOL bMustAbortOnError = FALSE;
IF_PosIStream * pIStream = NULL;
FLMBYTE * pucSrc = NULL;
FLMBYTE * pucTmp;
FLMBOOL bOutputNodeData;
FLMBOOL bTruncateOnReplace;
FLMUINT32 ui32BlkAddr;
FLMUINT uiOffsetIndex;
FLMBYTE * pucIV = NULL;
FLMUINT uiIVLen = 0;
FLMUINT uiEncDefId = pCachedNode->getEncDefId();
eDomNodeType eNodeType = pCachedNode->getNodeType();
FLMUINT uiNodeDataLength;
// Node should be dirty
flmAssert( pCachedNode->nodeIsDirty());
// Transaction IDs should match
if( pCachedNode->getLowTransId() != getTransID())
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
uiNodeDataLength = pCachedNode->m_nodeInfo.uiDataLength;
// Output the header
if( (pCachedNode->getModeFlags() & FDOM_FIXED_SIZE_HEADER) == 0)
{
if( RC_BAD( rc = dynaBuf.allocSpace( MAX_DOM_HEADER_SIZE,
(void **)&pucTmp)))
{
goto Exit;
}
if( RC_BAD( rc = pCachedNode->headerToBuf( FALSE,
pucTmp, &uiHeaderStorageSize, NULL, NULL)))
{
goto Exit;
}
dynaBuf.truncateData( uiHeaderStorageSize);
}
else
{
if( RC_BAD( rc = dynaBuf.allocSpace( FIXED_DOM_HEADER_SIZE,
(void **)&pucTmp)))
{
goto Exit;
}
if( RC_BAD( rc = pCachedNode->headerToBuf( TRUE, pucTmp,
&uiHeaderStorageSize, NULL, NULL)))
{
goto Exit;
}
}
// Get a pointer to the collection
if( RC_BAD( rc = m_pDict->getCollection( pCachedNode->getCollection(),
&pCollection)))
{
goto Exit;
}
uiKeyLen = sizeof( ucKeyBuf);
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId,
&uiKeyLen, ucKeyBuf, FALSE, TRUE)))
{
goto Exit;
}
if( eNodeType == ELEMENT_NODE)
{
FLMUINT uiLoop;
NODE_ITEM * pNodeItem;
FLMUINT uiNodeCount = pCachedNode->getChildElmCount();
FLMUINT uiTmpOffset;
FLMUINT uiPrevNameId = 0;
FLMUINT64 ui64ElmNodeId = pCachedNode->getNodeId();
// Go through the child element list and output them to the buffer
// Note that the child element node count has already been output
// as part of the node header.
pNodeItem = pCachedNode->m_pNodeList;
for( uiLoop = 0; uiLoop < uiNodeCount; pNodeItem++, uiLoop++)
{
uiTmpOffset = dynaBuf.getDataLength();
if( RC_BAD( rc = dynaBuf.allocSpace( FLM_MAX_SEN_LEN * 2,
(void **)&pucTmp)))
{
goto Exit;
}
flmAssert( pNodeItem->uiNameId > uiPrevNameId);
flmAssert( pNodeItem->ui64NodeId > ui64ElmNodeId);
uiTmpOffset += f_encodeSEN( pNodeItem->uiNameId - uiPrevNameId,
&pucTmp);
uiTmpOffset += f_encodeSEN( pNodeItem->ui64NodeId - ui64ElmNodeId,
&pucTmp);
uiPrevNameId = pNodeItem->uiNameId;
dynaBuf.truncateData( uiTmpOffset);
}
// Export any attributes on the element
if( pCachedNode->m_uiAttrCount)
{
if( RC_BAD( rc = pCachedNode->exportAttributeList( this,
&dynaBuf, NULL)))
{
goto Exit;
}
}
}
// Set up to output data
if( uiNodeDataLength)
{
if( pCachedNode->getModeFlags() & FDOM_VALUE_ON_DISK)
{
if( pCachedNode->getModeFlags() & FDOM_FIXED_SIZE_HEADER)
{
bOutputNodeData = FALSE;
bTruncateOnReplace = FALSE;
}
else
{
// If the value is on disk and we don't have a fixed-size header,
// we'll have to read and output the entire node value.
flmAssert( eNodeType != ELEMENT_NODE);
if( RC_BAD( rc = pCachedNode->getIStream( this, NULL, &pIStream)))
{
goto Exit;
}
bOutputNodeData = TRUE;
bTruncateOnReplace = TRUE;
}
}
else
{
pucSrc = pCachedNode->getDataPtr();
bOutputNodeData = TRUE;
bTruncateOnReplace = TRUE;
}
}
else
{
bOutputNodeData = FALSE;
bTruncateOnReplace = TRUE;
}
if( bOutputNodeData)
{
FLMUINT uiDataOutputSize = uiNodeDataLength;
if( uiEncDefId)
{
F_ENCDEF * pEncDef;
if( RC_BAD( rc = m_pDict->getEncDef( uiEncDefId, &pEncDef)))
{
goto Exit;
}
uiIVLen = pEncDef->pCcs->getIVLen();
flmAssert( uiIVLen == 8 || uiIVLen == 16);
if( RC_BAD( rc = dynaBuf.allocSpace( uiIVLen, (void **)&pucIV)))
{
goto Exit;
}
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, pucIV)))
{
goto Exit;
}
uiDataOutputSize = getEncLen( uiNodeDataLength);
}
if( RC_BAD( rc = dynaBuf.allocSpace( uiDataOutputSize,
(void **)&pucTmp)))
{
goto Exit;
}
if( pIStream)
{
if( RC_BAD( rc = pIStream->read( pucTmp, uiNodeDataLength, NULL)))
{
goto Exit;
}
}
else
{
f_memcpy( pucTmp, pucSrc, uiNodeDataLength);
}
if( uiEncDefId)
{
if( RC_BAD( rc = encryptData( uiEncDefId, pucIV,
pucTmp, uiDataOutputSize, uiNodeDataLength, &uiDataOutputSize)))
{
goto Exit;
}
}
}
ui32BlkAddr = pCachedNode->getBlkAddr();
uiOffsetIndex = pCachedNode->getOffsetIndex();
if( pCachedNode->nodeIsNew())
{
// If this is a new node, the value will not be on disk.
// This routine is only called for values that we are
// keeping in memory. If we stream a value out through
// multiple buffers, it is written right away and the
// node's dirty and new flags will be unset as soon as
// the writing is done.
if( pCachedNode->getModeFlags() & FDOM_VALUE_ON_DISK)
{
// This shouldn't happen
rc = RC_SET_AND_ASSERT( NE_XFLM_FAILURE);
goto Exit;
}
if( RC_BAD( rc = pBTree->btInsertEntry(
ucKeyBuf, uiKeyLen,
dynaBuf.getBufferPtr(), dynaBuf.getDataLength(),
TRUE, TRUE, &ui32BlkAddr, &uiOffsetIndex)))
{
if( rc == NE_XFLM_NOT_UNIQUE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_EXISTS);
}
goto Exit;
}
}
else
{
// Replace the node on disk.
if( RC_BAD( rc = pBTree->btReplaceEntry(
ucKeyBuf, uiKeyLen,
dynaBuf.getBufferPtr(), dynaBuf.getDataLength(),
TRUE, TRUE, bTruncateOnReplace, &ui32BlkAddr,
&uiOffsetIndex)))
{
goto Exit;
}
}
pCachedNode->setBlkAddr( ui32BlkAddr);
pCachedNode->setOffsetIndex( uiOffsetIndex);
// Clear the dirty flag and the new flag.
pCachedNode->unsetNodeDirtyAndNew( this);
Exit:
if( pIStream)
{
pIStream->Release();
}
if( RC_BAD( rc) && bMustAbortOnError)
{
setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::encryptData(
FLMUINT uiEncDefId,
FLMBYTE * pucIV,
FLMBYTE * pucBuffer,
FLMUINT uiBufferSize,
FLMUINT uiDataLen,
FLMUINT * puiOutputLength)
{
RCODE rc = NE_XFLM_OK;
F_Dict * pDict;
F_ENCDEF * pEncDef;
FLMUINT uiEncLen;
FLMUINT uiTmpLen;
FLMUINT uiEncBuffLen;
FLMUINT uiDataToEncrypt = uiDataLen;
FLMUINT uiChunkLen;
FLMBYTE * pucEncTmp;
FLMBYTE ucEncryptBuffer[ FLM_ENCRYPT_CHUNK_SIZE];
if( m_pDatabase->m_bInLimitedMode)
{
*puiOutputLength = uiDataLen;
rc = RC_SET( m_pDatabase->m_rcLimitedCode);
goto Exit;
}
// Need to retrieve the encryption key.
if( RC_BAD( rc = getDictionary( &pDict)))
{
goto Exit;
}
if( RC_BAD( rc = pDict->getEncDef( uiEncDefId, &pEncDef)))
{
goto Exit;
}
flmAssert( pEncDef);
flmAssert( pEncDef->pCcs);
// Check first to make sure we wil be able to encrypt the entire buffer
// since we must return the encrypted data in the source buffer.
uiEncLen = getEncLen( uiDataLen);
if( uiEncLen > uiBufferSize)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
// Encrypt the buffer in chunks
uiEncBuffLen = 0;
pucEncTmp = &ucEncryptBuffer[0];
while( uiDataToEncrypt)
{
FLMUINT uiDataEncrypted;
uiDataEncrypted = uiChunkLen = ((uiDataToEncrypt > FLM_ENCRYPT_CHUNK_SIZE)
? FLM_ENCRYPT_CHUNK_SIZE
: uiDataToEncrypt);
if( extraEncBytes( uiChunkLen) != 0)
{
// If we are padding, we *MUST* be on the last piece to encrypt!
flmAssert( uiChunkLen == uiDataToEncrypt);
uiChunkLen += (ENCRYPT_MIN_CHUNK_SIZE - extraEncBytes( uiChunkLen));
}
flmAssert( uiChunkLen <= FLM_ENCRYPT_CHUNK_SIZE);
uiTmpLen = uiChunkLen;
if( RC_BAD( rc = pEncDef->pCcs->encryptToStore(
pucBuffer, uiChunkLen, pucEncTmp, &uiTmpLen, pucIV)))
{
goto Exit;
}
flmAssert( uiTmpLen == uiChunkLen);
f_memcpy( pucBuffer, pucEncTmp, uiChunkLen);
pucBuffer += uiChunkLen;
uiDataToEncrypt -= uiDataEncrypted;
uiEncBuffLen += uiChunkLen;
flmAssert( uiEncBuffLen <= uiEncLen);
}
flmAssert( uiEncBuffLen == uiEncLen);
*puiOutputLength = uiEncLen;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createRootNode(
FLMUINT uiCollection,
FLMUINT uiElementNameId,
eDomNodeType eNodeType,
F_DOMNode ** ppNewNode,
FLMUINT64 * pui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_Rfl * pRfl = m_pDatabase->m_pRfl;
F_DOMNode * pPrevSib = NULL;
F_DOMNode * pNewNode = NULL;
F_CachedNode * pCachedNode;
F_COLLECTION * pCollection;
FLMBOOL bMustAbortOnError = FALSE;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiRflToken = 0;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( eNodeType != ELEMENT_NODE && eNodeType != DOCUMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// If a specific node Id is requested, check to make sure it is not
// already in use.
if( pui64NodeId)
{
if( *pui64NodeId && (m_uiFlags & FDB_REBUILDING_DATABASE))
{
if( RC_OK( rc = getNode( uiCollection, *pui64NodeId, &pNewNode)))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
else if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
else
{
// Set the value to zero so we don't use it. We will
// return the new nodeId.
*pui64NodeId = 0;
}
}
bMustAbortOnError = TRUE;
// Check the state if this is a root element
if( eNodeType == ELEMENT_NODE)
{
if( RC_BAD( rc = checkAndUpdateState( ELEMENT_NODE, uiElementNameId)))
{
goto Exit;
}
}
// Disable RFL logging
pRfl->disableLogging( &uiRflToken);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( this,
uiCollection,
(FLMUINT64)(pui64NodeId
? *pui64NodeId
: (FLMUINT64)0),
&pNewNode)))
{
goto Exit;
}
// Clone the dictionary since the first/last document ID
// values of the collection will be changed
if( !(m_uiFlags & FDB_UPDATED_DICTIONARY))
{
if( RC_BAD( rc = dictClone()))
{
goto Exit;
}
}
// Get a pointer to the collection
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
pCachedNode = pNewNode->m_pCachedNode;
if( !pCollection->ui64FirstDocId)
{
pCollection->ui64FirstDocId = pCollection->ui64NextNodeId;
pCollection->ui64LastDocId = pCollection->ui64NextNodeId;
}
else
{
pCachedNode->setPrevSibId( pCollection->ui64LastDocId);
pCollection->ui64LastDocId = pCollection->ui64NextNodeId;
}
pCollection->bNeedToUpdateNodes = TRUE;
if( eNodeType == ELEMENT_NODE)
{
F_AttrElmInfo elmInfo;
if( RC_BAD( rc = m_pDict->getElement( this, uiElementNameId, &elmInfo)))
{
goto Exit;
}
pCachedNode->setNameId( uiElementNameId);
pCachedNode->setDataType( elmInfo.m_uiDataType);
// Is this a node whose child elements must all be unique?
if( elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
{
flmAssert( elmInfo.m_uiDataType == XFLM_NODATA_TYPE);
pCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
}
}
else
{
pCachedNode->setDataType( XFLM_NODATA_TYPE);
}
pCachedNode->setNodeType( eNodeType);
pCachedNode->setDocumentId( pCachedNode->getNodeId());
// Link the document into the document list
bMustAbortOnError = TRUE;
if( pui64NodeId && *pui64NodeId)
{
pCollection->ui64LastDocId = *pui64NodeId;
pCollection->bNeedToUpdateNodes = TRUE;
}
// Output the node
if( RC_BAD( rc = updateNode( pCachedNode, FLM_UPD_ADD)))
{
goto Exit;
}
// Retrieve the previous sibling and set its next sibling
// value
if( pCachedNode->getPrevSibId())
{
if( RC_BAD( rc = getNode( uiCollection,
pCachedNode->getPrevSibId(), &pPrevSib)))
{
goto Exit;
}
if( RC_BAD( rc = pPrevSib->makeWriteCopy( this)))
{
goto Exit;
}
pPrevSib->setNextSibId( pCachedNode->getNodeId());
if( RC_BAD( rc = updateNode( pPrevSib->m_pCachedNode,
FLM_UPD_INTERNAL_CHANGE)))
{
goto Exit;
}
}
// Check indexing if it is an element
if( eNodeType == ELEMENT_NODE)
{
if( RC_BAD( rc = updateIndexKeys(
uiCollection, pNewNode, IX_ADD_NODE_VALUE, TRUE)))
{
goto Exit;
}
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logNodeCreate( this, pCachedNode->getCollection(),
pCachedNode->getNodeId(), eNodeType, uiElementNameId,
XFLM_ROOT, pNewNode->getNodeId())))
{
goto Exit;
}
if( pui64NodeId)
{
*pui64NodeId = pCachedNode->getNodeId();
}
if( ppNewNode)
{
if( *ppNewNode)
{
(*ppNewNode)->Release();
}
*ppNewNode = pNewNode;
pNewNode = NULL;
}
Exit:
if( pNewNode)
{
pNewNode->Release();
}
if( pPrevSib)
{
pPrevSib->Release();
}
if( RC_BAD( rc) && bMustAbortOnError)
{
setMustAbortTrans( rc);
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::findNode(
FLMUINT uiCollection,
FLMUINT64 * pui64NodeId,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
F_Btree * pBTree = NULL;
F_BTreeIStream btreeIStream;
// Determine the node's B-Tree address
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBTree)))
{
goto Exit;
}
// At this point, we know that uiFlags is NOT XFLM_EXACT, but is
// XFLM_INCL, XFLM_EXCL, XFLM_FIRST, or XFLM_LAST. So we will
// need to reassign ui64NodeId once we have located the node.
if( RC_BAD( rc = btreeIStream.open( this, pBTree,
uiFlags, uiCollection, *pui64NodeId, 0, 0)))
{
goto Exit;
}
*pui64NodeId = btreeIStream.m_ui64NodeId;
// Close the input stream
btreeIStream.close();
Exit:
if( pBTree)
{
pBTree->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::getNode(
FLMUINT uiCollection,
FLMUINT64 ui64NodeId,
FLMUINT uiFlags,
F_DOMNode ** ppNode)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Quick check to see if the user is re-retrieving the same
// node that is currently pointed to by pNode
if( uiFlags == XFLM_EXACT)
{
F_DOMNode * pTmpNode;
if( ((pTmpNode = *ppNode) != NULL) &&
pTmpNode->m_pCachedNode && pTmpNode->m_uiAttrNameId == 0)
{
if( pTmpNode->getNodeId() == ui64NodeId &&
pTmpNode->getCollection() == uiCollection &&
pTmpNode->getDatabase() == m_pDatabase)
{
if( RC_BAD( rc = pTmpNode->syncFromDb( this)))
{
if( rc == NE_XFLM_DOM_NODE_DELETED)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
}
goto Exit;
}
}
}
else
{
if( getTransType() == XFLM_UPDATE_TRANS)
{
// Need to flush dirty nodes through to the B-Tree so that
// look-ups will work correctly
if( RC_BAD( rc = flushDirtyNodes()))
{
goto Exit;
}
}
if( RC_BAD( rc = findNode( uiCollection, &ui64NodeId, uiFlags)))
{
goto Exit;
}
}
// Retrieve the node into cache.
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->retrieveNode( this,
uiCollection, ui64NodeId, &pNode)))
{
goto Exit;
}
if( *ppNode)
{
(*ppNode)->Release();
}
*ppNode = pNode;
pNode = NULL;
Exit:
if( pNode)
{
pNode->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getAttribute(
FLMUINT uiCollection,
FLMUINT64 ui64ElementId,
FLMUINT uiAttrName,
IF_DOMNode ** ifppAttr)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pElementNode = NULL;
F_DOMNode * pAttrNode = NULL;
F_AttrItem * pAttrItem;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = getNode( uiCollection, ui64ElementId,
XFLM_EXACT, &pElementNode)))
{
goto Exit;
}
if( pElementNode->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( (pAttrItem = pElementNode->m_pCachedNode->getAttribute( uiAttrName,
NULL)) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttrNode->m_pCachedNode = pElementNode->m_pCachedNode;
pAttrNode->m_pCachedNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
if( ifppAttr)
{
if( *ifppAttr)
{
(*ifppAttr)->Release();
}
*ifppAttr = (IF_DOMNode *)pAttrNode;
pAttrNode = NULL;
}
Exit:
if( pAttrNode)
{
pAttrNode->Release();
}
if( pElementNode)
{
pElementNode->Release();
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getFirstDocument(
FLMUINT uiCollection,
IF_DOMNode ** ppDocumentNode)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( !pCollection->ui64FirstDocId)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64FirstDocId,
ppDocumentNode)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getLastDocument(
FLMUINT uiCollection,
IF_DOMNode ** ppDocumentNode)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
if( !pCollection->ui64LastDocId)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64LastDocId,
ppDocumentNode)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE FLMAPI F_Db::getDocument(
FLMUINT uiCollection,
FLMUINT uiFlags,
FLMUINT64 ui64DocumentId,
IF_DOMNode ** ppDocumentNode)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
FLMBOOL bStartedTrans = FALSE;
F_Btree * pBTree = NULL;
F_DOMNode * pNode = NULL;
FLMBYTE ucKey [FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen;
FLMBOOL bNeg;
FLMUINT uiBytesProcessed;
FLMUINT64 ui64NodeId;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
goto Exit;
}
switch (uiFlags)
{
case XFLM_FIRST:
{
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64FirstDocId,
ppDocumentNode)))
{
goto Exit;
}
break;
}
case XFLM_LAST:
{
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64LastDocId,
ppDocumentNode)))
{
goto Exit;
}
break;
}
case XFLM_EXACT:
{
if( RC_BAD( rc = getNode( uiCollection, ui64DocumentId, &pNode)))
{
goto Exit;
}
if( !pNode->isRootNode())
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( *ppDocumentNode)
{
(*ppDocumentNode)->Release();
}
// No need to do an AddRef on ppDocumentNode - just use the reference
// from pNode and set pNode to NULL so it won't be released
*ppDocumentNode = pNode;
pNode = NULL;
break;
}
case XFLM_INCL:
case XFLM_EXCL:
{
if( getTransType() == XFLM_UPDATE_TRANS)
{
// Need to flush dirty nodes through to the B-Tree so that
// look-ups will work correctly
if( RC_BAD( rc = flushDirtyNodes()))
{
goto Exit;
}
}
// Get a btree
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btOpen( this, &pCollection->lfInfo,
FALSE, TRUE)))
{
goto Exit;
}
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( ui64DocumentId, &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = pBTree->btLocateEntry(
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_INCL)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
// Make sure we hit a root node. If not, continue reading until we do
// or until we hit the end. Root nodes are always linked together in
// ascending order, so if there is another document, we will find it
// simply by searching forward from where we are. Then we can follow
// document links.
for (;;)
{
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
&ui64NodeId, &bNeg, &uiBytesProcessed)))
{
goto Exit;
}
if( RC_BAD( rc = getNode( uiCollection, ui64NodeId, &pNode)))
{
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// Better be able to find the node at this point!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
// If the node is a root node, we have a document we can
// process.
if( pNode->isRootNode())
{
if( uiFlags == XFLM_EXCL && ui64NodeId == ui64DocumentId)
{
if( RC_BAD( rc = pNode->getNextDocument( this, ppDocumentNode)))
{
goto Exit;
}
}
else
{
if( *ppDocumentNode)
{
(*ppDocumentNode)->Release();
}
// No need to do an AddRef on ppDocumentNode - just use the reference
// from pNode and set pNode to NULL so it won't be released
*ppDocumentNode = pNode;
pNode = NULL;
}
break;
}
// Need to go to the next node.
if( RC_BAD( rc = pBTree->btNextEntry( ucKey, uiKeyLen, &uiKeyLen)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
}
goto Exit;
}
}
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( pBTree)
{
gv_XFlmSysData.pBtPool->btpReturnBtree( &pBTree);
}
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc:
Notes: This routine assumes that the node has been unlinked. It doesn't
perform any checks to guarantee that removing the node won't cause
referential integrity problems.
******************************************************************************/
RCODE F_Db::purgeNode(
FLMUINT uiCollection,
FLMUINT64 ui64NodeId)
{
RCODE rc = NE_XFLM_OK;
F_Btree * pBTree = NULL;
FLMUINT uiKeyLen;
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
FLMBOOL bStartedTrans = FALSE;
FLMBOOL bMustAbortOnError = FALSE;
// Make sure we're in an update transaction
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Remove the node from the collection
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBTree)))
{
goto Exit;
}
uiKeyLen = sizeof( ucKey);
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId,
&uiKeyLen, ucKey, FALSE, TRUE)))
{
goto Exit;
}
bMustAbortOnError = TRUE;
if( RC_BAD( rc = pBTree->btRemoveEntry( ucKey, uiKeyLen)))
{
if( rc != NE_XFLM_NOT_FOUND)
{
goto Exit;
}
// Item may not have been flushed from cache yet
rc = NE_XFLM_OK;
}
// Remove the node from the cache
gv_XFlmSysData.pNodeCacheMgr->removeNode( this, uiCollection, ui64NodeId);
Exit:
if( pBTree)
{
pBTree->Release();
}
if( RC_BAD( rc))
{
if( bMustAbortOnError)
{
setMustAbortTrans( rc);
}
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::documentDone(
FLMUINT uiCollection,
FLMUINT64 ui64DocId)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiRflToken = 0;
F_Rfl * pRfl = m_pDatabase->m_pRfl;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( !m_pDatabase->m_DocumentList.isNodeInList( uiCollection, ui64DocId, 0))
{
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
if( uiCollection == XFLM_DICT_COLLECTION)
{
FLMUINT uiDictDefType;
if( RC_BAD( rc = dictDocumentDone( ui64DocId, FALSE, &uiDictDefType)))
{
goto Exit;
}
// If this is an encryption definition, we need to log the encryption
// key
if( uiDictDefType == ELM_ENCDEF_TAG && !(m_uiFlags & FDB_REPLAYING_RFL))
{
FLMBYTE ucDynaBuf[ 64];
F_DynaBuf keyBuffer( ucDynaBuf, sizeof( ucDynaBuf));
FLMUINT uiKeySize;
if( RC_BAD( rc = getNode( uiCollection, ui64DocId,
XFLM_EXACT, &pNode)))
{
RC_UNEXPECTED_ASSERT( rc);
goto Exit;
}
if( RC_BAD( rc = pNode->getAttributeValueBinary( this,
ATTR_ENCRYPTION_KEY_TAG, &keyBuffer)))
{
RC_UNEXPECTED_ASSERT( rc);
goto Exit;
}
if( RC_BAD( rc = pNode->getAttributeValueUINT( this,
ATTR_ENCRYPTION_KEY_SIZE_TAG, &uiKeySize)))
{
goto Exit;
}
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logEncDefKey( this, (FLMUINT)ui64DocId,
keyBuffer.getBufferPtr(), keyBuffer.getDataLength(), uiKeySize)))
{
goto Exit;
}
pRfl->disableLogging( &uiRflToken);
}
}
m_pDatabase->m_DocumentList.removeNode( uiCollection, ui64DocId, 0);
pRfl->enableLogging( &uiRflToken);
if( RC_BAD( rc = pRfl->logDocumentDone( this, uiCollection, ui64DocId)))
{
goto Exit;
}
Exit:
if( pNode)
{
pNode->Release();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::documentDone(
IF_DOMNode * pDocNode)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
FLMUINT uiCollection;
FLMUINT64 ui64DocId;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = pDocNode->getCollection( this, &uiCollection)))
{
goto Exit;
}
if( RC_BAD( rc = pDocNode->getDocumentId( this, &ui64DocId)))
{
goto Exit;
}
if( RC_BAD( rc = documentDone( uiCollection, ui64DocId)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::import(
IF_IStream * ifpStream,
FLMUINT uiCollection,
IF_DOMNode * pNodeToLinkTo,
eNodeInsertLoc eInsertLoc,
XFLM_IMPORT_STATS * pImportStats)
{
RCODE rc = NE_XFLM_OK;
F_XMLImport xmlImport;
F_DOMNode * pNode = NULL;
F_DOMNode * pNewNode = NULL;
if( RC_BAD( rc = xmlImport.setup()))
{
goto Exit;
}
if( (pNode = (F_DOMNode *)pNodeToLinkTo) != NULL)
{
pNode->AddRef();
}
for( ;;)
{
if( RC_BAD( rc = xmlImport.import( ifpStream, this, uiCollection,
FLM_XML_COMPRESS_WHITESPACE_FLAG |
FLM_XML_TRANSLATE_ESC_FLAG |
FLM_XML_EXTEND_DICT_FLAG, pNode, eInsertLoc,
&pNewNode, pImportStats)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
if( RC_BAD( rc = documentDone( pNewNode)))
{
goto Exit;
}
// If pNode is NULL, we are creating separate documents
// and pNode should remain NULL. Otherwise, it should be
// set to the newly created node, and all subsequent trees
// should be linked as next siblings after this one.
if( pNode)
{
pNode->Release();
pNode = pNewNode;
// No need to do pNode->AddRef() and pNewNode->Release() since
// there is already a reference on pNewNode.
pNewNode = NULL;
eInsertLoc = XFLM_NEXT_SIB;
}
else
{
pNewNode->Release();
pNewNode = NULL;
}
xmlImport.reset();
}
Exit:
if( pNode)
{
pNode->Release();
}
if( pNewNode)
{
pNewNode->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::importDocument(
IF_IStream * ifpStream,
FLMUINT uiCollection,
IF_DOMNode ** ppDoc,
XFLM_IMPORT_STATS * pImportStats)
{
RCODE rc = NE_XFLM_OK;
F_XMLImport xmlImport;
F_DOMNode * pNode = NULL;
if( pNode)
{
pNode->AddRef();
}
if( RC_BAD( rc = xmlImport.setup()))
{
goto Exit;
}
if( RC_BAD( rc = xmlImport.import( ifpStream, this, uiCollection,
FLM_XML_COMPRESS_WHITESPACE_FLAG |
FLM_XML_TRANSLATE_ESC_FLAG |
FLM_XML_EXTEND_DICT_FLAG, NULL, XFLM_LAST_CHILD, &pNode, pImportStats)))
{
goto Exit;
}
if( RC_BAD( rc = documentDone( pNode)))
{
goto Exit;
}
if( ppDoc)
{
if( *ppDoc)
{
(*ppDoc)->Release();
}
*ppDoc = pNode;
pNode = NULL;
}
Exit:
if( pNode)
{
pNode->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createElemOrAttrDef(
FLMBOOL bElement,
FLMBOOL bUnicode,
const void * pvNamespaceURI,
const void * pvLocalName,
FLMUINT uiDataType,
FLMBOOL bUniqueChildElms,
FLMUINT * puiNameId,
F_DOMNode ** ppDocumentNode)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
bElement ? ELM_ELEMENT_TAG : ELM_ATTRIBUTE_TAG, ELEMENT_NODE, &pDoc)))
{
goto Exit;
}
if( pvNamespaceURI)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_TARGET_NAMESPACE_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode(
this, (FLMUNICODE *)pvNamespaceURI)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvNamespaceURI)))
{
goto Exit;
}
}
}
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvLocalName)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvLocalName)))
{
goto Exit;
}
}
if( puiNameId && *puiNameId)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( this, *puiNameId)))
{
goto Exit;
}
}
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_TYPE_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUTF8( this,
(const FLMBYTE *)fdictGetDataTypeStr( uiDataType))))
{
goto Exit;
}
if( bUniqueChildElms && bElement)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_UNIQUE_SUB_ELEMENTS_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)"true")))
{
goto Exit;
}
}
if( RC_BAD( rc = documentDone( pDoc)))
{
goto Exit;
}
if( puiNameId)
{
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->getUINT( this, puiNameId)))
{
goto Exit;
}
}
if( ppDocumentNode)
{
if( (*ppDocumentNode))
{
(*ppDocumentNode)->Release();
}
*ppDocumentNode = pDoc;
pDoc = NULL;
}
Exit:
if( pDoc)
{
pDoc->Release();
}
if( pAttr)
{
flmAssert( pAttr->m_refCnt <= 2);
pAttr->Release();
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
else if( RC_BAD( rc))
{
setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createPrefixDef(
FLMBOOL bUnicode,
const void * pvPrefixName,
FLMUINT * puiPrefixNumber)
{
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
F_DOMNode * pNumAttr = NULL;
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
ELM_PREFIX_TAG, ELEMENT_NODE, &pDoc)))
{
goto Exit;
}
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvPrefixName)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvPrefixName)))
{
goto Exit;
}
}
// Create the prefix number attribute if passed in.
if( puiPrefixNumber && *puiPrefixNumber)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pNumAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pNumAttr->setUINT( this, *puiPrefixNumber)))
{
goto Exit;
}
}
if( RC_BAD( rc = documentDone( pDoc)))
{
goto Exit;
}
// Change the modes on the definition so that the name cannot be modified
// and the definition cannot be deleted. This needs to be done after
// calling documentDone() because it sets the flags on the nodes of the
// definition according to a set of default rules that do not correspond
// to what we need to have in this case.
if( RC_BAD( rc = pAttr->addModeFlags(
this, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if( puiPrefixNumber)
{
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
(IF_DOMNode **)&pNumAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pNumAttr->getUINT( this, puiPrefixNumber)))
{
goto Exit;
}
}
Exit:
if( pDoc)
{
pDoc->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( pNumAttr)
{
pNumAttr->Release();
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
else if( RC_BAD( rc))
{
setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::createEncDef(
FLMBOOL bUnicode,
const void * pvEncType,
const void * pvEncName,
FLMUINT uiKeySize,
FLMUINT * puiEncDefNumber)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
ELM_ENCDEF_TAG, ELEMENT_NODE, &pDoc)))
{
goto Exit;
}
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvEncName)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvEncName)))
{
goto Exit;
}
}
// Create the encdef id attribute if passed in.
if( puiEncDefNumber && *puiEncDefNumber)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( this, *puiEncDefNumber)))
{
goto Exit;
}
}
// Create the algorithm attribute
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_TYPE_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvEncType)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvEncType)))
{
goto Exit;
}
}
// Create the key size attribute
if( uiKeySize)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_ENCRYPTION_KEY_SIZE_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( this, uiKeySize)))
{
goto Exit;
}
}
// Call documentDone to complete it all.
if( RC_BAD( rc = documentDone( pDoc)))
{
goto Exit;
}
if( puiEncDefNumber)
{
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->getUINT( this, puiEncDefNumber)))
{
goto Exit;
}
}
Exit:
if( pDoc)
{
pDoc->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
else if( RC_BAD( rc))
{
setMustAbortTrans( rc);
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_Db::getPrefixId(
const FLMUNICODE * puzPrefixName,
FLMUINT * puiPrefixNumber)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getPrefixId(
this, puzPrefixName, puiPrefixNumber)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_Db::getPrefixId(
const char * pszPrefixName,
FLMUINT * puiPrefixNumber)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getPrefixId(
this, pszPrefixName, puiPrefixNumber)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_Db::getEncDefId(
const char * pszEncDefName,
FLMUINT * puiEncDefNumber)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getEncDefId( this,
pszEncDefName, puiEncDefNumber)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FLMAPI F_Db::getEncDefId(
const FLMUNICODE * puzEncDefName,
FLMUINT * puiEncDefNumber)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDict->getEncDefId(
this, puzEncDefName, puiEncDefNumber)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
transAbort();
}
return( rc);
}
/*****************************************************************************
Desc: Create a new c ollection definition in the dictionary.
******************************************************************************/
RCODE F_Db::createCollectionDef(
FLMBOOL bUnicode,
const void * pvCollectionName,
FLMUINT * puiCollectionNumber,
FLMUINT uiEncNumber)
{
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// First, create the root element to hold the collection definition
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
ELM_COLLECTION_TAG, ELEMENT_NODE, &pDoc)))
{
goto Exit;
}
// Create the collection name attruibute
if( RC_BAD( rc = pDoc->createAttribute(
this, ATTR_NAME_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( bUnicode)
{
if( RC_BAD( rc = pAttr->setUnicode(
this, (FLMUNICODE *)pvCollectionName)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvCollectionName)))
{
goto Exit;
}
}
// Create the collection number attribute if passed in.
if( puiCollectionNumber && *puiCollectionNumber)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( this, *puiCollectionNumber)))
{
goto Exit;
}
}
if( uiEncNumber)
{
if( RC_BAD( rc = pDoc->createAttribute( this,
ATTR_ENCRYPTION_ID_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( this, uiEncNumber)))
{
goto Exit;
}
}
if( RC_BAD( rc = documentDone( pDoc)))
{
goto Exit;
}
if( puiCollectionNumber)
{
if( RC_BAD( rc = pDoc->getAttribute(
this, ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->getUINT( this, puiCollectionNumber)))
{
goto Exit;
}
}
Exit:
if( bStartedTrans)
{
if( RC_BAD( rc))
{
transAbort();
}
else
{
rc = transCommit();
}
}
if( pDoc)
{
pDoc->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( RC_BAD( rc))
{
setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::flushDirtyNodes( void)
{
RCODE rc = NE_XFLM_OK;
F_CachedNode * pNode;
F_Btree * pBtree = NULL;
FLMUINT uiRflToken = 0;
FLMUINT uiCollection = 0;
if( !m_uiDirtyNodeCount)
{
goto Exit;
}
// Disable RFL logging
m_pDatabase->m_pRfl->disableLogging( &uiRflToken);
// All of the dirty nodes should be at the front of the list.
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
while ((pNode = m_pDatabase->m_pFirstNode) != NULL)
{
if( !pNode->nodeIsDirty())
{
break;
}
// Flushing the node should remove it from the front of the list.
// Need to increment the use count on the node to prevent it from
// being moved while we are flushing it to disk.
pNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
if( uiCollection != pNode->getCollection())
{
if( pBtree)
{
pBtree->Release();
}
uiCollection = pNode->getCollection();
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBtree)))
{
goto Exit;
}
}
rc = flushNode( pBtree, pNode);
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
pNode->decrNodeUseCount();
if( rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
if( RC_BAD( rc))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
}
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
flmAssert( !m_uiDirtyNodeCount);
Exit:
if( uiRflToken)
{
m_pDatabase->m_pRfl->enableLogging( &uiRflToken);
}
if( pBtree)
{
pBtree->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Db::flushDirtyNode(
F_CachedNode * pNode)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bMutexLocked = FALSE;
FLMUINT uiRflToken = 0;
F_Btree * pBTree = NULL;
m_pDatabase->m_pRfl->disableLogging( &uiRflToken);
if( !pNode->nodeIsDirty())
{
goto Exit;
}
// Get a B-Tree object
if( RC_BAD( rc = getCachedBTree( pNode->getCollection(), &pBTree)))
{
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
pNode->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = FALSE;
rc = flushNode( pBTree, pNode);
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
pNode->decrNodeUseCount();
if( RC_BAD( rc))
{
goto Exit;
}
Exit:
if( uiRflToken)
{
m_pDatabase->m_pRfl->enableLogging( &uiRflToken);
}
if( bMutexLocked)
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
if( pBTree)
{
pBTree->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_Database::startPendingInput(
FLMUINT uiPendingType,
F_CachedNode * pPendingNode)
{
RCODE rc = NE_XFLM_OK;
if( m_pPendingInput)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
goto Exit;
}
// Not supported on element nodes
if( pPendingNode->getNodeType() == ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
m_uiPendingType = uiPendingType;
m_pPendingInput = pPendingNode;
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
m_pPendingInput->incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
m_uiUpdCharCount = 0;
m_bUpdFirstBuf = TRUE;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
void F_Database::endPendingInput( void)
{
if( m_pPendingInput)
{
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
m_pPendingInput->decrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
m_pPendingInput = NULL;
}
if( m_pPendingBTree)
{
gv_XFlmSysData.pBtPool->btpReturnBtree( &m_pPendingBTree);
m_pPendingBTree = NULL;
}
m_uiPendingType = XFLM_NODATA_TYPE;
m_bUpdFirstBuf = TRUE;
m_uiUpdByteCount = 0;
m_uiUpdCharCount = 0;
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::createAttribute(
F_Db * pDb,
FLMUINT uiAttrNameId,
F_AttrItem ** ppAttrItem)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem = NULL;
FLMUINT uiInsertPos;
// Attribute should not exist
if (getAttribute( uiAttrNameId, &uiInsertPos) != NULL)
{
flmAssert( 0);
}
else
{
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
// Allocate the new attribute
if( RC_BAD( rc = allocAttribute( pDb, uiAttrNameId, NULL, uiInsertPos,
&pAttrItem, FALSE)))
{
goto Exit;
}
}
Exit:
if( ppAttrItem)
{
*ppAttrItem = pAttrItem;
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
F_AttrItem * F_CachedNode::getAttribute(
FLMUINT uiAttrNameId,
FLMUINT * puiInsertPos)
{
FLMUINT uiLoop;
F_AttrItem * pAttrItem = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMUINT uiTblNameId;
if (!m_uiAttrCount)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
// If the attribute count is <= 4, do a sequential search through
// the array. Otherwise, do a binary search.
if ((uiTblSize = m_uiAttrCount) <= 4)
{
for (uiLoop = 0; uiLoop < m_uiAttrCount; uiLoop++)
{
pAttrItem = m_ppAttrList [uiLoop];
if (pAttrItem->m_uiNameId == uiAttrNameId)
{
break;
}
else if (pAttrItem->m_uiNameId > uiAttrNameId)
{
pAttrItem = NULL;
break;
}
}
if (uiLoop == m_uiAttrCount)
{
pAttrItem = NULL;
}
if (puiInsertPos)
{
*puiInsertPos = uiLoop;
}
}
else
{
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblNameId = m_ppAttrList [uiMid]->m_uiNameId;
if (uiTblNameId == uiAttrNameId)
{
// Found Match
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
pAttrItem = m_ppAttrList [uiMid];
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (uiAttrNameId < uiTblNameId)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (uiAttrNameId < uiTblNameId)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
}
Exit:
return( pAttrItem);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getPrevSiblingNode(
FLMUINT uiCurrentNameId,
IF_DOMNode ** ppSib)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_DOMNode * pAttr = NULL;
if( (pAttrItem = getPrevSibling( uiCurrentNameId)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttr->m_uiAttrNameId = pAttrItem->m_uiNameId;
pAttr->m_pCachedNode = this;
incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
if( ppSib)
{
if( *ppSib)
{
(*ppSib)->Release();
}
*ppSib = (IF_DOMNode *)pAttr;
pAttr = NULL;
}
Exit:
if( pAttr)
{
pAttr->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getNextSiblingNode(
FLMUINT uiCurrentNameId,
IF_DOMNode ** ppSib)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_DOMNode * pAttr = NULL;
if( (pAttrItem = getNextSibling( uiCurrentNameId)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
goto Exit;
}
pAttr->m_uiAttrNameId = pAttrItem->m_uiNameId;
pAttr->m_pCachedNode = this;
incrNodeUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
if( ppSib)
{
if( *ppSib)
{
(*ppSib)->Release();
}
*ppSib = (IF_DOMNode *)pAttr;
pAttr = NULL;
}
Exit:
if( pAttr)
{
pAttr->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::allocAttribute(
F_Db * pDb,
FLMUINT uiAttrNameId,
F_AttrItem * pCopyFromItem,
FLMUINT uiInsertPos,
F_AttrItem ** ppAttrItem,
FLMBOOL bMutexAlreadyLocked)
{
RCODE rc = NE_XFLM_OK;
F_AttrElmInfo defInfo;
F_AttrItem * pAttrItem = NULL;
FLMUINT uiSize;
FLMBOOL bMutexLocked = FALSE;
if( RC_BAD( rc = pDb->m_pDict->getAttribute(
pDb, uiAttrNameId, &defInfo)))
{
flmAssert( 0);
goto Exit;
}
if( !bMutexAlreadyLocked)
{
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
}
if( (pAttrItem = new F_AttrItem) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( pCopyFromItem)
{
pAttrItem->copyFrom( pCopyFromItem);
}
else
{
if( defInfo.getFlags() & ATTR_ELM_NS_DECL)
{
pAttrItem->m_uiFlags |= FDOM_NAMESPACE_DECL;
}
}
// Find where this thing goes in the attribute list
// If we are copying, we don't need to resize the list as it will
// already be the correct size.
if (!pCopyFromItem)
{
if (RC_BAD( rc = resizeAttrList( m_uiAttrCount + 1, bMutexLocked)))
{
goto Exit;
}
// NOTE: m_uiAttrCount will have been incremented to accommodate
// the new attribute.
// Move everything above the [uiInsertPos] slot up. Remember, no need to
// preserve the item at [m_uiAttrCount - 1], because we just increased
// the size of the array, and there is nothing there right now.
if (uiInsertPos < m_uiAttrCount - 1)
{
f_memmove( &m_ppAttrList [uiInsertPos + 1],
&m_ppAttrList [uiInsertPos],
sizeof( F_AttrItem *) * (m_uiAttrCount - uiInsertPos - 1));
}
}
m_ppAttrList [uiInsertPos] = pAttrItem;
pAttrItem->m_pCachedNode = this;
pAttrItem->m_uiDataType = defInfo.getDataType();
pAttrItem->m_uiNameId = uiAttrNameId;
*ppAttrItem = pAttrItem;
uiSize = pAttrItem->memSize();
m_uiTotalAttrSize += uiSize;
if (m_ui64HighTransId != FLM_MAX_UINT64)
{
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes += uiSize;
}
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount += uiSize;
// Set to NULL so it won't get deleted below.
pAttrItem = NULL;
Exit:
if (pAttrItem)
{
delete pAttrItem;
}
if( bMutexLocked)
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::freeAttribute(
F_AttrItem * pAttrItem,
FLMUINT uiPos)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bMutexLocked = FALSE;
// Move everything above the [uiPos] slot down.
if (uiPos < m_uiAttrCount - 1)
{
f_memmove( &m_ppAttrList [uiPos],
&m_ppAttrList [uiPos + 1],
sizeof( F_AttrItem *) * (m_uiAttrCount - uiPos - 1));
}
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
if (RC_BAD( rc = resizeAttrList( m_uiAttrCount - 1, bMutexLocked)))
{
goto Exit;
}
delete pAttrItem;
Exit:
if (bMutexLocked)
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::setNumber64(
F_Db * pDb,
FLMUINT uiAttrNameId,
FLMUINT64 ui64Value,
FLMBOOL bNeg,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
FLMUINT uiValLen = 0;
FLMUINT uiEncryptedLen;
FLMBYTE ucNumBuf[ 32];
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
// Get a pointer to the attribute list item
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
{
goto Exit;
}
}
else
{
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
}
pAttrItem->m_ui64QuickVal = ui64Value;
if( bNeg)
{
pAttrItem->m_uiFlags |= FDOM_SIGNED_QUICK_VAL;
}
else
{
pAttrItem->m_uiFlags |= FDOM_UNSIGNED_QUICK_VAL;
}
switch( pAttrItem->m_uiDataType)
{
case XFLM_NUMBER_TYPE:
{
if( ui64Value <= 0x7F && !uiEncDefId)
{
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, 0, 1, FALSE,
FALSE)))
{
goto Exit;
}
*(pAttrItem->getAttrDataPtr()) = (FLMBYTE)ui64Value;
goto Exit;
}
else
{
uiValLen = sizeof( ucNumBuf);
if( RC_BAD( rc = flmNumber64ToStorage(
ui64Value, &uiValLen, ucNumBuf, bNeg, FALSE)))
{
goto Exit;
}
}
break;
}
case XFLM_TEXT_TYPE:
{
FLMBYTE * pucSen;
FLMUINT uiSenLen;
if( bNeg)
{
ucNumBuf[ 1] = '-';
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 2]);
}
else
{
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 1]);
}
uiValLen = f_strlen( (const char *)&ucNumBuf[ 1]);
pucSen = &ucNumBuf [0];
uiSenLen = f_encodeSEN( uiValLen, &pucSen, (FLMUINT)0);
flmAssert( uiSenLen == 1);
uiValLen += uiSenLen + 1;
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
goto Exit;
}
}
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
uiValLen, TRUE, FALSE)))
{
goto Exit;
}
if( uiValLen)
{
f_memcpy( pAttrItem->getAttrDataPtr(), ucNumBuf, uiValLen);
if( uiEncDefId)
{
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
pAttrItem->getAttrDataBufferSize(), uiValLen, &uiEncryptedLen)))
{
goto Exit;
}
}
}
else
{
pAttrItem->m_uiPayloadLen = 0;
}
pAttrItem->m_uiDecryptedDataLen = uiValLen;
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getNumber64(
F_Db * pDb,
FLMUINT uiAttrNameId,
FLMUINT64 * pui64Value,
FLMBOOL * pbNeg)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bNeg;
FLMUINT64 ui64Value;
F_AttrItem * pAttrItem;
IF_PosIStream * pIStream = NULL;
F_NodeBufferIStream bufferIStream;
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
else if( pAttrItem->m_uiFlags & FDOM_UNSIGNED_QUICK_VAL)
{
*pbNeg = FALSE;
*pui64Value = pAttrItem->m_ui64QuickVal;
}
else if( pAttrItem->m_uiFlags & FDOM_SIGNED_QUICK_VAL)
{
*pbNeg = TRUE;
*pui64Value = pAttrItem->m_ui64QuickVal;
}
else
{
if( RC_BAD( rc = getIStream( pDb, uiAttrNameId, &bufferIStream, &pIStream)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsNumber(
pIStream, pAttrItem->m_uiDataType, &ui64Value, &bNeg)))
{
goto Exit;
}
*pui64Value = ui64Value;
*pbNeg = bNeg;
}
Exit:
if( pIStream)
{
pIStream->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::setBinary(
F_Db * pDb,
FLMUINT uiAttrNameId,
const void * pvValue,
FLMUINT uiValueLen,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
FLMUINT uiDecryptedValLen = 0;
FLMUINT uiEncryptedLen;
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
// Get a pointer to the attribute list item
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
{
goto Exit;
}
}
else
{
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
}
switch( pAttrItem->m_uiDataType)
{
case XFLM_BINARY_TYPE:
{
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
uiValueLen, TRUE, FALSE)))
{
goto Exit;
}
if( uiValueLen)
{
f_memcpy( pAttrItem->getAttrDataPtr(), pvValue, uiValueLen);
if( uiEncDefId)
{
uiDecryptedValLen = uiValueLen;
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
pAttrItem->getAttrDataBufferSize(), uiValueLen, &uiEncryptedLen)))
{
goto Exit;
}
flmAssert( uiEncryptedLen == pAttrItem->getAttrDataBufferSize());
}
}
pAttrItem->m_uiDecryptedDataLen = uiValueLen;
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::getBinary(
F_Db * pDb,
FLMUINT uiAttrNameId,
void * pvBuffer,
FLMUINT uiBufferLen,
FLMUINT * puiDataLen)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
IF_PosIStream * pIStream = NULL;
F_NodeBufferIStream bufferIStream;
// If a NULL buffer is passed in, just return the
// data length
if( !pvBuffer)
{
rc = getDataLength( uiAttrNameId, puiDataLen);
goto Exit;
}
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( !pAttrItem->m_uiEncDefId)
{
FLMUINT uiCopySize = f_min( uiBufferLen,
pAttrItem->getAttrDataLength());
if( uiCopySize)
{
f_memcpy( pvBuffer, pAttrItem->getAttrDataPtr(), uiCopySize);
}
if( puiDataLen)
{
*puiDataLen = uiCopySize;
}
}
else
{
if( RC_BAD( rc = getIStream( pDb, uiAttrNameId, &bufferIStream, &pIStream)))
{
goto Exit;
}
if( RC_BAD( rc = flmReadStorageAsBinary( pIStream,
pvBuffer, uiBufferLen, 0, puiDataLen)))
{
goto Exit;
}
}
Exit:
if( pIStream)
{
pIStream->Release();
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::setUTF8(
F_Db * pDb,
FLMUINT uiAttrNameId,
const void * pvValue,
FLMUINT uiNumBytesInValue,
FLMUINT uiNumCharsInValue,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
FLMUINT uiValLen = 0;
FLMUINT uiDecryptedValLen = 0;
FLMUINT uiEncryptedLen;
FLMUINT uiSenLen;
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
FLMBOOL bNullTerminate = FALSE;
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
// Get a pointer to the attribute list item
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
{
goto Exit;
}
}
else
{
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
{
rc = RC_SET( NE_XFLM_READ_ONLY);
goto Exit;
}
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
}
switch( pAttrItem->m_uiDataType)
{
case XFLM_TEXT_TYPE:
{
break;
}
default:
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
}
if( pvValue && uiNumBytesInValue)
{
if( pucValue[ uiNumBytesInValue - 1] != 0)
{
bNullTerminate = TRUE;
}
uiSenLen = f_getSENByteCount( uiNumCharsInValue);
uiValLen = uiNumBytesInValue + uiSenLen + (bNullTerminate ? 1 : 0);
}
else
{
uiSenLen = 0;
uiValLen = 0;
}
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
uiValLen, TRUE, FALSE)))
{
goto Exit;
}
if( uiValLen)
{
FLMBYTE * pucTmp = pAttrItem->getAttrDataPtr();
f_encodeSENKnownLength( uiNumCharsInValue, uiSenLen, &pucTmp);
f_memcpy( pucTmp, pucValue, uiNumBytesInValue);
if( bNullTerminate)
{
pucTmp[ uiNumBytesInValue] = 0;
}
if( uiEncDefId)
{
uiDecryptedValLen = uiValLen;
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
pAttrItem->getAttrDataBufferSize(), uiValLen, &uiEncryptedLen)))
{
goto Exit;
}
}
}
pAttrItem->m_uiDecryptedDataLen = uiValLen;
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::setStorageValue(
F_Db * pDb,
FLMUINT uiAttrNameId,
const void * pvValue,
FLMUINT uiValueLen,
FLMUINT uiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
FLMUINT uiDecryptedValLen = 0;
FLMUINT uiEncryptedLen;
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
// Get a pointer to the attribute list item
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
{
goto Exit;
}
}
else
{
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
}
if( pAttrItem->m_uiDataType == XFLM_UNKNOWN_TYPE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
uiValueLen, TRUE, FALSE)))
{
goto Exit;
}
if( uiValueLen)
{
f_memcpy( pAttrItem->getAttrDataPtr(), pvValue, uiValueLen);
if( uiEncDefId)
{
uiDecryptedValLen = uiValueLen;
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
pAttrItem->getAttrDataBufferSize(), uiValueLen, &uiEncryptedLen)))
{
goto Exit;
}
flmAssert( uiEncryptedLen == pAttrItem->getAttrDataBufferSize());
}
}
pAttrItem->m_uiDecryptedDataLen = uiValueLen;
Exit:
if( RC_BAD( rc))
{
pDb->setMustAbortTrans( rc);
}
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::addModeFlags(
F_Db * pDb,
FLMUINT uiAttrNameId,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_UNREFERENCED_PARM( pDb);
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
pAttrItem->m_uiFlags |= uiFlags;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::removeModeFlags(
F_Db * pDb,
FLMUINT uiAttrNameId,
FLMUINT uiFlags)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_UNREFERENCED_PARM( pDb);
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
pAttrItem->m_uiFlags &= ~uiFlags;
Exit:
return( rc);
}
/*****************************************************************************
Desc:
******************************************************************************/
RCODE F_CachedNode::setPrefixId(
F_Db * pDb,
FLMUINT uiAttrNameId,
FLMUINT uiPrefixId)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_UNREFERENCED_PARM( pDb);
// Logging should be done by the caller
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
pAttrItem->m_uiPrefixId = uiPrefixId;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_CachedNode::getIStream(
F_Db * pDb,
FLMUINT uiAttrNameId,
F_NodeBufferIStream * pStackStream,
IF_PosIStream ** ppIStream,
FLMUINT * puiDataType,
FLMUINT * puiDataLength)
{
RCODE rc = NE_XFLM_OK;
F_AttrItem * pAttrItem;
F_NodeBufferIStream * pNodeBufferIStream = NULL;
FLMBYTE * pucAllocatedBuffer = NULL;
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
{
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
if( pStackStream)
{
pNodeBufferIStream = pStackStream;
pStackStream->AddRef();
flmAssert( !pStackStream->m_pCachedNode);
}
else
{
if( (pNodeBufferIStream = f_new F_NodeBufferIStream) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
if( pAttrItem->m_uiEncDefId)
{
flmAssert( pAttrItem->m_uiIVLen);
if( RC_BAD( rc = pNodeBufferIStream->open( NULL,
pAttrItem->getAttrDataBufferSize(), (char **)&pucAllocatedBuffer)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->decryptData(
pAttrItem->m_uiEncDefId, pAttrItem->getAttrIVPtr(),
pAttrItem->getAttrDataPtr(), pAttrItem->getAttrDataBufferSize(),
pucAllocatedBuffer, (FLMUINT)pNodeBufferIStream->totalSize())))
{
goto Exit;
}
pNodeBufferIStream->truncate( pAttrItem->getAttrDataLength());
}
else
{
if( RC_BAD( rc = pNodeBufferIStream->open(
(const char *)pAttrItem->getAttrDataPtr(),
pAttrItem->getAttrDataLength())))
{
goto Exit;
}
}
if( !pStackStream)
{
pNodeBufferIStream->m_pCachedNode = this;
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
incrNodeUseCount();
incrStreamUseCount();
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
if( puiDataType)
{
*puiDataType = pAttrItem->m_uiDataType;
}
if( puiDataLength)
{
*puiDataLength = (FLMUINT)pNodeBufferIStream->remainingSize();
}
if( *ppIStream)
{
(*ppIStream)->Release();
}
*ppIStream = pNodeBufferIStream;
pNodeBufferIStream = NULL;
Exit:
if( pNodeBufferIStream)
{
pNodeBufferIStream->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_AttrItem::resizePayloadBuffer(
FLMUINT uiTotalNeeded,
FLMBOOL bMutexAlreadyLocked)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCurrentSize = m_uiPayloadLen;
FLMBOOL bMutexLocked = FALSE;
if( uiCurrentSize != uiTotalNeeded)
{
FLMUINT uiOldSize = memSize();
FLMUINT uiNewSize;
FLMUINT uiSize;
if( uiTotalNeeded <= sizeof( FLMBYTE *))
{
if( uiCurrentSize && uiCurrentSize > sizeof( FLMBYTE *))
{
if (!bMutexAlreadyLocked)
{
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
}
m_pucPayload -= sizeof( F_AttrItem *);
gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->freeBuf( m_uiPayloadLen +
sizeof( F_AttrItem *), &m_pucPayload);
}
else
{
// NOTE: Mutex is NOT locked here, because
// nothing will be changed that requires the
// mutex to be locked. Nor will the size
// change. If the size were to change, we
// would want to lock the mutex because we
// would be incrementing/decrementing size
// counts below.
m_pucPayload = NULL;
}
}
else
{
F_AttrItem * pAttrItem = this;
if (!bMutexAlreadyLocked)
{
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
bMutexLocked = TRUE;
}
if( uiCurrentSize && uiCurrentSize > sizeof( FLMBYTE *))
{
m_pucPayload -= sizeof( F_AttrItem *);
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->reallocBuf(
&gv_XFlmSysData.pNodeCacheMgr->m_attrBufferRelocator,
m_uiPayloadLen + sizeof( F_AttrItem *),
uiTotalNeeded + sizeof( F_AttrItem *),
&pAttrItem, sizeof( F_AttrItem *), &m_pucPayload)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->allocBuf(
&gv_XFlmSysData.pNodeCacheMgr->m_attrBufferRelocator,
uiTotalNeeded + sizeof( F_AttrItem *),
&pAttrItem, sizeof( F_AttrItem *), &m_pucPayload)))
{
goto Exit;
}
}
flmAssert( *((F_AttrItem **)m_pucPayload) == this);
m_pucPayload += sizeof( F_AttrItem *);
}
m_uiPayloadLen = uiTotalNeeded;
uiNewSize = memSize();
if (uiNewSize > uiOldSize)
{
uiSize = uiNewSize - uiOldSize;
m_pCachedNode->m_uiTotalAttrSize += uiSize;
if (m_pCachedNode->m_ui64HighTransId != FLM_MAX_UINT64)
{
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes += uiSize;
}
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount += uiSize;
}
else if (uiNewSize < uiOldSize)
{
uiSize = uiOldSize - uiNewSize;
flmAssert( m_pCachedNode->m_uiTotalAttrSize >= uiSize);
m_pCachedNode->m_uiTotalAttrSize -= uiSize;
if (m_pCachedNode->m_ui64HighTransId != FLM_MAX_UINT64)
{
flmAssert( gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes >= uiSize);
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes -= uiSize;
}
flmAssert( gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount >= uiSize);
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount -= uiSize;
}
}
Exit:
if( bMutexLocked)
{
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_AttrItem::setupAttribute(
F_Db * pDb,
FLMUINT uiEncDefId,
FLMUINT uiDataSizeNeeded,
FLMBOOL bOkToGenerateIV,
FLMBOOL bMutexAlreadyLocked)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiTotalNeeded = uiDataSizeNeeded;
FLMUINT uiIVLen = 0;
FLMBOOL bGenerateIV = FALSE;
F_ENCDEF * pEncDef = NULL;
if( uiEncDefId)
{
if( RC_BAD( rc = pDb->m_pDict->getEncDef(
uiEncDefId, &pEncDef)))
{
goto Exit;
}
uiIVLen = pEncDef->pCcs->getIVLen();
flmAssert( uiIVLen == 8 || uiIVLen == 16);
m_uiEncDefId = uiEncDefId;
m_uiIVLen = uiIVLen;
if( bOkToGenerateIV)
{
bGenerateIV = TRUE;
}
uiTotalNeeded += m_uiIVLen +
(getEncLen( uiDataSizeNeeded) - uiDataSizeNeeded);
}
else
{
m_uiEncDefId = 0;
m_uiIVLen = 0;
}
#ifdef FLM_DEBUG
if( uiEncDefId)
{
flmAssert( uiTotalNeeded >= 8 + uiDataSizeNeeded);
}
#endif
if( RC_BAD( rc = resizePayloadBuffer( uiTotalNeeded, bMutexAlreadyLocked)))
{
goto Exit;
}
if( bGenerateIV)
{
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, getAttrIVPtr())))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_NodeBufferIStream::open(
const char * pucBuffer,
FLMUINT uiLength,
char ** ppucAllocatedBuffer)
{
RCODE rc = NE_XFLM_OK;
IF_BufferIStream * pBufferIStream = NULL;
if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferIStream)))
{
goto Exit;
}
if( RC_BAD( rc = pBufferIStream->open( pucBuffer,
uiLength, ppucAllocatedBuffer)))
{
goto Exit;
}
m_pBufferIStream = pBufferIStream;
pBufferIStream = NULL;
Exit:
if( pBufferIStream)
{
pBufferIStream->Release();
}
return( rc);
}