Files
mars-flaim/flaim/src/fcs.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

7392 lines
141 KiB
C++

//-------------------------------------------------------------------------
// Desc: FLAIM C/S client interface
// Tabs: 3
//
// Copyright (c) 1998-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library 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
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; 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$
//------------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC FLMBOOL flmGetNextHexPacketSlot(
FLMBYTE * pucUsedMap,
FLMUINT uiMapSize,
IF_RandomGenerator * pRandGen,
FLMUINT * puiSlot);
FSTATIC RCODE flmGetNextHexPacketBytes(
FLMBYTE * pucUsedMap,
FLMUINT uiMapSize,
FLMBYTE * pucPacket,
IF_RandomGenerator * pRandGen,
FLMBYTE * pucBuf,
FLMUINT uiCount);
/****************************************************************************
Desc:
*****************************************************************************/
FCS_BIOS::FCS_BIOS( void)
{
m_pool.poolInit( (FCS_BIOS_BLOCK_SIZE + sizeof( FCSBIOSBLOCK)) * 2);
m_bMessageActive = FALSE;
m_pRootBlock = NULL;
m_pCurrWriteBlock = NULL;
m_pCurrReadBlock = NULL;
m_bAcceptingData = FALSE;
m_pEventHook = NULL;
m_pvUserData = 0;
}
/****************************************************************************
Desc:
*****************************************************************************/
FCS_BIOS::~FCS_BIOS()
{
m_pool.poolFree();
}
/****************************************************************************
Desc: Clears all pending data
*****************************************************************************/
RCODE FCS_BIOS::reset( void)
{
return( close());
}
/****************************************************************************
Desc: Flushes any pending data and closes the stream.
*****************************************************************************/
RCODE FCS_BIOS::close( void)
{
RCODE rc = FERR_OK;
m_pool.poolReset();
m_bMessageActive = FALSE;
m_pRootBlock = NULL;
m_pCurrWriteBlock = NULL;
m_pCurrReadBlock = NULL;
m_bAcceptingData = FALSE;
return( rc);
}
/****************************************************************************
Desc: Writes the requested amount of data to the stream.
*****************************************************************************/
RCODE FCS_BIOS::write(
FLMBYTE * pucData,
FLMUINT uiLength)
{
FLMUINT uiCopySize;
FLMUINT uiDataPos = 0;
FCSBIOSBLOCK * pPrevBlock = NULL;
RCODE rc = FERR_OK;
if( !m_bAcceptingData)
{
m_pool.poolReset();
m_pCurrWriteBlock = NULL;
m_pCurrReadBlock = NULL;
m_pRootBlock = NULL;
m_bAcceptingData = TRUE;
}
while( uiLength)
{
if( !m_pCurrWriteBlock ||
m_pCurrWriteBlock->uiCurrWriteOffset == FCS_BIOS_BLOCK_SIZE)
{
pPrevBlock = m_pCurrWriteBlock;
if( RC_BAD( rc = m_pool.poolCalloc( sizeof( FCSBIOSBLOCK),
(void **)&m_pCurrWriteBlock)))
{
goto Exit;
}
if( RC_BAD( rc = m_pool.poolAlloc( FCS_BIOS_BLOCK_SIZE,
(void **)&m_pCurrWriteBlock->pucBlock)))
{
goto Exit;
}
if( pPrevBlock)
{
pPrevBlock->pNextBlock = m_pCurrWriteBlock;
}
else
{
m_pRootBlock = m_pCurrWriteBlock;
m_pCurrReadBlock = m_pCurrWriteBlock;
}
}
uiCopySize = f_min( uiLength,
(FLMUINT)(FCS_BIOS_BLOCK_SIZE -
m_pCurrWriteBlock->uiCurrWriteOffset));
flmAssert( uiCopySize != 0);
f_memcpy( &(m_pCurrWriteBlock->pucBlock[
m_pCurrWriteBlock->uiCurrWriteOffset]),
&(pucData[ uiDataPos]), uiCopySize);
m_pCurrWriteBlock->uiCurrWriteOffset += uiCopySize;
uiDataPos += uiCopySize;
uiLength -= uiCopySize;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Terminates the current message
*****************************************************************************/
RCODE FCS_BIOS::endMessage( void)
{
RCODE rc = FERR_OK;
if( !m_bAcceptingData)
{
goto Exit;
}
if( m_pEventHook)
{
if( RC_BAD( rc = m_pEventHook( this,
FCS_BIOS_EOM_EVENT, m_pvUserData)))
{
goto Exit;
}
}
Exit:
m_bAcceptingData = FALSE;
return( rc);
}
/****************************************************************************
Desc: Reads the requested amount of data from the stream.
*****************************************************************************/
RCODE FCS_BIOS::read(
FLMBYTE * pucData,
FLMUINT uiLength,
FLMUINT * puiBytesRead)
{
FLMUINT uiCopySize;
FLMUINT uiDataPos = 0;
RCODE rc = FERR_OK;
if( puiBytesRead)
{
*puiBytesRead = 0;
}
if( m_bAcceptingData)
{
m_bAcceptingData = FALSE;
}
while( uiLength)
{
if( m_pCurrReadBlock &&
m_pCurrReadBlock->uiCurrReadOffset ==
m_pCurrReadBlock->uiCurrWriteOffset)
{
m_pCurrReadBlock = m_pCurrReadBlock->pNextBlock;
}
if( !m_pCurrReadBlock)
{
m_pool.poolReset();
rc = RC_SET( FERR_EOF_HIT);
goto Exit;
}
uiCopySize = f_min( uiLength,
m_pCurrReadBlock->uiCurrWriteOffset -
m_pCurrReadBlock->uiCurrReadOffset);
f_memcpy( &(pucData[ uiDataPos]),
&(m_pCurrReadBlock->pucBlock[ m_pCurrReadBlock->uiCurrReadOffset]),
uiCopySize);
m_pCurrReadBlock->uiCurrReadOffset += uiCopySize;
uiDataPos += uiCopySize;
if( puiBytesRead)
{
(*puiBytesRead) += uiCopySize;
}
uiLength -= uiCopySize;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
FLMBOOL FCS_BIOS::isDataAvailable( void)
{
if( m_bAcceptingData)
{
if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset)
{
return( TRUE);
}
}
else if( m_pCurrReadBlock &&
((m_pCurrReadBlock->uiCurrReadOffset <
m_pCurrReadBlock->uiCurrWriteOffset) ||
(m_pCurrReadBlock->pNextBlock)))
{
return( TRUE);
}
return( FALSE);
}
/****************************************************************************
Desc: Returns the amount of data available for reading
*****************************************************************************/
FLMUINT FCS_BIOS::getAvailable( void)
{
FLMUINT uiAvail = 0;
FCSBIOSBLOCK * pBlk;
if( m_bAcceptingData)
{
if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset)
{
pBlk = m_pRootBlock;
while( pBlk)
{
uiAvail += pBlk->uiCurrWriteOffset;
pBlk = pBlk->pNextBlock;
}
}
}
else if( m_pCurrReadBlock &&
((m_pCurrReadBlock->uiCurrReadOffset <
m_pCurrReadBlock->uiCurrWriteOffset) ||
(m_pCurrReadBlock->pNextBlock)))
{
pBlk = m_pCurrReadBlock;
while( pBlk)
{
uiAvail += (pBlk->uiCurrWriteOffset -
pBlk->uiCurrReadOffset);
pBlk = pBlk->pNextBlock;
}
}
return( uiAvail);
}
/****************************************************************************
Desc:
****************************************************************************/
FCS_DIS::FCS_DIS( void)
{
m_pIStream = NULL;
m_uiBOffset = m_uiBDataSize = 0;
m_bSetupCalled = FALSE;
}
/****************************************************************************
Desc:
****************************************************************************/
FCS_DIS::~FCS_DIS( void)
{
if( m_bSetupCalled)
{
(void)close();
}
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::setup(
FCS_ISTM * pIStream)
{
m_pIStream = pIStream;
m_bSetupCalled = TRUE;
return( FERR_OK);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readByte(
FLMBYTE * pValue)
{
return( read( pValue, 1, NULL));
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readShort(
FLMINT16 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL)))
{
*pValue = f_bigEndianToINT16( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readUShort(
FLMUINT16 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL)))
{
*pValue = f_bigEndianToUINT16( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readInt(
FLMINT32 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL)))
{
*pValue = f_bigEndianToINT32( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readUInt(
FLMUINT32 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL)))
{
*pValue = f_bigEndianToUINT32( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readInt64(
FLMINT64 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL)))
{
*pValue = f_bigEndianToINT64( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::readUInt64(
FLMUINT64 * pValue)
{
RCODE rc;
if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL)))
{
*pValue = f_bigEndianToUINT64( (FLMBYTE *)pValue);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FCS_DIS::skip(
FLMUINT uiBytesToSkip)
{
return( read( NULL, uiBytesToSkip, NULL));
}
/****************************************************************************
Desc: Flushes any pending data and closes the DIS
****************************************************************************/
RCODE FCS_DIS::close( void)
{
RCODE rc = FERR_OK;
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Terminate and flush.
if( RC_BAD( rc = endMessage()))
{
goto Exit;
}
// Reset the member variables.
m_pIStream = NULL;
Exit:
return( rc);
}
/****************************************************************************
Desc: Returns the state of the stream (open == TRUE, closed == FALSE)
****************************************************************************/
FLMBOOL FCS_DIS::isOpen( void)
{
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
if( m_pIStream && m_pIStream->isOpen())
{
return( TRUE);
}
return( FALSE);
}
/****************************************************************************
Desc: Flushes and terminates the current parent stream message
****************************************************************************/
RCODE FCS_DIS::endMessage( void)
{
RCODE rc = FERR_OK;
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
if( !m_pIStream)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
// Flush any pending data.
if( RC_BAD( rc = flush()))
{
goto Exit;
}
// Terminate the message.
if( RC_BAD( rc = m_pIStream->endMessage()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Flushes any pending data
****************************************************************************/
RCODE FCS_DIS::flush( void)
{
RCODE rc = FERR_OK;
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
if( !m_pIStream)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
// Flush the passed-in input stream.
if( RC_BAD( rc = m_pIStream->flush()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads the specified number of bytes.
****************************************************************************/
RCODE FCS_DIS::read(
FLMBYTE * pucData,
FLMUINT uiLength,
FLMUINT * puiBytesRead)
{
FLMUINT uiCopySize;
FLMUINT uiReadLen;
FLMBYTE * pucPos = NULL;
RCODE rc = FERR_OK;
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
if( !m_pIStream)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
if( puiBytesRead)
{
*puiBytesRead = uiLength;
}
pucPos = pucData;
while( uiLength)
{
if( m_uiBOffset == m_uiBDataSize)
{
m_uiBOffset = m_uiBDataSize = 0;
if( RC_BAD( rc = m_pIStream->read( m_pucBuffer,
FCS_DIS_BUFFER_SIZE, &uiReadLen)))
{
if( uiReadLen)
{
rc = FERR_OK;
}
else
{
goto Exit;
}
}
m_uiBDataSize = uiReadLen;
}
uiCopySize = m_uiBDataSize - m_uiBOffset;
if( uiLength < uiCopySize)
{
uiCopySize = uiLength;
}
if( pucPos)
{
f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize);
pucPos += uiCopySize;
}
m_uiBOffset += uiCopySize;
uiLength -= uiCopySize;
}
Exit:
if( RC_OK( rc) && uiLength)
{
// Unable to satisfy the read request.
rc = RC_SET( FERR_EOF_HIT);
}
if( puiBytesRead)
{
(*puiBytesRead) -= uiLength;
}
return( rc);
}
/****************************************************************************
Desc: Reads a binary token from the stream. The token is tagged with a
length.
****************************************************************************/
RCODE FCS_DIS::readBinary(
F_Pool * pPool,
FLMBYTE ** ppValue,
FLMUINT * puiDataSize)
{
FLMUINT16 ui16DataSize;
RCODE rc = FERR_OK;
if( RC_BAD( rc = readUShort( &ui16DataSize)))
{
goto Exit;
}
if( pPool)
{
// If the data size is non-zero, allocate a buffer and
// read the entire binary value.
if( ui16DataSize)
{
if( RC_BAD( rc = pPool->poolAlloc( ui16DataSize, (void **)ppValue)))
{
goto Exit;
}
if( RC_BAD( rc = read( *ppValue, ui16DataSize, NULL)))
{
goto Exit;
}
}
else
{
*ppValue = NULL;
}
}
else
{
// The application is not interested in the value. Just skip the
// to the end of the value.
if( RC_BAD( rc = skip( ui16DataSize)))
{
goto Exit;
}
}
Exit:
if( puiDataSize)
{
*puiDataSize = ui16DataSize;
}
return( rc);
}
/****************************************************************************
Desc: Reads a large binary token from the stream. The token is tagged with a
length.
****************************************************************************/
RCODE FCS_DIS::readLargeBinary(
F_Pool * pPool,
FLMBYTE ** ppValue,
FLMUINT * puiDataSize)
{
FLMUINT32 ui32DataSize;
RCODE rc = FERR_OK;
if( RC_BAD( rc = readUInt( &ui32DataSize)))
{
goto Exit;
}
if( pPool)
{
// If the data size is non-zero, allocate a buffer and
// read the entire binary value.
if( ui32DataSize)
{
if( RC_BAD(rc = pPool->poolAlloc( ui32DataSize, (void **)ppValue)))
{
goto Exit;
}
if( RC_BAD( rc = read( *ppValue, ui32DataSize, NULL)))
{
goto Exit;
}
}
else
{
*ppValue = NULL;
}
}
else
{
// The application is not interested in the value. Just skip the
// to the end of the value.
if( RC_BAD( rc = skip( ui32DataSize)))
{
goto Exit;
}
}
Exit:
if( puiDataSize)
{
*puiDataSize = (FLMUINT)ui32DataSize;
}
return( rc);
}
/****************************************************************************
Desc: Reads a UTF-8 string from the stream.
****************************************************************************/
RCODE FCS_DIS::readUTF(
F_Pool * pPool,
FLMUNICODE ** ppValue)
{
FLMBYTE ucByte1;
FLMBYTE ucByte2;
FLMBYTE ucByte3;
FLMBYTE ucLoByte;
FLMBYTE ucHiByte;
FLMUINT16 ui16UTFLen;
FLMUINT uiOffset = 0;
RCODE rc = FERR_OK;
// Read the data.
if( RC_BAD( rc = readUShort( &ui16UTFLen)))
{
goto Exit;
}
// Check the size of the UTF string. FLAIM does not support
// strings that are larger than 32K characters.
if( ui16UTFLen >= 32767)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
// Allocate space for the string.
if( pPool)
{
if( RC_BAD( rc = pPool->poolAlloc(
(FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * (FLMUINT)(ui16UTFLen + 1)),
(void **)ppValue)))
{
goto Exit;
}
}
else if( ppValue)
{
*ppValue = NULL;
}
while( ui16UTFLen)
{
// Read and decode the bytes.
if( RC_BAD( rc = read( &ucByte1, 1, NULL)))
{
goto Exit;
}
if( (ucByte1 & 0xC0) != 0xC0)
{
ucHiByte = 0;
ucLoByte = ucByte1;
}
else
{
if( RC_BAD( rc = read( &ucByte2, 1, NULL)))
{
goto Exit;
}
if( (ucByte1 & 0xE0) == 0xE0)
{
if( RC_BAD( rc = read( &ucByte3, 1, NULL)))
{
goto Exit;
}
ucHiByte =
(FLMBYTE)(((ucByte1 & 0x0F) << 4) | ((ucByte2 & 0x3C) >> 2));
ucLoByte = (FLMBYTE)(((ucByte2 & 0x03) << 6) | (ucByte3 & 0x3F));
}
else
{
ucHiByte = (FLMBYTE)(((ucByte1 & 0x1C) >> 2));
ucLoByte = (FLMBYTE)(((ucByte1 & 0x03) << 6) | (ucByte2 & 0x3F));
}
}
if( pPool)
{
(*ppValue)[ uiOffset] =
(FLMUNICODE)(((((FLMUNICODE)(ucHiByte)) << 8) |
((FLMUNICODE)(ucLoByte))));
}
uiOffset++;
ui16UTFLen--;
}
if( pPool)
{
(*ppValue)[ uiOffset] = 0;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads an Hierarchical Tagged Data record from the stream.
****************************************************************************/
RCODE FCS_DIS::readHTD(
F_Pool * pPool,
FLMUINT uiContainer,
FLMUINT uiDrn,
NODE ** ppNode,
FlmRecord ** ppRecord)
{
FLMBYTE ucType;
FLMBYTE ucLevel = 0;
FLMBYTE ucPrevLevel = 0;
FLMBYTE ucDescriptor;
FLMBYTE ucFlags;
FLMUINT16 ui16Tag;
FLMBOOL bHasValue;
FLMBOOL bChild;
FLMBOOL bSibling;
FLMBOOL bLeftTruncated;
FLMBOOL bRightTruncated;
NODE * pRoot = NULL;
NODE * pNode = NULL;
NODE * pPrevNode = NULL;
void * pField = NULL;
void * pvMark = NULL;
RCODE rc = FERR_OK;
if( pPool)
{
pvMark = pPool->poolMark();
}
for( ;;)
{
// Reset variables.
bChild = FALSE;
bSibling = FALSE;
// Read the attribute's tag number.
if( RC_BAD( rc = readUShort( &ui16Tag)))
{
goto Exit;
}
// A tag number of 0 indicates that the end of the HTD data
// stream has been reached.
if( !ui16Tag)
{
break;
}
// Read the attribute's descriptor.
if( RC_BAD(rc = read( &ucDescriptor, 1, NULL)))
{
goto Exit;
}
// Set the flag indicating whether or not the
// attribute has a value.
bHasValue = (FLMBOOL)((ucDescriptor & HTD_HAS_VALUE_FLAG)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE);
// Set the value type.
ucType = (FLMBYTE)((ucDescriptor & HTD_VALUE_TYPE_MASK));
// Get the attribute's level.
switch( (ucDescriptor & HTD_LEVEL_MASK) >> HTD_LEVEL_POS)
{
case HTD_LEVEL_SIBLING:
{
bSibling = TRUE;
ucLevel = ucPrevLevel;
break;
}
case HTD_LEVEL_CHILD:
{
if( ucLevel < 0xFF)
{
bChild = TRUE;
ucLevel = (FLMBYTE)(ucPrevLevel + 1);
}
else
{
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
goto Exit;
}
break;
}
case HTD_LEVEL_BACK:
{
if( ucLevel > 0)
{
ucLevel = (FLMBYTE)(ucPrevLevel - 1);
}
else
{
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
goto Exit;
}
break;
}
case HTD_LEVEL_BACK_X:
{
FLMBYTE ucLevelsBack;
if( RC_BAD(rc = read( &ucLevelsBack, 1, NULL)))
{
goto Exit;
}
if( ucPrevLevel >= ucLevelsBack)
{
ucLevel = (FLMBYTE)(ucPrevLevel - ucLevelsBack);
}
else
{
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
goto Exit;
}
break;
}
}
// Allocate the record object
if( ppRecord && ucLevel == 0)
{
if( *ppRecord)
{
if( (*ppRecord)->isReadOnly() ||
(*ppRecord)->getRefCount() > 1)
{
(*ppRecord)->Release();
if( (*ppRecord = f_new FlmRecord) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
}
else
{
// Reuse the existing FlmRecord object.
(*ppRecord)->clear();
}
}
else
{
if( (*ppRecord = f_new FlmRecord) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
}
(*ppRecord)->setContainerID( uiContainer);
(*ppRecord)->setID( uiDrn);
}
// Allocate the attribute.
if( pPool && ppNode)
{
pNode = GedNodeMake( pPool, ui16Tag, &rc);
if( RC_BAD( rc))
{
goto Exit;
}
}
bLeftTruncated = FALSE;
bRightTruncated = FALSE;
// Read the attribute's value.
switch( ucType)
{
case HTD_TYPE_UNICODE:
{
FLMUNICODE * pUTF;
if( pNode)
{
GedValTypeSet( pNode, FLM_TEXT_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_TEXT_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read UNICODE text in UTF-8 format.
if( pPool)
{
if( RC_BAD( rc = readUTF( pPool, &pUTF)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutUNICODE( pPool, pNode, pUTF)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setUnicode( pField, pUTF)))
{
goto Exit;
}
}
}
else
{
if( RC_BAD( rc = readUTF( NULL, NULL)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_UINT:
{
FLMUINT32 ui32Value;
if( pNode)
{
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_NUMBER_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read an unsigned 32-bit integer.
if( RC_BAD( rc = readUInt( &ui32Value)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutUINT( pPool, pNode, ui32Value)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setUINT( pField, ui32Value)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_UINT64:
{
FLMUINT64 ui64Value;
if( pNode)
{
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_NUMBER_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read an unsigned 64-bit integer.
if( RC_BAD( rc = readUInt64( &ui64Value)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutUINT64( pPool, pNode, ui64Value)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setUINT64( pField, ui64Value)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_INT:
{
FLMINT32 i32Value;
if( pNode)
{
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_NUMBER_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read a signed 32-bit integer.
if( RC_BAD( rc = readInt( &i32Value)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutINT( pPool, pNode, i32Value)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setINT( pField, i32Value)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_INT64:
{
FLMINT64 i64Value;
if( pNode)
{
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_NUMBER_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read a signed 64-bit integer.
if( RC_BAD( rc = readInt64( &i64Value)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutINT64( pPool, pNode, i64Value)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setINT64( pField, i64Value)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_CONTEXT:
{
FLMUINT32 ui32Value;
if( pNode)
{
GedValTypeSet( pNode, FLM_CONTEXT_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_CONTEXT_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read an unsigned 32-bit integer.
if( RC_BAD( rc = readUInt( &ui32Value)))
{
goto Exit;
}
if( pNode)
{
if( RC_BAD( rc = GedPutRecPtr( pPool, pNode, ui32Value)))
{
goto Exit;
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setRecPointer( pField, ui32Value)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_BINARY:
{
FLMUINT16 ui16DataSize;
FLMBYTE * pucData = NULL;
if( pNode)
{
GedValTypeSet( pNode, FLM_BINARY_TYPE);
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, FLM_BINARY_TYPE, &pField)))
{
goto Exit;
}
}
if( !bHasValue)
{
break;
}
// Read a binary data stream.
if( RC_BAD( rc = readUShort( &ui16DataSize)))
{
goto Exit;
}
if( pPool)
{
if( pNode)
{
if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode,
FLM_BINARY_TYPE, ui16DataSize)) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
}
else if( ppRecord)
{
if( RC_BAD(rc = (*ppRecord)->allocStorageSpace( pField,
FLM_BINARY_TYPE, ui16DataSize, 0, 0, 0, &pucData, NULL)))
{
goto Exit;
}
}
if( RC_BAD( rc = read( pucData, ui16DataSize, NULL)))
{
goto Exit;
}
if( pNode)
{
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setBinary( pField,
pucData, ui16DataSize)))
{
goto Exit;
}
}
}
}
else
{
if( RC_BAD( rc = skip( ui16DataSize)))
{
goto Exit;
}
}
break;
}
case HTD_TYPE_DATE:
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
case HTD_TYPE_GEDCOM:
{
FLMBYTE ucGedType;
FLMUINT16 ui16DataSize;
FLMBYTE * pucData = NULL;
// Read the GEDCOM data type and flags
if( RC_BAD( rc = read( &ucGedType, 1, NULL)))
{
goto Exit;
}
ucFlags = ucGedType & 0xF0;
ucGedType &= 0x0F;
if( ucFlags & 0x10)
{
bLeftTruncated = TRUE;
}
if( ucFlags & 0x20)
{
bRightTruncated = TRUE;
}
if( ucGedType != FLM_TEXT_TYPE &&
ucGedType != FLM_NUMBER_TYPE &&
ucGedType != FLM_BINARY_TYPE &&
ucGedType != FLM_BLOB_TYPE &&
ucGedType != FLM_CONTEXT_TYPE)
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
if( pNode)
{
GedValTypeSet( pNode, ucGedType);
if( bLeftTruncated)
{
GedSetLeftTruncated( pNode);
}
if( bRightTruncated)
{
GedSetRightTruncated( pNode);
}
}
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
ui16Tag, ucGedType, &pField)))
{
goto Exit;
}
if( bLeftTruncated)
{
(*ppRecord)->setLeftTruncated( pField, TRUE);
}
if( bRightTruncated)
{
(*ppRecord)->setRightTruncated( pField, TRUE);
}
}
if( !bHasValue)
{
break;
}
// Read the data size.
if( RC_BAD( rc = readUShort( &ui16DataSize)))
{
goto Exit;
}
// Read the data value.
if( pPool)
{
if( pNode)
{
if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode,
ucGedType, ui16DataSize)) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
}
else if( ppRecord)
{
if (RC_BAD( rc = (*ppRecord)->allocStorageSpace( pField,
ucGedType, ui16DataSize, 0, 0, 0, &pucData, NULL)))
{
goto Exit;
}
}
if( RC_BAD( rc = read( pucData, ui16DataSize, NULL)))
{
goto Exit;
}
if( pNode)
{
if( ppRecord)
{
if( RC_BAD( rc = (*ppRecord)->setBinary( pField,
pucData, ui16DataSize)))
{
goto Exit;
}
}
}
}
else
{
if( RC_BAD( rc = skip( ui16DataSize)))
{
goto Exit;
}
}
break;
}
default:
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
}
// Set the truncation flags
if( ucType != HTD_TYPE_GEDCOM)
{
if( pNode)
{
if( bLeftTruncated)
{
GedSetLeftTruncated( pNode);
}
if( bRightTruncated)
{
GedSetRightTruncated( pNode);
}
}
else if( pField)
{
if( bLeftTruncated)
{
(*ppRecord)->setLeftTruncated( pField, TRUE);
}
if( bRightTruncated)
{
(*ppRecord)->setRightTruncated( pField, TRUE);
}
}
}
// Graft the attribute into the tree.
if( pNode)
{
if( pRoot == NULL)
{
pRoot = pNode;
}
else
{
if( bSibling)
{
pPrevNode->next = pNode;
pNode->prior = pPrevNode;
GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode));
}
else if( bChild)
{
pPrevNode->next = pNode;
pNode->prior = pPrevNode;
GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode) + 1);
}
else
{
pPrevNode->next = pNode;
pNode->prior = pPrevNode;
GedNodeLevelSet( pNode, ucLevel);
}
}
}
ucPrevLevel = ucLevel;
pPrevNode = pNode;
// Reset the pool if a GEDCOM record is not going to be returned.
if( pPool && !ppNode)
{
pPool->poolReset( pvMark);
}
}
Exit:
if( RC_OK( rc))
{
if( ppNode)
{
*ppNode = pRoot;
}
}
else
{
if( ppRecord && *ppRecord)
{
(*ppRecord)->Release();
}
}
if( pPool && !ppNode)
{
pPool->poolReset( pvMark);
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FCS_DOS::FCS_DOS( void)
{
m_pOStream = NULL;
m_uiBOffset = 0;
m_tmpPool.poolInit( 512);
m_bSetupCalled = FALSE;
}
/****************************************************************************
Desc:
****************************************************************************/
FCS_DOS::~FCS_DOS( void)
{
if( m_bSetupCalled)
{
(void)close();
}
m_tmpPool.poolFree();
}
/****************************************************************************
Desc: Writes a specified number of bytes from a buffer to the output
stream.
****************************************************************************/
RCODE FCS_DOS::write(
FLMBYTE * pucData,
FLMUINT uiLength)
{
RCODE rc = FERR_OK;
// Verify that setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Write the data.
Retry_Write:
if( FCS_DOS_BUFFER_SIZE - m_uiBOffset >= uiLength)
{
f_memcpy( &(m_pucBuffer[ m_uiBOffset]), pucData, uiLength);
m_uiBOffset += uiLength;
}
else
{
if( m_uiBOffset > 0)
{
if( RC_BAD( rc = flush()))
{
goto Exit;
}
}
if( uiLength <= FCS_DOS_BUFFER_SIZE)
{
goto Retry_Write;
}
if( RC_BAD( rc = m_pOStream->write( pucData, uiLength)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes a UNICODE string to the stream in the UTF-8 format.
****************************************************************************/
RCODE FCS_DOS::writeUTF(
FLMUNICODE * puzValue)
{
FLMUINT uiUTFLen;
FLMUNICODE * puzTmp;
RCODE rc = FERR_OK;
// Verify that setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Verify pValue is valid.
flmAssert( puzValue != NULL);
// Determine the size of the string.
uiUTFLen = 0;
puzTmp = puzValue;
while( *puzTmp)
{
uiUTFLen++;
puzTmp++;
}
if( RC_BAD( rc = writeUShort( (FLMUINT16)uiUTFLen)))
{
goto Exit;
}
puzTmp = puzValue;
while( *puzTmp)
{
if( *puzTmp <= 0x007F)
{
if( RC_BAD( rc = writeByte( (FLMBYTE)(*puzTmp))))
{
goto Exit;
}
}
else if( *puzTmp >= 0x0080 && *puzTmp <= 0x07FF)
{
if( RC_BAD( rc = writeUShort((FLMUINT16)
((((FLMUINT16)(0xC0 | (FLMBYTE)((*puzTmp & 0x07C0) >> 6))) << 8) |
(FLMUINT16)(0x80 | (FLMBYTE)(*puzTmp & 0x003F))))))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = writeUShort((FLMUINT16)
((((FLMUINT16)(0xE0 | (FLMBYTE)((*puzTmp & 0xF000) >> 12))) << 8) |
(FLMUINT16)(0x80 | (FLMBYTE)((*puzTmp & 0x0FC0) >> 6))))))
{
goto Exit;
}
if( RC_BAD( rc = writeByte( (0x80 | (FLMBYTE)(*puzTmp & 0x003F)))))
{
goto Exit;
}
}
puzTmp++;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes a binary token (including length) to the stream.
****************************************************************************/
RCODE FCS_DOS::writeBinary(
FLMBYTE * pucValue,
FLMUINT uiSize)
{
RCODE rc = FERR_OK;
flmAssert( uiSize <= 0x0000FFFF);
if( RC_BAD( rc = writeUShort( (FLMUINT16)uiSize)))
{
goto Exit;
}
if( uiSize)
{
if( RC_BAD( rc = write( pucValue, uiSize)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes a large binary token (including length) to the stream.
****************************************************************************/
RCODE FCS_DOS::writeLargeBinary(
FLMBYTE * pucValue,
FLMUINT uiSize)
{
RCODE rc = FERR_OK;
if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiSize)))
{
goto Exit;
}
if( uiSize)
{
if( RC_BAD( rc = write( pucValue, uiSize)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes a Hierarchical Tagged Data record to the stream.
****************************************************************************/
RCODE FCS_DOS::writeHTD(
NODE * pHTD,
FlmRecord * pRecord,
FLMBOOL bSendForest,
FLMBOOL bSendAsGedcom)
{
FLMUINT uiPrevLevel = 0;
FLMUINT uiLevelsBack = 0;
FLMUINT uiDescriptor = 0;
FLMUINT uiCurLevel = 0;
FLMUINT uiCurValType = 0;
FLMUINT uiCurDataLen = 0;
FLMBOOL bLeftTruncated;
FLMBOOL bRightTruncated;
FLMBYTE * pucCurData = NULL;
FLMBYTE pucTmpBuf[ 32];
void * pvMark = m_tmpPool.poolMark();
NODE * pCurNode = NULL;
void * pCurField = NULL;
RCODE rc = FERR_OK;
// Verify that setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Set the current node or field
if( pHTD)
{
pCurNode = pHTD;
}
else
{
pCurField = pRecord->root();
}
while( pCurNode || pCurField)
{
// See if we are done sending the tree/forest.
if( pCurNode)
{
if( !bSendForest && (pCurNode != pHTD) &&
(GedNodeLevel( pCurNode) == GedNodeLevel( pHTD)))
{
break;
}
}
// Output the attribute's tag number.
if( pCurNode)
{
f_UINT16ToBigEndian( (FLMUINT16)GedTagNum( pCurNode), pucTmpBuf);
}
else if( pCurField)
{
f_UINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pCurField), pucTmpBuf);
}
if( RC_BAD( rc = write( pucTmpBuf, 2)))
{
goto Exit;
}
// Setup the attribute's descriptor.
uiDescriptor = 0;
uiLevelsBack = 0;
if( pCurNode)
{
uiCurLevel = GedNodeLevel( pCurNode);
}
else
{
uiCurLevel = pRecord->getLevel( pCurField);
}
if( uiCurLevel == uiPrevLevel)
{
(void)(uiDescriptor |= (HTD_LEVEL_SIBLING << HTD_LEVEL_POS));
}
else if( uiCurLevel == uiPrevLevel + 1)
{
uiDescriptor |= (HTD_LEVEL_CHILD << HTD_LEVEL_POS);
}
else if( uiCurLevel == uiPrevLevel - 1)
{
uiDescriptor |= (HTD_LEVEL_BACK << HTD_LEVEL_POS);
}
else if( uiCurLevel < uiPrevLevel)
{
uiDescriptor |= (HTD_LEVEL_BACK_X << HTD_LEVEL_POS);
uiLevelsBack = uiPrevLevel - uiCurLevel;
}
else
{
flmAssert( 0);
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
if( pCurNode)
{
uiCurDataLen = GedValLen( pCurNode);
uiCurValType = GedValType( pCurNode) & 0x0F;
bLeftTruncated = GedIsLeftTruncated( pCurNode);
bRightTruncated = GedIsRightTruncated( pCurNode);
pucCurData = (FLMBYTE *)GedValPtr( pCurNode);
}
else
{
uiCurDataLen = pRecord->getDataLength( pCurField);
uiCurValType = (FLMUINT)pRecord->getDataType( pCurField);
bLeftTruncated = pRecord->isLeftTruncated( pCurField);
bRightTruncated = pRecord->isRightTruncated( pCurField);
pucCurData = (FLMBYTE *)(pRecord->getDataPtr( pCurField));
}
if( uiCurDataLen)
{
uiDescriptor |= HTD_HAS_VALUE_FLAG;
}
if( bSendAsGedcom)
{
uiDescriptor |= HTD_TYPE_GEDCOM;
}
else
{
switch( uiCurValType)
{
case FLM_TEXT_TYPE:
{
uiDescriptor |= HTD_TYPE_UNICODE;
break;
}
case FLM_NUMBER_TYPE:
{
// To save conversion time, cheat to determine if
// the number is negative.
if( ((*pucCurData & 0xF0) == 0xB0))
{
FLMINT64 i64Value;
if( (pCurNode && RC_BAD( rc = GedGetINT64(
pCurNode, &i64Value))) ||
(pCurField && RC_BAD( rc = pRecord->getINT64(
pCurField, &i64Value))))
{
goto Exit;
}
if (i64Value >= (FLMINT64)(FLM_MIN_INT32) &&
i64Value <= (FLMINT64)(FLM_MAX_INT32))
{
uiDescriptor |= HTD_TYPE_INT;
}
else
{
uiDescriptor |= HTD_TYPE_INT64;
}
}
else
{
FLMUINT64 ui64Value;
if( (pCurNode && RC_BAD( rc = GedGetUINT64(
pCurNode, &ui64Value))) ||
(pCurField && RC_BAD( rc = pRecord->getUINT64(
pCurField, &ui64Value))))
{
goto Exit;
}
if (ui64Value <= (FLMUINT64)(FLM_MAX_UINT32))
{
uiDescriptor |= HTD_TYPE_UINT;
}
else
{
uiDescriptor |= HTD_TYPE_UINT64;
}
}
break;
}
case FLM_CONTEXT_TYPE:
{
uiDescriptor |= HTD_TYPE_CONTEXT;
break;
}
case FLM_BINARY_TYPE:
{
uiDescriptor |= HTD_TYPE_BINARY;
break;
}
default:
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
}
}
// Output the attribute's descriptor.
pucTmpBuf[ 0] = (FLMBYTE)uiDescriptor;
if( RC_BAD( rc = write( pucTmpBuf, 1)))
{
goto Exit;
}
// Output the "levels back" value (if available).
if( uiLevelsBack)
{
flmAssert( uiLevelsBack <= 0xFF);
pucTmpBuf[ 0] = (FLMBYTE)uiLevelsBack;
if( RC_BAD( rc = write( pucTmpBuf, 1)))
{
goto Exit;
}
}
// Output the attribute's value.
if( bSendAsGedcom)
{
// Output the GEDCOM data type and flags
pucTmpBuf[ 0] = (FLMBYTE)uiCurValType;
if( bLeftTruncated)
{
pucTmpBuf[ 0] |= 0x10;
}
if( bRightTruncated)
{
pucTmpBuf[ 0] |= 0x20;
}
if( RC_BAD( rc = write( pucTmpBuf, 1)))
{
goto Exit;
}
if( uiCurDataLen)
{
// Output the data size.
flmAssert( uiCurDataLen <= 0x0000FFFF);
f_UINT16ToBigEndian( (FLMUINT16)uiCurDataLen, pucTmpBuf);
if( RC_BAD( rc = write( pucTmpBuf, 2)))
{
goto Exit;
}
// Send the data.
if( RC_BAD( rc = write( pucCurData, uiCurDataLen)))
{
goto Exit;
}
}
}
else
{
// Send the value.
switch( uiCurValType)
{
case FLM_TEXT_TYPE:
{
// Extract the value.
if( uiCurDataLen)
{
FLMUINT uiBufSize;
FLMUNICODE * puzValue;
// Reset the temporary pool.
m_tmpPool.poolReset( pvMark);
if( uiCurDataLen <= 32751)
{
// Allocate a buffer that is twice the size of the
// attribute's value length. This is necessary because the
// UNICODE conversion will may double the size of the
// attribute's value. A "safety" zone of 32 bytes is added
// to the buffer size to allow for strings that may require
// more than 2x the attribute's size and to account for
// null-termination bytes.
uiBufSize = (2 * uiCurDataLen) + 32;
}
else
{
// Allocate a full 64K.
uiBufSize = 65535;
}
if( RC_BAD( rc = m_tmpPool.poolAlloc( uiBufSize,
(void **)&puzValue)))
{
goto Exit;
}
// Extract UNICODE from the attribute.
if( (pCurNode && RC_BAD( rc = GedGetUNICODE(
pCurNode, puzValue, &uiBufSize))) ||
(pCurField && RC_BAD( rc = pRecord->getUnicode(
pCurField, puzValue, &uiBufSize))))
{
if( rc == FERR_CONV_DEST_OVERFLOW)
{
// Since we did not correctly guess the buffer size,
// try again. This time, take the slow (but safe)
// approach of calculating the size of the UNICODE string.
if( (pCurNode && RC_BAD( rc = GedGetUNICODE(
pCurNode, NULL, &uiBufSize))) ||
(pCurField && RC_BAD( rc = pRecord->getUnicodeLength(
pCurField, &uiBufSize))))
{
goto Exit;
}
// Add two bytes to account for null-termination.
uiBufSize += 2;
// Reset the pool to clear the prior allocation.
m_tmpPool.poolReset( pvMark);
// Allocate the new buffer.
if( RC_BAD( rc = m_tmpPool.poolAlloc( uiBufSize,
(void **)&puzValue)))
{
goto Exit;
}
// Extract the UNICODE string.
if( (pCurNode && RC_BAD( rc = GedGetUNICODE(
pCurNode, puzValue, &uiBufSize))) ||
(pCurField && RC_BAD( rc = pRecord->getUnicode(
pCurField, puzValue, &uiBufSize))))
{
goto Exit;
}
}
else
{
goto Exit;
}
}
// Write the attribute's value.
if( RC_BAD( rc = writeUTF( puzValue)))
{
goto Exit;
}
}
break;
}
case FLM_NUMBER_TYPE:
{
if( uiCurDataLen)
{
if( uiDescriptor & HTD_TYPE_INT64)
{
// Since the number is negative, extract and send it
// as a signed 64-bit value.
FLMINT64 i64Value;
if( (pCurNode && RC_BAD( rc = GedGetINT64(
pCurNode, &i64Value))) ||
(pCurField && RC_BAD( rc = pRecord->getINT64(
pCurField, &i64Value))))
{
goto Exit;
}
// Write the value.
if( RC_BAD( rc = writeInt64( i64Value)))
{
goto Exit;
}
}
else if( uiDescriptor & HTD_TYPE_INT)
{
// Since the number is negative, extract and send it
// as a signed 32-bit value.
FLMINT32 i32Value;
if( (pCurNode && RC_BAD( rc = GedGetINT32(
pCurNode, &i32Value))) ||
(pCurField && RC_BAD( rc = pRecord->getINT32(
pCurField, &i32Value))))
{
goto Exit;
}
// Write the value.
if( RC_BAD( rc = writeInt32( i32Value)))
{
goto Exit;
}
}
else if( uiDescriptor & HTD_TYPE_UINT64)
{
// The number is non-negative 64 bit
FLMUINT64 ui64Value;
if( (pCurNode && RC_BAD( rc = GedGetUINT64(
pCurNode, &ui64Value))) ||
(pCurField && RC_BAD( rc = pRecord->getUINT64(
pCurField, &ui64Value))))
{
goto Exit;
}
// Write the value.
if( RC_BAD( rc = writeUInt64( ui64Value)))
{
goto Exit;
}
}
else
{
flmAssert( uiDescriptor & HTD_TYPE_UINT);
// The number is non-negative 32 bit
FLMUINT32 ui32Value;
if( (pCurNode && RC_BAD( rc = GedGetUINT32(
pCurNode, &ui32Value))) ||
(pCurField && RC_BAD( rc = pRecord->getUINT32(
pCurField, &ui32Value))))
{
goto Exit;
}
// Write the value.
if( RC_BAD( rc = writeUInt32( ui32Value)))
{
goto Exit;
}
}
}
break;
}
case FLM_CONTEXT_TYPE:
{
// Extract the value.
if( uiCurDataLen)
{
// The context node has a DRN value associated with
// it. Send the value as an unsigned 32-bit number.
FLMUINT uiDrn;
if( (pCurNode && RC_BAD( rc = GedGetRecPtr(
pCurNode, &uiDrn))) ||
(pCurField && RC_BAD( rc = pRecord->getUINT(
pCurField, &uiDrn))))
{
goto Exit;
}
if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiDrn)))
{
goto Exit;
}
}
break;
}
case FLM_BINARY_TYPE:
{
// Extract the value.
if( uiCurDataLen)
{
if( RC_BAD( rc = writeUShort( (FLMUINT16)uiCurDataLen)))
{
goto Exit;
}
if( RC_BAD( rc = write( pucCurData, uiCurDataLen)))
{
goto Exit;
}
}
break;
}
default:
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
}
}
uiPrevLevel = uiCurLevel;
if( pCurNode)
{
pCurNode = GedNodeNext( pCurNode);
}
else
{
pCurField = pRecord->next( pCurField);
}
}
// Write a zero tag to indicate the end of the transmission.
if( RC_BAD( rc = writeUShort( 0)))
{
goto Exit;
}
Exit:
m_tmpPool.poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc: Flushes any pending data and closes the stream.
****************************************************************************/
RCODE FCS_DOS::close( void)
{
RCODE rc = FERR_OK;
// Verify that setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Flush and terminate any pending message.
if( RC_BAD( rc = endMessage()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Flushes pending data.
****************************************************************************/
RCODE FCS_DOS::flush( void)
{
// Verify that setup has been called.
flmAssert( m_bSetupCalled == TRUE);
// Flush the output buffer.
if( m_uiBOffset > 0)
{
m_pOStream->write( m_pucBuffer, m_uiBOffset);
m_uiBOffset = 0;
}
// Flush the parent stream.
return( m_pOStream->flush());
}
/****************************************************************************
Desc: Flushes and terminates the current parent stream message
****************************************************************************/
RCODE FCS_DOS::endMessage( void)
{
RCODE rc = FERR_OK;
// Verify that Setup has been called.
flmAssert( m_bSetupCalled == TRUE);
if( !m_pOStream)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
// Flush any pending data.
if( RC_BAD( rc = flush()))
{
goto Exit;
}
// Terminate the message.
if( RC_BAD( rc = m_pOStream->endMessage()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
FCS_FIS::FCS_FIS( void)
{
m_pFileHdl = NULL;
m_pucBufPos = NULL;
m_pucBuffer = NULL;
m_uiFileOffset = 0;
m_uiBlockSize = 0;
m_uiBlockEnd = 0;
}
/****************************************************************************
Desc:
*****************************************************************************/
FCS_FIS::~FCS_FIS( void)
{
if( m_pFileHdl)
{
m_pFileHdl->Release();
}
if( m_pucBuffer)
{
f_free( &m_pucBuffer);
}
}
/****************************************************************************
Desc: Configures the input stream for use
*****************************************************************************/
RCODE FCS_FIS::setup(
const char * pszFilePath,
FLMUINT uiBlockSize)
{
RCODE rc = FERR_OK;
flmAssert( uiBlockSize);
if( RC_BAD( rc = close()))
{
goto Exit;
}
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszFilePath,
FLM_IO_RDONLY | FLM_IO_SH_DENYNONE, &m_pFileHdl)))
{
goto Exit;
}
m_uiBlockSize = uiBlockSize;
if( RC_BAD( rc = f_alloc( m_uiBlockSize, &m_pucBuffer)))
{
goto Exit;
}
m_pucBufPos = m_pucBuffer;
Exit:
return( rc);
}
/****************************************************************************
Desc: Closes the input stream and frees any resources
*****************************************************************************/
RCODE FCS_FIS::close( void)
{
if( m_pFileHdl)
{
m_pFileHdl->Release();
m_pFileHdl = NULL;
}
if( m_pucBuffer)
{
f_free( &m_pucBuffer);
}
return( FERR_OK);
}
/****************************************************************************
Desc: Reads the requested amount of data from the stream.
*****************************************************************************/
RCODE FCS_FIS::read(
FLMBYTE * pucData,
FLMUINT uiLength,
FLMUINT * puiBytesRead)
{
RCODE rc = FERR_OK;
FLMUINT uiBytesRead = 0;
FLMUINT uiMaxSize;
if( puiBytesRead)
{
*puiBytesRead = 0;
}
if( !m_pFileHdl)
{
rc = RC_SET( FERR_READING_FILE);
goto Exit;
}
while( uiLength)
{
uiMaxSize = m_uiBlockEnd - (FLMUINT)(m_pucBufPos - m_pucBuffer);
if( !uiMaxSize)
{
if( RC_BAD( rc = getNextPacket()))
{
goto Exit;
}
}
else if( uiLength <= uiMaxSize)
{
f_memcpy( pucData, m_pucBufPos, uiLength);
m_pucBufPos += uiLength;
uiBytesRead += uiLength;
uiLength = 0;
}
else
{
f_memcpy( pucData, m_pucBufPos, uiMaxSize);
m_pucBufPos += uiMaxSize;
pucData += uiMaxSize;
uiLength -= uiMaxSize;
uiBytesRead += uiMaxSize;
}
}
Exit:
if( puiBytesRead)
{
*puiBytesRead = uiBytesRead;
}
return( rc);
}
/****************************************************************************
Desc: Flushes any pending data.
*****************************************************************************/
RCODE FCS_FIS::flush( void)
{
return( FERR_OK);
}
/****************************************************************************
Desc: Flushes any pending data.
*****************************************************************************/
RCODE FCS_FIS::endMessage( void)
{
return( FERR_OK);
}
/****************************************************************************
Desc: Returns TRUE if the stream is open
*****************************************************************************/
FLMBOOL FCS_FIS::isOpen( void)
{
return( TRUE);
}
/****************************************************************************
Desc: Reads the next block from the file
*****************************************************************************/
RCODE FCS_FIS::getNextPacket( void)
{
RCODE rc = FERR_OK;
if( RC_BAD( rc = m_pFileHdl->read( m_uiFileOffset, m_uiBlockSize,
m_pucBuffer, &m_uiBlockEnd)))
{
if( rc == FERR_IO_END_OF_FILE)
{
if( !m_uiBlockEnd)
{
goto Exit;
}
else
{
rc = FERR_OK;
}
}
}
m_uiFileOffset += m_uiBlockEnd;
m_pucBufPos = m_pucBuffer;
Exit:
return( rc);
}
/****************************************************************************
Desc: Converts a UNICODE string consisting of 7-bit ASCII characters to
a native string.
*****************************************************************************/
RCODE fcsConvertUnicodeToNative(
F_Pool * pPool,
const FLMUNICODE * puzUnicode,
char ** ppucNative)
{
RCODE rc = FERR_OK;
char * pucDest = NULL;
FLMUINT uiCount;
uiCount = 0;
while( puzUnicode[ uiCount])
{
if( puzUnicode[ uiCount] > 0x007F)
{
rc = RC_SET( FERR_CONV_ILLEGAL);
goto Exit;
}
uiCount++;
}
if( RC_BAD( rc = pPool->poolAlloc( uiCount + 1, (void **)&pucDest)))
{
goto Exit;
}
uiCount = 0;
while( puzUnicode[ uiCount])
{
pucDest[ uiCount] = f_tonative( (FLMBYTE)puzUnicode[ uiCount]);
uiCount++;
}
pucDest[ uiCount] = '\0';
Exit:
*ppucNative = pucDest;
return( rc);
}
/****************************************************************************
Desc: Converts a native string to a double-byte UNICODE string.
*****************************************************************************/
RCODE fcsConvertNativeToUnicode(
F_Pool * pPool,
const char * pszNative,
FLMUNICODE ** ppuzUnicode)
{
RCODE rc = FERR_OK;
FLMUNICODE * puzDest;
FLMUINT uiCount;
uiCount = f_strlen( pszNative);
if( RC_BAD( rc = pPool->poolAlloc( uiCount + 1, (void **)&puzDest)))
{
goto Exit;
}
uiCount = 0;
while( pszNative[ uiCount])
{
puzDest[ uiCount] = (FLMUNICODE)f_toascii( pszNative[ uiCount]);
uiCount++;
}
puzDest[ uiCount] = 0;
Exit:
*ppuzUnicode = puzDest;
return( rc);
}
/****************************************************************************
Desc: Initializes members of a CREATE_OPTS structure to their default values
*****************************************************************************/
void fcsInitCreateOpts(
CREATE_OPTS * pCreateOptsRV)
{
f_memset( pCreateOptsRV, 0, sizeof( CREATE_OPTS));
pCreateOptsRV->uiBlockSize = DEFAULT_BLKSIZ;
pCreateOptsRV->uiMinRflFileSize = DEFAULT_MIN_RFL_FILE_SIZE;
pCreateOptsRV->uiMaxRflFileSize = DEFAULT_MAX_RFL_FILE_SIZE;
pCreateOptsRV->bKeepRflFiles = DEFAULT_KEEP_RFL_FILES_FLAG;
pCreateOptsRV->bLogAbortedTransToRfl = DEFAULT_LOG_ABORTED_TRANS_FLAG;
pCreateOptsRV->uiDefaultLanguage = DEFAULT_LANG;
pCreateOptsRV->uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM;
}
/****************************************************************************
Desc: Converts a CHECKPOINT_INFO structure to an HTD tree
*****************************************************************************/
RCODE fcsBuildCheckpointInfo(
CHECKPOINT_INFO * pChkptInfo,
F_Pool * pPool,
NODE ** ppTree)
{
NODE * pRootNd = NULL;
void * pMark = pPool->poolMark();
FLMUINT uiTmp;
RCODE rc = FERR_OK;
*ppTree = NULL;
// Build the root node of the tree.
if( (pRootNd = GedNodeMake( pPool, FCS_CPI_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
// Add fields to the tree.
if( pChkptInfo->bRunning)
{
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_RUNNING, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiRunningTime)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_START_TIME, (void *)&pChkptInfo->uiRunningTime,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->bForcingCheckpoint)
{
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_FORCING_CP, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiForceCheckpointRunningTime)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_FORCE_CP_START_TIME,
(void *)&pChkptInfo->uiForceCheckpointRunningTime,
4, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->iForceCheckpointReason)
{
uiTmp = pChkptInfo->iForceCheckpointReason;
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_FORCE_CP_REASON, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->bWritingDataBlocks)
{
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_WRITING_DATA_BLOCKS, (void *)&uiTmp,
4, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiLogBlocksWritten)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_LOG_BLOCKS_WRITTEN,
(void *)&pChkptInfo->uiLogBlocksWritten,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiDataBlocksWritten)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_DATA_BLOCKS_WRITTEN,
(void *)&pChkptInfo->uiDataBlocksWritten,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiDirtyCacheBytes)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_DIRTY_CACHE_BYTES,
(void *)&pChkptInfo->uiDirtyCacheBytes,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiBlockSize)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_BLOCK_SIZE, (void *)&pChkptInfo->uiBlockSize,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pChkptInfo->uiWaitTruncateTime)
{
if( RC_BAD( rc = gedAddField( pPool, pRootNd,
FCS_CPI_WAIT_TRUNC_TIME, (void *)&pChkptInfo->uiWaitTruncateTime,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
*ppTree = pRootNd;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Converts a F_LOCK_USER structure (or list of structures) to an HTD tree
*****************************************************************************/
RCODE fcsBuildLockUser(
F_LOCK_USER * pLockUser,
FLMBOOL bList,
F_Pool * pPool,
NODE ** ppTree)
{
NODE * pRootNd = NULL;
NODE * pContextNd = NULL;
void * pMark = pPool->poolMark();
RCODE rc = FERR_OK;
*ppTree = NULL;
if( !pLockUser)
{
goto Exit;
}
// Add fields to the tree.
for( ;;)
{
if( (pContextNd = GedNodeMake( pPool, FCS_LUSR_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_LUSR_THREAD_ID, (void *)&pLockUser->uiThreadId,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_LUSR_TIME, (void *)&pLockUser->uiTime,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( pRootNd == NULL)
{
pRootNd = pContextNd;
}
else
{
GedSibGraft( pRootNd, pContextNd, GED_LAST);
}
if( !bList)
{
break;
}
pLockUser++;
if( !pLockUser->uiTime)
{
break;
}
}
*ppTree = pRootNd;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Converts an HTD tree to a F_LOCK_USER structure (or list of structures)
*****************************************************************************/
RCODE fcsExtractLockUser(
NODE * pTree,
FLMBOOL bExtractAsList,
void * pvLockUser)
{
NODE * pTmpNd;
FLMUINT uiItemCount = 0;
FLMUINT fieldPath[ 8];
F_LOCK_USER * pLockUser = NULL;
FLMUINT uiLoop;
RCODE rc = FERR_OK;
if( !pTree)
{
if( bExtractAsList)
{
*((F_LOCK_USER **)pvLockUser) = NULL;
}
else
{
f_memset( (F_LOCK_USER *)pvLockUser, 0, sizeof( F_LOCK_USER));
}
goto Exit;
}
if( bExtractAsList)
{
pTmpNd = pTree;
while( pTmpNd != NULL)
{
if( GedTagNum( pTmpNd) == FCS_LUSR_CONTEXT)
{
uiItemCount++;
}
pTmpNd = pTmpNd->next;
}
if( RC_BAD( rc = f_alloc(
sizeof( F_LOCK_USER) * (uiItemCount + 1), &pLockUser)))
{
goto Exit;
}
*((F_LOCK_USER **)pvLockUser) = pLockUser;
}
else
{
pLockUser = (F_LOCK_USER *)pvLockUser;
f_memset( pLockUser, 0, sizeof( F_LOCK_USER));
uiItemCount = 1;
}
// Parse the tree and extract the values.
for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++)
{
fieldPath[ 0] = FCS_LUSR_CONTEXT;
fieldPath[ 1] = FCS_LUSR_THREAD_ID;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiThreadId);
}
fieldPath[ 0] = FCS_LUSR_CONTEXT;
fieldPath[ 1] = FCS_LUSR_TIME;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiTime);
}
pTree = GedSibNext( pTree);
}
if( bExtractAsList)
{
f_memset( &(pLockUser[ uiItemCount]), 0, sizeof( F_LOCK_USER));
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Extracts a CHECKPOINT_INFO structure from an HTD tree.
*****************************************************************************/
RCODE fcsExtractCheckpointInfo(
NODE * pTree,
CHECKPOINT_INFO * pChkptInfo)
{
NODE * pTmpNd;
FLMUINT fieldPath[ 8];
FLMUINT uiTmp;
RCODE rc = FERR_OK;
// Initialize the structure
f_memset( pChkptInfo, 0, sizeof( CHECKPOINT_INFO));
// Parse the tree and extract the values.
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_RUNNING;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
pChkptInfo->bRunning = uiTmp ? TRUE : FALSE;
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_START_TIME;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiRunningTime);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_FORCING_CP;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
pChkptInfo->bForcingCheckpoint = uiTmp ? TRUE : FALSE;
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_FORCE_CP_START_TIME;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiForceCheckpointRunningTime);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_FORCE_CP_REASON;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetINT( pTmpNd, &pChkptInfo->iForceCheckpointReason);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_WRITING_DATA_BLOCKS;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
pChkptInfo->bWritingDataBlocks = uiTmp ? TRUE : FALSE;
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_LOG_BLOCKS_WRITTEN;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiLogBlocksWritten);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_DATA_BLOCKS_WRITTEN;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiDataBlocksWritten);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_DIRTY_CACHE_BYTES;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiDirtyCacheBytes);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_BLOCK_SIZE;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiBlockSize);
}
fieldPath[ 0] = FCS_CPI_CONTEXT;
fieldPath[ 1] = FCS_CPI_WAIT_TRUNC_TIME;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pChkptInfo->uiWaitTruncateTime);
}
return( rc);
}
/****************************************************************************
Desc: Translates a FLAIM query operator to a c/s query operator
*****************************************************************************/
RCODE fcsTranslateQFlmToQCSOp(
QTYPES eFlmOp,
FLMUINT * puiCSOp)
{
RCODE rc = FERR_OK;
switch( eFlmOp)
{
case FLM_AND_OP:
*puiCSOp = FCS_ITERATOR_AND_OP;
break;
case FLM_OR_OP:
*puiCSOp = FCS_ITERATOR_OR_OP;
break;
case FLM_NOT_OP:
*puiCSOp = FCS_ITERATOR_NOT_OP;
break;
case FLM_EQ_OP:
*puiCSOp = FCS_ITERATOR_EQ_OP;
break;
case FLM_MATCH_OP:
*puiCSOp = FCS_ITERATOR_MATCH_OP;
break;
case FLM_MATCH_BEGIN_OP:
*puiCSOp = FCS_ITERATOR_MATCH_BEGIN_OP;
break;
case FLM_CONTAINS_OP:
*puiCSOp = FCS_ITERATOR_CONTAINS_OP;
break;
case FLM_NE_OP:
*puiCSOp = FCS_ITERATOR_NE_OP;
break;
case FLM_LT_OP:
*puiCSOp = FCS_ITERATOR_LT_OP;
break;
case FLM_LE_OP:
*puiCSOp = FCS_ITERATOR_LE_OP;
break;
case FLM_GT_OP:
*puiCSOp = FCS_ITERATOR_GT_OP;
break;
case FLM_GE_OP:
*puiCSOp = FCS_ITERATOR_GE_OP;
break;
case FLM_BITAND_OP:
*puiCSOp = FCS_ITERATOR_BITAND_OP;
break;
case FLM_BITOR_OP:
*puiCSOp = FCS_ITERATOR_BITOR_OP;
break;
case FLM_BITXOR_OP:
*puiCSOp = FCS_ITERATOR_BITXOR_OP;
break;
case FLM_MULT_OP:
*puiCSOp = FCS_ITERATOR_MULT_OP;
break;
case FLM_DIV_OP:
*puiCSOp = FCS_ITERATOR_DIV_OP;
break;
case FLM_MOD_OP:
*puiCSOp = FCS_ITERATOR_MOD_OP;
break;
case FLM_PLUS_OP:
*puiCSOp = FCS_ITERATOR_PLUS_OP;
break;
case FLM_MINUS_OP:
*puiCSOp = FCS_ITERATOR_MINUS_OP;
break;
case FLM_NEG_OP:
*puiCSOp = FCS_ITERATOR_NEG_OP;
break;
case FLM_LPAREN_OP:
*puiCSOp = FCS_ITERATOR_LPAREN_OP;
break;
case FLM_RPAREN_OP:
*puiCSOp = FCS_ITERATOR_RPAREN_OP;
break;
default:
rc = RC_SET( FERR_NOT_IMPLEMENTED);
break;
}
return( rc);
}
/****************************************************************************
Desc: Translates a FLAIM query operator to a c/s query operator
*****************************************************************************/
RCODE fcsTranslateQCSToQFlmOp(
FLMUINT uiCSOp,
QTYPES * peFlmOp)
{
RCODE rc = FERR_OK;
switch( uiCSOp)
{
case FCS_ITERATOR_AND_OP:
*peFlmOp = FLM_AND_OP;
break;
case FCS_ITERATOR_OR_OP:
*peFlmOp = FLM_OR_OP;
break;
case FCS_ITERATOR_NOT_OP:
*peFlmOp = FLM_NOT_OP;
break;
case FCS_ITERATOR_EQ_OP:
*peFlmOp = FLM_EQ_OP;
break;
case FCS_ITERATOR_MATCH_OP:
*peFlmOp = FLM_MATCH_OP;
break;
case FCS_ITERATOR_MATCH_BEGIN_OP:
*peFlmOp = FLM_MATCH_BEGIN_OP;
break;
case FCS_ITERATOR_CONTAINS_OP:
*peFlmOp = FLM_CONTAINS_OP;
break;
case FCS_ITERATOR_NE_OP:
*peFlmOp = FLM_NE_OP;
break;
case FCS_ITERATOR_LT_OP:
*peFlmOp = FLM_LT_OP;
break;
case FCS_ITERATOR_LE_OP:
*peFlmOp = FLM_LE_OP;
break;
case FCS_ITERATOR_GT_OP:
*peFlmOp = FLM_GT_OP;
break;
case FCS_ITERATOR_GE_OP:
*peFlmOp = FLM_GE_OP;
break;
case FCS_ITERATOR_BITAND_OP:
*peFlmOp = FLM_BITAND_OP;
break;
case FCS_ITERATOR_BITOR_OP:
*peFlmOp = FLM_BITOR_OP;
break;
case FCS_ITERATOR_BITXOR_OP:
*peFlmOp = FLM_BITXOR_OP;
break;
case FCS_ITERATOR_MULT_OP:
*peFlmOp = FLM_MULT_OP;
break;
case FCS_ITERATOR_DIV_OP:
*peFlmOp = FLM_DIV_OP;
break;
case FCS_ITERATOR_MOD_OP:
*peFlmOp = FLM_MOD_OP;
break;
case FCS_ITERATOR_PLUS_OP:
*peFlmOp = FLM_PLUS_OP;
break;
case FCS_ITERATOR_MINUS_OP:
*peFlmOp = FLM_MINUS_OP;
break;
case FCS_ITERATOR_NEG_OP:
*peFlmOp = FLM_NEG_OP;
break;
case FCS_ITERATOR_LPAREN_OP:
*peFlmOp = FLM_LPAREN_OP;
break;
case FCS_ITERATOR_RPAREN_OP:
*peFlmOp = FLM_RPAREN_OP;
break;
default:
rc = RC_SET( FERR_NOT_IMPLEMENTED);
break;
}
return( rc);
}
/****************************************************************************
Desc: Converts an FINDEX_STATUS structure to an HTD tree
*****************************************************************************/
RCODE fcsBuildIndexStatus(
FINDEX_STATUS * pIndexStatus,
F_Pool * pPool,
NODE ** ppTree)
{
NODE * pContextNd = NULL;
void * pMark = pPool->poolMark();
FLMUINT uiTmp;
RCODE rc = FERR_OK;
*ppTree = NULL;
if( !pIndexStatus)
{
goto Exit;
}
// Add fields to the tree.
if( (pContextNd = GedNodeMake( pPool, FCS_IXSTAT_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
if( pIndexStatus->uiIndexNum)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_INDEX_NUM, (void *)&pIndexStatus->uiIndexNum,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pIndexStatus->uiStartTime)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_START_TIME, (void *)&pIndexStatus->uiStartTime,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
// Send the "auto-online" flag for backwards compatibility
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_AUTO_ONLINE,
(void *)&uiTmp, 0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
// Send the priority (high) for backwards compatibility
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_PRIORITY,
(void *)&uiTmp, 0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
// Set the suspended time field (for backwards compatibility)
// if the index is suspended
if( pIndexStatus->bSuspended)
{
f_timeGetSeconds( &uiTmp);
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_SUSPEND_TIME, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pIndexStatus->uiLastRecordIdIndexed)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_LAST_REC_INDEXED,
(void *)&pIndexStatus->uiLastRecordIdIndexed,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pIndexStatus->uiKeysProcessed)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_KEYS_PROCESSED,
(void *)&pIndexStatus->uiKeysProcessed,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pIndexStatus->uiRecordsProcessed)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_RECS_PROCESSED,
(void *)&pIndexStatus->uiRecordsProcessed,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pIndexStatus->bSuspended)
{
uiTmp = (FLMUINT)pIndexStatus->bSuspended;
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_IXSTAT_STATE, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
*ppTree = pContextNd;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Extracts an FINDEX_STATUS structure from an HTD tree.
*****************************************************************************/
RCODE fcsExtractIndexStatus(
NODE * pTree,
FINDEX_STATUS * pIndexStatus)
{
NODE * pTmpNd;
FLMUINT fieldPath[ 8];
RCODE rc = FERR_OK;
// Initialize the structure
f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS));
// Make sure pTree is non-null
if( !pTree)
{
goto Exit;
}
// Parse the tree and extract the values.
fieldPath[ 0] = FCS_IXSTAT_CONTEXT;
fieldPath[ 1] = FCS_IXSTAT_INDEX_NUM;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pIndexStatus->uiIndexNum);
}
fieldPath[ 1] = FCS_IXSTAT_START_TIME;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pIndexStatus->uiStartTime);
}
fieldPath[ 1] = FCS_IXSTAT_LAST_REC_INDEXED;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pIndexStatus->uiLastRecordIdIndexed);
}
fieldPath[ 1] = FCS_IXSTAT_KEYS_PROCESSED;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pIndexStatus->uiKeysProcessed);
}
fieldPath[ 1] = FCS_IXSTAT_RECS_PROCESSED;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pIndexStatus->uiRecordsProcessed);
}
fieldPath[ 1] = FCS_IXSTAT_STATE;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
FLMUINT uiTmp;
(void)GedGetUINT( pTmpNd, &uiTmp);
pIndexStatus->bSuspended = uiTmp ? TRUE : FALSE;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Converts an FLM_MEM_INFO structure to an HTD tree
*****************************************************************************/
RCODE fcsBuildMemInfo(
FLM_MEM_INFO * pMemInfo,
F_Pool * pPool,
NODE ** ppTree)
{
FLMUINT uiTmp;
NODE * pContextNd = NULL;
NODE * pSubContext = NULL;
void * pMark = pPool->poolMark();
FLM_CACHE_USAGE * pUsage;
RCODE rc = FERR_OK;
*ppTree = NULL;
if( !pMemInfo)
{
goto Exit;
}
// Add fields to the tree.
if( (pContextNd = GedNodeMake( pPool,
FCS_MEMINFO_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
if( pMemInfo->bDynamicCacheAdjust)
{
uiTmp = 1;
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_MEMINFO_DYNA_CACHE_ADJ, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pMemInfo->uiCacheAdjustPercent)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_MEMINFO_CACHE_ADJ_PERCENT,
(void *)&pMemInfo->uiCacheAdjustPercent,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pMemInfo->uiCacheAdjustMin)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_MEMINFO_CACHE_ADJ_MIN,
(void *)&pMemInfo->uiCacheAdjustMin,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pMemInfo->uiCacheAdjustMax)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_MEMINFO_CACHE_ADJ_MAX,
(void *)&pMemInfo->uiCacheAdjustMax,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pMemInfo->uiCacheAdjustMinToLeave)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE,
(void *)&pMemInfo->uiCacheAdjustMinToLeave,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
pUsage = &pMemInfo->RecordCache;
if( (pSubContext = GedNodeMake( pPool,
FCS_MEMINFO_RECORD_CACHE, &rc)) == NULL)
{
goto Exit;
}
add_usage:
if( pUsage->uiMaxBytes)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_MAX_BYTES,
(void *)&pUsage->uiMaxBytes,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiCount)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_COUNT,
(void *)&pUsage->uiCount,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiOldVerCount)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_OLD_VER_COUNT,
(void *)&pUsage->uiOldVerCount,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiTotalBytesAllocated)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_TOTAL_BYTES_ALLOC,
(void *)&pUsage->uiTotalBytesAllocated,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiOldVerBytes)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_OLD_VER_BYTES,
(void *)&pUsage->uiOldVerBytes,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiCacheHits)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_CACHE_HITS,
(void *)&pUsage->uiCacheHits,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiCacheHitLooks)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_CACHE_HIT_LOOKS,
(void *)&pUsage->uiCacheHitLooks,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiCacheFaults)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_CACHE_FAULTS,
(void *)&pUsage->uiCacheFaults,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pUsage->uiCacheFaultLooks)
{
if( RC_BAD( rc = gedAddField( pPool, pSubContext,
FCS_MEMINFO_CACHE_FAULT_LOOKS,
(void *)&pUsage->uiCacheFaultLooks,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( GedChild( pSubContext))
{
GedChildGraft( pContextNd, pSubContext, GED_LAST);
}
if( pUsage != &pMemInfo->BlockCache)
{
pUsage = &pMemInfo->BlockCache;
if( (pSubContext = GedNodeMake( pPool,
FCS_MEMINFO_BLOCK_CACHE, &rc)) == NULL)
{
goto Exit;
}
goto add_usage;
}
*ppTree = pContextNd;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Extracts a FLM_MEM_INFO structure from an HTD tree.
*****************************************************************************/
RCODE fcsExtractMemInfo(
NODE * pTree,
FLM_MEM_INFO * pMemInfo)
{
NODE * pTmpNd;
FLMUINT fieldPath[ 8];
FLMUINT uiTmp;
FLM_CACHE_USAGE * pUsage;
FLMUINT uiUsageTag;
RCODE rc = FERR_OK;
// Initialize the structure
f_memset( pMemInfo, 0, sizeof( FLM_MEM_INFO));
// Make sure pTree is non-null
if( !pTree)
{
goto Exit;
}
// Parse the tree and extract the values.
fieldPath[ 0] = FCS_MEMINFO_CONTEXT;
fieldPath[ 1] = FCS_MEMINFO_DYNA_CACHE_ADJ;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
pMemInfo->bDynamicCacheAdjust = (FLMBOOL)(uiTmp ? TRUE : FALSE);
}
fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_PERCENT;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustPercent);
}
fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMin);
}
fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MAX;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMax);
}
fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMinToLeave);
}
pUsage = &pMemInfo->RecordCache;
uiUsageTag = FCS_MEMINFO_RECORD_CACHE;
get_usage:
fieldPath[ 0] = FCS_MEMINFO_CONTEXT;
fieldPath[ 1] = uiUsageTag;
fieldPath[ 2] = FCS_MEMINFO_MAX_BYTES;
fieldPath[ 3] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiMaxBytes);
}
fieldPath[ 2] = FCS_MEMINFO_COUNT;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiCount);
}
fieldPath[ 2] = FCS_MEMINFO_OLD_VER_COUNT;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiOldVerCount);
}
fieldPath[ 2] = FCS_MEMINFO_TOTAL_BYTES_ALLOC;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiTotalBytesAllocated);
}
fieldPath[ 2] = FCS_MEMINFO_OLD_VER_BYTES;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiOldVerBytes);
}
fieldPath[ 2] = FCS_MEMINFO_CACHE_HITS;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiCacheHits);
}
fieldPath[ 2] = FCS_MEMINFO_CACHE_HIT_LOOKS;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiCacheHitLooks);
}
fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULTS;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaults);
}
fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULT_LOOKS;
if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaultLooks);
}
if( pUsage != &pMemInfo->BlockCache)
{
pUsage = &pMemInfo->BlockCache;
uiUsageTag = FCS_MEMINFO_BLOCK_CACHE;
goto get_usage;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Builds a GEDCOM tree containing information on all FLAIM threads
*****************************************************************************/
RCODE fcsBuildThreadInfo(
F_Pool * pPool,
NODE ** ppTree)
{
NODE * pContextNd = NULL;
NODE * pRootNd = NULL;
void * pMark = pPool->poolMark();
F_THREAD_INFO * pThreadInfo = NULL;
FLMUINT uiNumThreads;
FLMUINT uiLoop;
RCODE rc = FERR_OK;
*ppTree = NULL;
// Query FLAIM for available threads
if( RC_BAD( rc = FlmGetThreadInfo( pPool, &pThreadInfo, &uiNumThreads)))
{
goto Exit;
}
if( (pRootNd = GedNodeMake( pPool,
FCS_THREAD_INFO_ROOT, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = GedPutRecPtr( pPool, pRootNd, uiNumThreads)))
{
goto Exit;
}
for( uiLoop = 0; uiLoop < uiNumThreads; uiLoop++)
{
// Add fields to the tree.
if( (pContextNd = GedNodeMake( pPool,
FCS_THREAD_INFO_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
GedChildGraft( pRootNd, pContextNd, GED_LAST);
if( pThreadInfo->uiThreadId)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_THREAD_ID, (void *)&pThreadInfo->uiThreadId,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pThreadInfo->uiThreadGroup)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_THREAD_GROUP, (void *)&pThreadInfo->uiThreadGroup,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pThreadInfo->uiAppId)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_APP_ID, (void *)&pThreadInfo->uiAppId,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pThreadInfo->uiStartTime)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_START_TIME, (void *)&pThreadInfo->uiStartTime,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
}
if( pThreadInfo->pszThreadName)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_THREAD_NAME, (void *)pThreadInfo->pszThreadName,
0, FLM_TEXT_TYPE)))
{
goto Exit;
}
}
if( pThreadInfo->pszThreadStatus)
{
if( RC_BAD( rc = gedAddField( pPool, pContextNd,
FCS_THREADINFO_THREAD_STATUS, (void *)pThreadInfo->pszThreadStatus,
0, FLM_TEXT_TYPE)))
{
goto Exit;
}
}
pThreadInfo++;
}
*ppTree = pRootNd;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Extracts a list of F_THREAD_INFO structure from an HTD tree.
*****************************************************************************/
RCODE fcsExtractThreadInfo(
NODE * pTree,
F_Pool * pPool,
F_THREAD_INFO ** ppThreadInfo,
FLMUINT * puiNumThreads)
{
NODE * pTmpNd;
NODE * pContextNd;
void * pMark = pPool->poolMark();
FLMUINT uiTmp;
F_THREAD_INFO * pThreadInfo;
F_THREAD_INFO * pCurThread;
FLMUINT uiNumThreads;
FLMUINT uiLoop;
RCODE rc = FERR_OK;
*ppThreadInfo = NULL;
*puiNumThreads = 0;
if( GedTagNum( pTree) != FCS_THREAD_INFO_ROOT)
{
rc = RC_SET( FERR_SYNTAX);
goto Exit;
}
if( RC_BAD( rc = GedGetUINT( pTree, &uiNumThreads)))
{
goto Exit;
}
if( !uiNumThreads)
{
goto Exit;
}
if( RC_BAD( rc = pPool->poolAlloc( uiNumThreads * sizeof( F_THREAD_INFO),
(void **)&pThreadInfo)))
{
goto Exit;
}
if( (pContextNd = GedFind( 1, pTree,
FCS_THREAD_INFO_CONTEXT, 1)) == NULL)
{
rc = RC_SET( FERR_SYNTAX);
goto Exit;
}
for( uiLoop = 0, pCurThread = pThreadInfo;
uiLoop < uiNumThreads;
uiLoop++, pCurThread++)
{
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_THREAD_ID, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pCurThread->uiThreadId);
}
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_THREAD_GROUP, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pCurThread->uiThreadGroup);
}
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_APP_ID, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pCurThread->uiAppId);
}
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_START_TIME, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &pCurThread->uiStartTime);
}
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_THREAD_NAME, 1)) != NULL)
{
if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp)))
{
goto Exit;
}
if( uiTmp)
{
uiTmp++;
if( RC_BAD( rc = pPool->poolAlloc( uiTmp,
(void **)&pCurThread->pszThreadName)))
{
goto Exit;
}
}
if( RC_BAD( rc = GedGetNATIVE( pTmpNd,
pCurThread->pszThreadName, &uiTmp)))
{
goto Exit;
}
}
if( (pTmpNd = GedFind( 1, pContextNd,
FCS_THREADINFO_THREAD_STATUS, 1)) != NULL)
{
if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp)))
{
goto Exit;
}
if( uiTmp)
{
uiTmp++;
if( RC_BAD( rc = pPool->poolAlloc( uiTmp,
(void **)pCurThread->pszThreadStatus)))
{
goto Exit;
}
}
if( RC_BAD( rc = GedGetNATIVE( pTmpNd,
pCurThread->pszThreadStatus, &uiTmp)))
{
goto Exit;
}
}
if( (pContextNd = GedSibNext( pContextNd)) != NULL)
{
if( GedTagNum( pContextNd) != FCS_THREAD_INFO_CONTEXT)
{
rc = RC_SET( FERR_SYNTAX);
goto Exit;
}
}
}
*ppThreadInfo = pThreadInfo;
*puiNumThreads = uiNumThreads;
Exit:
if( RC_BAD( rc))
{
pPool->poolReset( pMark);
}
return( rc);
}
/****************************************************************************
Desc: Reads a block from a remote database
*****************************************************************************/
RCODE fcsGetBlock(
HFDB hDb,
FLMUINT uiAddress,
FLMUINT uiMinTransId,
FLMUINT * puiCount,
FLMUINT * puiBlocksExamined,
FLMUINT * puiNextBlkAddr,
FLMUINT uiFlags,
FLMBYTE * pucBlock)
{
FDB * pDb = (FDB *)hDb;
RCODE rc = FERR_OK;
flmAssert( IsInCSMode( hDb));
fdbInitCS( pDb);
CS_CONTEXT * pCSContext = pDb->pCSContext;
FCL_WIRE Wire( pCSContext, pDb);
if( !pCSContext->bConnectionGood)
{
rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.sendOp(
FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_BLOCK)))
{
goto Exit;
}
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_ADDRESS, uiAddress)))
{
goto Transmission_Error;
}
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TRANSACTION_ID,
uiMinTransId)))
{
goto Transmission_Error;
}
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_COUNT, *puiCount)))
{
goto Transmission_Error;
}
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiFlags)))
{
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.sendTerminate()))
{
goto Transmission_Error;
}
// Read the response
if (RC_BAD( rc = Wire.read()))
{
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.getRCode()))
{
if( rc != FERR_IO_END_OF_FILE)
{
goto Exit;
}
}
*puiBlocksExamined = (FLMUINT)Wire.getNumber2();
*puiCount = (FLMUINT)Wire.getCount();
*puiNextBlkAddr = Wire.getAddress();
if( *puiCount)
{
f_memcpy( pucBlock, Wire.getBlock(), Wire.getBlockSize());
}
goto Exit;
Transmission_Error:
pCSContext->bConnectionGood = FALSE;
goto Exit;
Exit:
fdbExit( pDb);
return( rc);
}
/****************************************************************************
Desc: Instructs the server to generate a serial number
*****************************************************************************/
RCODE fcsCreateSerialNumber(
void * pvCSContext,
FLMBYTE * pucSerialNum)
{
RCODE rc = FERR_OK;
CS_CONTEXT * pCSContext = (CS_CONTEXT *)pvCSContext;
FCL_WIRE Wire( pCSContext);
if( !pCSContext->bConnectionGood)
{
rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.sendOp(
FCS_OPCLASS_MISC, FCS_OP_CREATE_SERIAL_NUM)))
{
goto Exit;
}
if( RC_BAD( rc = Wire.sendTerminate()))
{
goto Transmission_Error;
}
// Read the response
if (RC_BAD( rc = Wire.read()))
{
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.getRCode()))
{
goto Exit;
}
if( !Wire.getSerialNum())
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
f_memcpy( pucSerialNum, Wire.getSerialNum(), F_SERIAL_NUM_SIZE);
goto Exit;
Transmission_Error:
pCSContext->bConnectionGood = FALSE;
goto Exit;
Exit:
return( rc);
}
/****************************************************************************
Desc: Sets or clears the backup active flag for the database
Note: This should only be called internally from the backup routines.
*****************************************************************************/
RCODE fcsSetBackupActiveFlag(
HFDB hDb,
FLMBOOL bBackupActive)
{
FDB * pDb = (FDB *)hDb;
RCODE rc = FERR_OK;
flmAssert( IsInCSMode( hDb));
fdbInitCS( pDb);
CS_CONTEXT * pCSContext = pDb->pCSContext;
FCL_WIRE Wire( pCSContext, pDb);
if( !pCSContext->bConnectionGood)
{
rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.sendOp(
FCS_OPCLASS_DATABASE, FCS_OP_DB_SET_BACKUP_FLAG)))
{
goto Exit;
}
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_BOOLEAN, bBackupActive)))
{
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.sendTerminate()))
{
goto Transmission_Error;
}
/* Read the response. */
if (RC_BAD( rc = Wire.read()))
{
goto Transmission_Error;
}
if( RC_BAD( rc = Wire.getRCode()))
{
goto Exit;
}
goto Exit;
Transmission_Error:
pCSContext->bConnectionGood = FALSE;
goto Exit;
Exit:
fdbExit( pDb);
return( rc);
}
/****************************************************************************
Desc: Commits an update transaction and updates the log header.
Note: This should only be called internally from the backup routines.
*****************************************************************************/
RCODE fcsDbTransCommitEx(
HFDB hDb,
FLMBOOL bForceCheckpoint,
FLMBYTE * pucLogHdr)
{
RCODE rc = FERR_OK;
FDB * pDb = (FDB *)hDb;
FLMBOOL bInitializedFdb = FALSE;
if( IsInCSMode( hDb))
{
fdbInitCS( pDb);
bInitializedFdb = TRUE;
FCL_WIRE Wire( pDb->pCSContext, pDb);
if (!pDb->pCSContext->bConnectionGood)
{
rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
}
else
{
rc = Wire.doTransOp(
FCS_OP_TRANSACTION_COMMIT_EX, 0, 0, 0,
pucLogHdr, bForceCheckpoint);
}
}
else
{
rc = RC_SET( FERR_ILLEGAL_OP);
goto Exit;
}
Exit:
if( bInitializedFdb)
{
fdbExit( pDb);
}
return( rc);
}
/****************************************************************************
Desc: Generates a hex-encoded, obfuscated string consisting of characters
0-9, A-F from the passed-in data buffer.
*****************************************************************************/
RCODE flmGenerateHexPacket(
FLMBYTE * pucData,
FLMUINT uiDataSize,
FLMBYTE ** ppucPacket)
{
RCODE rc = FERR_OK;
FLMBYTE * pucBinPacket = NULL;
FLMBYTE * pucHexPacket = NULL;
FLMBYTE * pucUsedMap = NULL;
FLMUINT32 ui32Tmp;
FLMUINT uiLoop;
FLMUINT uiSlot = 0;
FLMBYTE ucTmp[ 32];
FLMUINT uiBinPacketSize;
FLMBOOL bTmp;
IF_RandomGenerator * pRandGen = NULL;
// Determine the packet size. Make the minimum packet size 128 bytes
// to account for the 64-byte "header" and for the overhead of the
// CRC bytes, etc. Round the packet size up to the nearest 64-byte
// boundary after adding on the data size.
uiBinPacketSize = 128 + uiDataSize;
if( (uiBinPacketSize % 64) != 0)
{
uiBinPacketSize += (64 - (uiBinPacketSize % 64));
}
// Allocate buffers for building the packet
if( RC_BAD( rc = f_alloc( uiBinPacketSize, &pucBinPacket)))
{
goto Exit;
}
if( RC_BAD( rc = f_calloc( uiBinPacketSize, &pucUsedMap)))
{
goto Exit;
}
// First 64-bytes of the packet are reserved as a header
f_memset( pucUsedMap, 0xFF, 64);
// Initialize the random number generator and seed with the current
// time.
if( RC_BAD( rc = FlmAllocRandomGenerator( &pRandGen)))
{
goto Exit;
}
// Fill the packet with random "noise"
for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop += 4)
{
ui32Tmp = pRandGen->getUINT32();
UD2FBA( ui32Tmp, &pucBinPacket[ uiLoop]);
}
for( uiLoop = 0; uiLoop < 512; uiLoop++)
{
ui32Tmp = pRandGen->getUINT32();
UD2FBA( ui32Tmp, &pucBinPacket[
pRandGen->getUINT32( 1, (int)(uiBinPacketSize / 4)) - 1]);
}
// Determine a new random seed based on bytes in the
// packet header
if( (ui32Tmp = (FLMUINT32)FB2UD( &pucBinPacket[
pRandGen->getUINT32( 1, 61) - 1])) == 0)
{
ui32Tmp = 1;
}
pRandGen->setSeed( ui32Tmp);
// Use the CRC of the header and the also first four bytes
// of the header as an 8-byte validation signature. This will
// be needed to decode the packet.
// Initialize the CRC to 0xFFFFFFFF and then compute the 1's
// complement of the returned CRC. This implements the
// "standard" CRC used by PKZIP, etc.
ui32Tmp = 0xFFFFFFFF;
f_updateCRC( pucBinPacket, 64, &ui32Tmp);
ui32Tmp = ~ui32Tmp;
UD2FBA( ui32Tmp, &ucTmp[ 0]);
f_memcpy( &ucTmp[ 4], pucBinPacket, 4);
for( uiLoop = 0; uiLoop < 8; uiLoop++)
{
bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize,
pRandGen, &uiSlot);
flmAssert( bTmp);
pucBinPacket[ uiSlot] = ucTmp[ uiLoop];
}
// Encode the data size
UD2FBA( (FLMUINT32)uiDataSize, &ucTmp[ 0]);
for( uiLoop = 0; uiLoop < 4; uiLoop++)
{
bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize,
pRandGen, &uiSlot);
flmAssert( bTmp);
pucBinPacket[ uiSlot] = ucTmp[ uiLoop];
}
// Randomly dispurse the data throughout the buffer. Obfuscate the
// data using the first 64-bytes of the buffer.
for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++)
{
bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize,
pRandGen, &uiSlot);
flmAssert( bTmp);
pucBinPacket[ uiSlot] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64];
}
// Calculate and encode the data CRC
ui32Tmp = 0xFFFFFFFF;
f_updateCRC( pucData, uiDataSize, &ui32Tmp);
ui32Tmp = ~ui32Tmp;
UD2FBA( ui32Tmp, &ucTmp[ 0]);
for( uiLoop = 0; uiLoop < 4; uiLoop++)
{
bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize,
pRandGen, &uiSlot);
flmAssert( bTmp);
pucBinPacket[ uiSlot] = ucTmp[ uiLoop];
}
// Hex encode the binary packet
if( RC_BAD( rc = f_alloc(
(uiBinPacketSize * 2) + 1, &pucHexPacket)))
{
goto Exit;
}
for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop++)
{
FLMBYTE ucLowNibble = pucBinPacket[ uiLoop] & 0x0F;
FLMBYTE ucHighNibble = (pucBinPacket[ uiLoop] & 0xF0) >> 4;
pucHexPacket[ uiLoop << 1] = (ucHighNibble <= 9
? (ucHighNibble + '0')
: ((ucHighNibble - 0xA) + 'A'));
pucHexPacket[ (uiLoop << 1) + 1] = (ucLowNibble <= 9
? (ucLowNibble + '0')
: ((ucLowNibble - 0xA) + 'A'));
}
pucHexPacket[ uiBinPacketSize * 2] = 0;
*ppucPacket = pucHexPacket;
pucHexPacket = NULL;
Exit:
if( pucUsedMap)
{
f_free( &pucUsedMap);
}
if( pucBinPacket)
{
f_free( &pucBinPacket);
}
if( pucHexPacket)
{
f_free( &pucHexPacket);
}
if( pRandGen)
{
pRandGen->Release();
}
return( rc);
}
/****************************************************************************
Desc: Extracts a data buffer from the passed-in hex-encoded, obfuscated
string.
*****************************************************************************/
RCODE flmExtractHexPacketData(
FLMBYTE * pucPacket,
FLMBYTE ** ppucData,
FLMUINT * puiDataSize)
{
RCODE rc = FERR_OK;
FLMBYTE * pucUsedMap = NULL;
FLMBYTE * pucData = NULL;
FLMBYTE * pucBinPacket = NULL;
FLMBYTE * pucTmp;
FLMUINT32 ui32Tmp;
FLMUINT32 ui32FirstCRC;
FLMUINT32 ui32Seed;
FLMUINT uiPacketSize;
FLMUINT uiLoop;
FLMUINT uiDataSize;
FLMBYTE ucTmp[ 32];
FLMBYTE ucVal = 0;
FLMBOOL bValid;
IF_RandomGenerator * pRandGen = NULL;
if( RC_BAD( rc = FlmAllocRandomGenerator( &pRandGen)))
{
goto Exit;
}
// Determine the packet size, ignoring all characters except 0-9, A-F
uiPacketSize = 0;
pucTmp = pucPacket;
while( *pucTmp)
{
if( (*pucTmp >= '0' && *pucTmp <= '9') ||
(*pucTmp >= 'A' && *pucTmp <= 'F'))
{
uiPacketSize++;
}
pucTmp++;
}
if( uiPacketSize & 0x00000001 ||
(uiPacketSize % 4) != 0 || uiPacketSize < 128)
{
rc = RC_SET( FERR_INVALID_CRC);
goto Exit;
}
// Get the actual size of the decoded binary data by dividing
// the packet size by 2
uiPacketSize >>= 1;
// Allocate a buffer and convert the data from hex ASCII to binary
if( RC_BAD( rc = f_calloc(
uiPacketSize, &pucBinPacket)))
{
goto Exit;
}
uiLoop = 0;
pucTmp = pucPacket;
while( *pucTmp)
{
bValid = FALSE;
if( *pucTmp >= '0' && *pucTmp <= '9')
{
ucVal = *pucTmp - '0';
bValid = TRUE;
}
else if( *pucTmp >= 'A' && *pucTmp <= 'F')
{
ucVal = (*pucTmp - 'A') + 0x0A;
bValid = TRUE;
}
if( bValid)
{
if( (uiLoop & 0x00000001) == 0)
{
ucVal <<= 4;
}
pucBinPacket[ uiLoop >> 1] |= ucVal;
uiLoop++;
}
pucTmp++;
}
// Allocate the data map
if( RC_BAD( rc = f_calloc( uiPacketSize, &pucUsedMap)))
{
goto Exit;
}
// First 64-bytes of the packet are reserved
f_memset( pucUsedMap, 0xFF, 64);
// Determine the CRC of the 1st 64-bytes
ui32FirstCRC = 0xFFFFFFFF;
f_updateCRC( pucBinPacket, 64, &ui32FirstCRC);
ui32FirstCRC = ~ui32FirstCRC;
// Search for the random seed within the first 64 bytes
ui32Seed = 0;
for( uiLoop = 0; uiLoop < 61; uiLoop++)
{
ui32Tmp = FB2UD( &pucBinPacket[ uiLoop]);
pRandGen->setSeed( ui32Tmp);
if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize,
pucBinPacket, pRandGen, ucTmp, 8)))
{
goto Exit;
}
if( FB2UD( &ucTmp[ 0]) == ui32FirstCRC &&
f_memcmp( &ucTmp[ 4], &pucBinPacket[ 0], 4) == 0)
{
ui32Seed = ui32Tmp;
break;
}
// Reset the "used" map
f_memset( pucUsedMap, 0, uiPacketSize);
f_memset( pucUsedMap, 0xFF, 64);
}
if( !ui32Seed)
{
rc = RC_SET( FERR_INVALID_CRC);
goto Exit;
}
// Get the data size
if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize,
pucBinPacket, pRandGen, ucTmp, 4)))
{
goto Exit;
}
uiDataSize = (FLMUINT)FB2UD( &ucTmp[ 0]);
if( uiDataSize > uiPacketSize)
{
rc = RC_SET( FERR_INVALID_CRC);
goto Exit;
}
// Allocate space for the data
if( RC_BAD( rc = f_alloc( uiDataSize, &pucData)))
{
goto Exit;
}
// Get the data
if( RC_BAD( rc = flmGetNextHexPacketBytes(
pucUsedMap, uiPacketSize, pucBinPacket, pRandGen, pucData, uiDataSize)))
{
goto Exit;
}
// Un-obfuscate the data
for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++)
{
pucData[ uiLoop] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64];
}
// Get the data CRC
if( RC_BAD( rc = flmGetNextHexPacketBytes(
pucUsedMap, uiPacketSize, pucBinPacket, pRandGen, ucTmp, 4)))
{
goto Exit;
}
// Verify the data CRC
ui32Tmp = 0xFFFFFFFF;
f_updateCRC( pucData, uiDataSize, &ui32Tmp);
ui32Tmp = ~ui32Tmp;
if( ui32Tmp != FB2UD( &ucTmp[ 0]))
{
rc = RC_SET( FERR_INVALID_CRC);
goto Exit;
}
*ppucData = pucData;
pucData = NULL;
*puiDataSize = uiDataSize;
Exit:
if( pucUsedMap)
{
f_free( &pucUsedMap);
}
if( pucData)
{
f_free( &pucData);
}
if( pucBinPacket)
{
f_free( &pucBinPacket);
}
if( pRandGen)
{
pRandGen->Release();
}
return( rc);
}
/****************************************************************************
Desc: Used by flmGenerateHexPacket to find an unused byte in the packet
*****************************************************************************/
FLMBOOL flmGetNextHexPacketSlot(
FLMBYTE * pucUsedMap,
FLMUINT uiMapSize,
IF_RandomGenerator * pRandGen,
FLMUINT * puiSlot)
{
FLMUINT uiLoop;
FLMUINT uiSlot = 0;
FLMBOOL bFound = FALSE;
for( uiLoop = 0; uiLoop < 100; uiLoop++)
{
uiSlot = ((FLMUINT)pRandGen->getUINT32()) % uiMapSize;
if( !pucUsedMap[ uiSlot])
{
bFound = TRUE;
goto Exit;
}
}
// Scan the table from the top to find an empty slot
for( uiSlot = 0; uiSlot < uiMapSize; uiSlot++)
{
if( !pucUsedMap[ uiSlot])
{
bFound = TRUE;
goto Exit;
}
}
Exit:
if( bFound)
{
flmAssert( uiSlot < uiMapSize);
*puiSlot = uiSlot;
pucUsedMap[ uiSlot] = 0xFF;
}
return( bFound);
}
/****************************************************************************
Desc: Used by flmExtractHexPacket to get the next N bytes of data from the
packet.
*****************************************************************************/
RCODE flmGetNextHexPacketBytes(
FLMBYTE * pucUsedMap,
FLMUINT uiMapSize,
FLMBYTE * pucPacket,
IF_RandomGenerator * pRandGen,
FLMBYTE * pucBuf,
FLMUINT uiCount)
{
FLMUINT uiSlot;
FLMUINT uiLoop;
RCODE rc = FERR_OK;
for( uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
if( !flmGetNextHexPacketSlot( pucUsedMap, uiMapSize, pRandGen, &uiSlot))
{
rc = RC_SET( FERR_INVALID_CRC);
goto Exit;
}
pucBuf[ uiLoop] = pucPacket[ uiSlot];
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Decodes a string containing %XX sequences and does it in place.
Typically, this data comes from an HTML form.
****************************************************************************/
void fcsDecodeHttpString(
char * pszSrc)
{
char * pszDest;
pszDest = pszSrc;
while( *pszSrc)
{
if( *pszSrc == '%')
{
pszSrc++;
if( f_isHexChar( (FLMBYTE)pszSrc[ 0]) &&
f_isHexChar( (FLMBYTE)pszSrc[ 1]))
{
*pszDest = (f_getHexVal( (FLMBYTE)pszSrc[ 0]) << 4) |
f_getHexVal( (FLMBYTE)pszSrc[ 1]);
pszSrc += 2;
pszDest++;
continue;
}
}
else if( *pszSrc == '+')
{
*pszDest = ' ';
pszSrc++;
pszDest++;
continue;
}
if( pszSrc != pszDest)
{
*pszDest = *pszSrc;
}
pszSrc++;
pszDest++;
}
*pszDest = 0;
}
/****************************************************************************
Desc:
*****************************************************************************/
FCS_WIRE::FCS_WIRE( FCS_DIS * pDIStream, FCS_DOS * pDOStream)
{
m_pool.poolInit( 2048);
m_pPool = &m_pool;
m_pDIStream = pDIStream;
m_pDOStream = pDOStream;
m_pRecord = NULL;
m_pFromKey = NULL;
m_pUntilKey = NULL;
m_bSendGedcom = FALSE;
(void)resetCommon();
}
/****************************************************************************
Desc:
*****************************************************************************/
FCS_WIRE::~FCS_WIRE( void)
{
if( m_pRecord)
{
m_pRecord->Release();
m_pRecord = NULL;
}
if( m_pFromKey)
{
m_pFromKey->Release();
m_pFromKey = NULL;
}
if( m_pUntilKey)
{
m_pUntilKey->Release();
m_pUntilKey = NULL;
}
m_pool.poolFree();
}
/****************************************************************************
Desc: Resets all member variables to their default / initial values.
*****************************************************************************/
void FCS_WIRE::resetCommon( void)
{
if( m_pRecord)
{
m_pRecord->Release();
m_pRecord = NULL;
}
if( m_pFromKey)
{
m_pFromKey->Release();
m_pFromKey = NULL;
}
if( m_pUntilKey)
{
m_pUntilKey->Release();
m_pUntilKey = NULL;
}
m_uiClass = 0;
m_uiOp = 0;
m_uiRCode = 0;
m_uiDrn = 0;
m_uiTransType = FLM_READ_TRANS;
m_ui64Count = 0;
m_uiItemId = 0;
m_uiIndexId = 0;
m_puzItemName = NULL;
m_pHTD = NULL;
m_uiSessionId = FCS_INVALID_ID;
m_uiSessionCookie = 0;
m_uiContainer = FLM_DATA_CONTAINER;
m_uiTransId = FCS_INVALID_ID;
m_uiIteratorId = FCS_INVALID_ID;
m_puzFilePath = NULL;
m_puzFilePath2 = NULL;
m_puzFilePath3 = NULL;
m_pucBlock = NULL;
m_pucSerialNum = NULL;
m_uiBlockSize = 0;
m_bIncludesAsync = FALSE;
fcsInitCreateOpts( &m_CreateOpts);
m_pPool->poolReset();
m_bFlag = FALSE;
m_ui64Number1 = 0;
m_ui64Number2 = 0;
m_ui64Number3 = 0;
m_uiAddress = 0;
m_uiFlags = 0;
m_uiFlaimVersion = 0;
m_i64SignedValue = 0;
m_pCSContext = NULL;
m_pDb = NULL;
}
/****************************************************************************
Desc: Reads the class and opcode for a client request or server response.
*****************************************************************************/
RCODE FCS_WIRE::readOpcode( void)
{
FLMBYTE ucClass;
FLMBYTE ucOp;
RCODE rc = FERR_OK;
if( RC_BAD( rc = m_pDIStream->read( &ucClass, 1, NULL)))
{
goto Exit;
}
m_uiClass = ucClass;
if( RC_BAD( rc = m_pDIStream->read( &ucOp, 1, NULL)))
{
goto Exit;
}
m_uiOp = ucOp;
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads a client request or server response and sets the appropriate
member variable values.
*****************************************************************************/
RCODE FCS_WIRE::readCommon(
FLMUINT * puiTagRV,
FLMBOOL * pbEndRV)
{
FLMUINT16 ui16Tmp;
FLMUINT uiTag = 0;
RCODE rc = FERR_OK;
*pbEndRV = FALSE;
// Read the tag.
if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Tmp)))
{
goto Exit;
}
uiTag = ui16Tmp;
// Read the request / response values.
switch( (uiTag & WIRE_VALUE_TAG_MASK))
{
case WIRE_VALUE_RCODE:
{
rc = readNumber( uiTag, &m_uiRCode);
uiTag = 0;
break;
}
case WIRE_VALUE_SESSION_ID:
{
rc = readNumber( uiTag, &m_uiSessionId);
uiTag = 0;
break;
}
case WIRE_VALUE_SESSION_COOKIE:
{
rc = readNumber( uiTag, &m_uiSessionCookie);
uiTag = 0;
break;
}
case WIRE_VALUE_CONTAINER_ID:
{
rc = readNumber( uiTag, &m_uiContainer);
uiTag = 0;
break;
}
case WIRE_VALUE_COUNT:
{
rc = readNumber( uiTag, NULL, NULL, &m_ui64Count);
uiTag = 0;
break;
}
case WIRE_VALUE_DRN:
{
rc = readNumber( uiTag, &m_uiDrn);
uiTag = 0;
break;
}
case WIRE_VALUE_INDEX_ID:
{
rc = readNumber( uiTag, &m_uiIndexId);
uiTag = 0;
break;
}
case WIRE_VALUE_HTD:
{
rc = m_pDIStream->readHTD( m_pPool, 0, 0, &m_pHTD, NULL);
uiTag = 0;
break;
}
case WIRE_VALUE_RECORD:
{
FlmRecord * pRecord = m_pRecord;
if( RC_OK( rc = receiveRecord( &pRecord)))
{
if( m_pRecord != pRecord)
{
if( m_pRecord)
{
m_pRecord->Release();
}
m_pRecord = pRecord;
}
}
uiTag = 0;
break;
}
case WIRE_VALUE_FROM_KEY:
{
FlmRecord * pFromKey = m_pFromKey;
if( RC_OK( rc = receiveRecord( &pFromKey)))
{
if( m_pFromKey != pFromKey)
{
if( m_pFromKey)
{
m_pFromKey->Release();
}
m_pFromKey = pFromKey;
}
}
uiTag = 0;
break;
}
case WIRE_VALUE_UNTIL_KEY:
{
FlmRecord * pUntilKey = m_pUntilKey;
if( RC_OK( rc = receiveRecord( &pUntilKey)))
{
if( m_pUntilKey != pUntilKey)
{
if( m_pUntilKey)
{
m_pUntilKey->Release();
}
m_pUntilKey = pUntilKey;
}
}
uiTag = 0;
break;
}
case WIRE_VALUE_CREATE_OPTS:
{
rc = receiveCreateOpts();
uiTag = 0;
break;
}
case WIRE_VALUE_ITERATOR_ID:
{
rc = readNumber( uiTag, &m_uiIteratorId);
uiTag = 0;
break;
}
case WIRE_VALUE_TRANSACTION_TYPE:
{
rc = readNumber( uiTag, &m_uiTransType);
uiTag = 0;
break;
}
case WIRE_VALUE_TRANSACTION_ID:
{
rc = readNumber( uiTag, &m_uiTransId);
uiTag = 0;
break;
}
case WIRE_VALUE_ITEM_NAME:
{
rc = m_pDIStream->readUTF( m_pPool, &m_puzItemName);
uiTag = 0;
break;
}
case WIRE_VALUE_ITEM_ID:
{
rc = readNumber( uiTag, &m_uiItemId);
uiTag = 0;
break;
}
case WIRE_VALUE_BOOLEAN:
{
FLMUINT uiTmp;
if( RC_OK( rc = readNumber( uiTag, &uiTmp)))
{
m_bFlag = (FLMBOOL)((uiTmp) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE);
}
uiTag = 0;
break;
}
case WIRE_VALUE_NUMBER1:
{
rc = readNumber( uiTag, NULL, NULL, &m_ui64Number1);
uiTag = 0;
break;
}
case WIRE_VALUE_NUMBER2:
{
rc = readNumber( uiTag, NULL, NULL, &m_ui64Number2);
uiTag = 0;
break;
}
case WIRE_VALUE_NUMBER3:
{
rc = readNumber( uiTag, NULL, NULL, &m_ui64Number3);
uiTag = 0;
break;
}
case WIRE_VALUE_ADDRESS:
{
rc = readNumber( uiTag, &m_uiAddress);
uiTag = 0;
break;
}
case WIRE_VALUE_SIGNED_NUMBER:
{
rc = readNumber( uiTag, NULL, NULL, NULL, &m_i64SignedValue);
uiTag = 0;
break;
}
case WIRE_VALUE_FILE_PATH:
{
rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath);
uiTag = 0;
break;
}
case WIRE_VALUE_FILE_PATH_2:
{
rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath2);
uiTag = 0;
break;
}
case WIRE_VALUE_FILE_PATH_3:
{
rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath3);
uiTag = 0;
break;
}
case WIRE_VALUE_BLOCK:
{
rc = m_pDIStream->readLargeBinary( m_pPool,
&m_pucBlock, &m_uiBlockSize);
uiTag = 0;
break;
}
case WIRE_VALUE_SERIAL_NUM:
{
FLMUINT uiSerialLen;
if( RC_BAD( rc = m_pDIStream->readBinary( m_pPool,
&m_pucSerialNum, &uiSerialLen)))
{
goto Exit;
}
if( uiSerialLen != F_SERIAL_NUM_SIZE)
{
rc = RC_SET( FERR_CONV_DEST_OVERFLOW);
goto Exit;
}
uiTag = 0;
break;
}
case WIRE_VALUE_START_ASYNC:
{
m_bIncludesAsync = TRUE;
*pbEndRV = TRUE;
uiTag = 0;
break;
}
case WIRE_VALUE_FLAGS:
{
rc = readNumber( uiTag, &m_uiFlags);
uiTag = 0;
break;
}
case WIRE_VALUE_FLAIM_VERSION:
{
rc = readNumber( uiTag, &m_uiFlaimVersion);
uiTag = 0;
break;
}
case WIRE_VALUE_TERMINATE:
{
rc = m_pDIStream->endMessage();
*pbEndRV = TRUE;
uiTag = 0;
break;
}
default:
{
break;
}
}
Exit:
*puiTagRV = uiTag;
return( rc);
}
/****************************************************************************
Desc: Copies the internal CREATE_OPTS structure into a user-supplied location
*****************************************************************************/
void FCS_WIRE::copyCreateOpts(
CREATE_OPTS * pCreateOptsRV)
{
f_memcpy( pCreateOptsRV, &m_CreateOpts, sizeof( CREATE_OPTS));
}
/****************************************************************************
Desc: Reads a numeric value from the specified data input stream.
*****************************************************************************/
RCODE FCS_WIRE::readNumber(
FLMUINT uiTag,
FLMUINT * puiNumber,
FLMINT * piNumber,
FLMUINT64 * pui64Number,
FLMINT64 * pi64Number)
{
RCODE rc = FERR_OK;
flmAssert( !(puiNumber && piNumber));
// Read the number of bytes specified by the
// value's tag.
switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >>
WIRE_VALUE_TYPE_START_BIT))
{
case WIRE_VALUE_TYPE_GEN_0:
{
if( puiNumber)
{
*puiNumber = 0;
}
else if( piNumber)
{
*piNumber = 0;
}
else if( pui64Number)
{
*pui64Number = 0;
}
else if( pi64Number)
{
*pi64Number = 0;
}
break;
}
case WIRE_VALUE_TYPE_GEN_1:
{
FLMBYTE ucValue;
if( RC_BAD( rc = m_pDIStream->read( &ucValue, 1, NULL)))
{
goto Exit;
}
if( puiNumber)
{
*puiNumber = (FLMUINT)ucValue;
}
else if( piNumber)
{
*piNumber = (FLMINT)*((FLMINT8 *)&ucValue);
}
else if( pui64Number)
{
*pui64Number = (FLMUINT64)ucValue;
}
else if( pi64Number)
{
*pi64Number = (FLMINT64)*((FLMINT8 *)&ucValue);
}
break;
}
case WIRE_VALUE_TYPE_GEN_2:
{
if( puiNumber || pui64Number)
{
FLMUINT16 ui16Value;
if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Value)))
{
goto Exit;
}
if( puiNumber)
{
*puiNumber = (FLMUINT)ui16Value;
}
else if( pui64Number)
{
*pui64Number = (FLMUINT64)ui16Value;
}
}
else if( piNumber || pi64Number)
{
FLMINT16 i16Value;
if( RC_BAD( rc = m_pDIStream->readShort( &i16Value)))
{
goto Exit;
}
if( piNumber)
{
*piNumber = (FLMINT)i16Value;
}
else if( pi64Number)
{
*pi64Number = (FLMINT)i16Value;
}
}
break;
}
case WIRE_VALUE_TYPE_GEN_4:
{
if( puiNumber || pui64Number)
{
FLMUINT32 ui32Value;
if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Value)))
{
goto Exit;
}
if( puiNumber)
{
*puiNumber = (FLMUINT)ui32Value;
}
else if( pui64Number)
{
*pui64Number = (FLMUINT64)ui32Value;
}
}
else if( piNumber || pi64Number)
{
FLMINT32 i32Value;
if( RC_BAD( rc = m_pDIStream->readInt( &i32Value)))
{
goto Exit;
}
if( piNumber)
{
*piNumber = (FLMINT)i32Value;
}
else if( pi64Number)
{
*pi64Number = (FLMINT64)i32Value;
}
}
break;
}
case WIRE_VALUE_TYPE_GEN_8:
{
if( puiNumber || piNumber)
{
rc = RC_SET( FERR_CONV_NUM_OVERFLOW);
}
else
{
if( pui64Number)
{
if( RC_BAD( rc = m_pDIStream->readUInt64( pui64Number)))
{
goto Exit;
}
}
else if( pi64Number)
{
if( RC_BAD( rc = m_pDIStream->readInt64( pi64Number)))
{
goto Exit;
}
}
else
{
flmAssert( 0);
rc = RC_SET( FERR_INVALID_PARM);
goto Exit;
}
}
break;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes an unsigned number to the specified data output stream.
*****************************************************************************/
RCODE FCS_WIRE::writeUnsignedNumber(
FLMUINT uiTag,
FLMUINT64 ui64Number)
{
RCODE rc = FERR_OK;
if( ui64Number <= (FLMUINT64)0x000000FF)
{
uiTag |= WIRE_VALUE_TYPE_GEN_1 <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeByte( (FLMBYTE)ui64Number)))
{
goto Exit;
}
}
else if( ui64Number <= (FLMUINT64)0x0000FFFF)
{
uiTag |= WIRE_VALUE_TYPE_GEN_2 <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)ui64Number)))
{
goto Exit;
}
}
else if( ui64Number <= (FLMUINT64)0xFFFFFFFF)
{
uiTag |= WIRE_VALUE_TYPE_GEN_4 <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeUInt32( (FLMUINT32)ui64Number)))
{
goto Exit;
}
}
else
{
uiTag |= WIRE_VALUE_TYPE_GEN_8 <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeUInt64( ui64Number)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Writes a signed number to the specified data output stream.
*****************************************************************************/
RCODE FCS_WIRE::writeSignedNumber(
FLMUINT uiTag,
FLMINT64 i64Number)
{
RCODE rc = FERR_OK;
if( RC_BAD( rc = writeUnsignedNumber( uiTag, (FLMUINT64)i64Number)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Skips a parameter or return value in the data stream
*****************************************************************************/
RCODE FCS_WIRE::skipValue(
FLMUINT uiTag)
{
RCODE rc = FERR_OK;
switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >>
WIRE_VALUE_TYPE_START_BIT))
{
case WIRE_VALUE_TYPE_GEN_0:
{
break;
}
case WIRE_VALUE_TYPE_GEN_1:
{
if( RC_BAD( rc = m_pDIStream->skip( 1)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_GEN_2:
{
if( RC_BAD( rc = m_pDIStream->skip( 2)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_GEN_4:
{
if( RC_BAD( rc = m_pDIStream->skip( 4)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_GEN_8:
{
if( RC_BAD( rc = m_pDIStream->skip( 8)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_BINARY:
{
if( RC_BAD( rc = m_pDIStream->readBinary( NULL, NULL, NULL)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_LARGE_BINARY:
{
if( RC_BAD( rc = m_pDIStream->readLargeBinary( NULL, NULL, NULL)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_HTD:
{
if( RC_BAD( rc = m_pDIStream->readHTD( NULL, 0, 0, NULL, NULL)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_TYPE_RECORD:
{
if( RC_BAD( rc = receiveRecord( NULL)))
{
goto Exit;
}
}
case WIRE_VALUE_TYPE_UTF:
{
if( RC_BAD( rc = m_pDIStream->readUTF( NULL, NULL)))
{
goto Exit;
}
break;
}
default:
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends an opcode to the client
*****************************************************************************/
RCODE FCS_WIRE::sendOpcode(
FLMUINT uiClass,
FLMUINT uiOp)
{
FLMBYTE ucClass = (FLMBYTE)uiClass;
FLMBYTE ucOp = (FLMBYTE)uiOp;
RCODE rc = FERR_OK;
if( RC_BAD( rc = m_pDOStream->write( &ucClass, 1)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->write( &ucOp, 1)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendTerminate( void)
{
RCODE rc = FERR_OK;
if( RC_BAD( rc = m_pDOStream->writeUShort( 0)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->endMessage()))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendNumber(
FLMUINT uiTag,
FLMUINT64 ui64Value,
FLMINT64 i64Value)
{
RCODE rc = FERR_OK;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_AREA_ID:
case WIRE_VALUE_OP_SEQ_NUM:
case WIRE_VALUE_FLAGS:
case WIRE_VALUE_CLIENT_VERSION:
case WIRE_VALUE_SESSION_ID:
case WIRE_VALUE_SESSION_COOKIE:
case WIRE_VALUE_CONTAINER_ID:
case WIRE_VALUE_INDEX_ID:
case WIRE_VALUE_ITEM_ID:
case WIRE_VALUE_TRANSACTION_ID:
case WIRE_VALUE_TRANSACTION_TYPE:
case WIRE_VALUE_DRN:
case WIRE_VALUE_COUNT:
case WIRE_VALUE_AUTOTRANS:
case WIRE_VALUE_MAX_LOCK_WAIT:
case WIRE_VALUE_RECORD_COUNT:
case WIRE_VALUE_BOOLEAN:
case WIRE_VALUE_ITERATOR_ID:
case WIRE_VALUE_SHARED_DICT_ID:
case WIRE_VALUE_PARENT_DICT_ID:
case WIRE_VALUE_TYPE:
case WIRE_VALUE_NUMBER1:
case WIRE_VALUE_NUMBER2:
case WIRE_VALUE_NUMBER3:
case WIRE_VALUE_ADDRESS:
case WIRE_VALUE_FLAIM_VERSION:
{
if( RC_BAD( rc = writeUnsignedNumber( uiTag, ui64Value)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_SIGNED_NUMBER:
{
if( RC_BAD( rc = writeSignedNumber( uiTag, i64Value)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendBinary(
FLMUINT uiTag,
FLMBYTE * pData,
FLMUINT uiLength)
{
RCODE rc = FERR_OK;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_PASSWORD:
case WIRE_VALUE_SERIAL_NUM:
{
uiTag |= WIRE_VALUE_TYPE_BINARY <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeBinary( pData, uiLength)))
{
goto Exit;
}
break;
}
case WIRE_VALUE_BLOCK:
{
uiTag |= WIRE_VALUE_TYPE_LARGE_BINARY <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeLargeBinary( pData, uiLength)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a record
*****************************************************************************/
RCODE FCS_WIRE::sendRecord(
FLMUINT uiTag,
FlmRecord * pRecord)
{
RCODE rc = FERR_OK;
#define RECORD_OUTPUT_BUFFER_SIZE 64
FLMBYTE pucBuffer[ RECORD_OUTPUT_BUFFER_SIZE];
FLMBYTE * pucBufPos;
FLMBYTE ucDescriptor;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_RECORD:
case WIRE_VALUE_FROM_KEY:
case WIRE_VALUE_UNTIL_KEY:
{
uiTag |= WIRE_VALUE_TYPE_RECORD <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
// The format of a record is (X = 1 bit):
//
// X X XXXXXX 0-64 bytes HTD
// RESERVED HTD_FOLLOWS ID_LENGTH ID_VALUE TREE (optional)
//
// This sequence can repeat, terminating with a 0 byte.
ucDescriptor = 0;
pucBufPos = pucBuffer;
ucDescriptor |= (FLMBYTE)RECORD_HAS_HTD_FLAG;
// Output the descriptor.
ucDescriptor |= (FLMBYTE)RECORD_ID_SIZE;
*pucBufPos = ucDescriptor;
pucBufPos++;
// Output the ID. Current format of a record ID is:
//
// 4-byte container ID, 4-byte DRN
f_UINT32ToBigEndian( (FLMUINT32)pRecord->getContainerID(), pucBufPos);
pucBufPos += 4;
f_UINT32ToBigEndian( (FLMUINT32)pRecord->getID(), pucBufPos);
pucBufPos += 4;
// Send the descriptor and record source.
if( RC_BAD( rc = m_pDOStream->write( pucBuffer,
pucBufPos - pucBuffer)))
{
goto Exit;
}
// Send the record.
if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord,
FALSE, m_bSendGedcom)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendDrnList(
FLMUINT uiTag,
FLMUINT * puiList)
{
FLMUINT uiItemCount;
FLMUINT uiLoop;
FLMUINT uiBufSize = 0;
FLMBYTE * pucItemBuf = NULL;
FLMBYTE * pucItemPos;
RCODE rc = FERR_OK;
if( !puiList)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_DRN_LIST:
{
uiTag |= WIRE_VALUE_TYPE_BINARY <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
// Count the entries in the list. For now, support only a list of
// 2048 elements.
for( uiItemCount = 0; uiItemCount < 2048; uiItemCount++)
{
if( !puiList[ uiItemCount])
{
break;
}
}
// Allocate a buffer for the list.
uiBufSize = (FLMUINT)(((FLMUINT)sizeof( FLMUINT) * uiItemCount) + (FLMUINT)4);
if( RC_BAD( rc = f_calloc( uiBufSize, &pucItemBuf)))
{
goto Exit;
}
pucItemPos = pucItemBuf;
// Set the item count.
UD2FBA( (FLMUINT32)uiItemCount, pucItemPos);
pucItemPos += 4;
// Put the items into the buffer.
for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++)
{
UD2FBA( (FLMUINT32)puiList[ uiLoop], pucItemPos);
pucItemPos += 4;
}
// Send the list.
if( RC_BAD( rc = m_pDOStream->writeBinary(
pucItemBuf, uiBufSize)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
if( pucItemBuf)
{
f_free( (void **)&pucItemBuf);
}
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendString(
FLMUINT uiTag,
FLMUNICODE * puzString)
{
RCODE rc = FERR_OK;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_FILE_NAME:
case WIRE_VALUE_FILE_PATH:
case WIRE_VALUE_FILE_PATH_2:
case WIRE_VALUE_FILE_PATH_3:
case WIRE_VALUE_DICT_FILE_PATH:
case WIRE_VALUE_ITEM_NAME:
case WIRE_VALUE_DICT_BUFFER:
{
uiTag |= WIRE_VALUE_TYPE_UTF <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeUTF( puzString)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendHTD(
FLMUINT uiTag,
NODE * pHTD)
{
RCODE rc = FERR_OK;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_HTD:
case WIRE_VALUE_ITERATOR_SELECT:
case WIRE_VALUE_ITERATOR_FROM:
case WIRE_VALUE_ITERATOR_WHERE:
case WIRE_VALUE_ITERATOR_CONFIG:
{
uiTag |= WIRE_VALUE_TYPE_HTD <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeHTD( pHTD, NULL, TRUE, m_bSendGedcom)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendHTD(
FLMUINT uiTag,
FlmRecord * pRecord)
{
RCODE rc = FERR_OK;
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_HTD:
{
uiTag |= WIRE_VALUE_TYPE_HTD <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord,
FALSE, m_bSendGedcom)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Copies the current HTD tree to the application's pool
*****************************************************************************/
RCODE FCS_WIRE::getHTD(
F_Pool * pPool,
NODE ** ppTreeRV)
{
RCODE rc = FERR_OK;
if( !m_pHTD)
{
*ppTreeRV = NULL;
goto Exit;
}
if( (*ppTreeRV = GedCopy( pPool, GED_FOREST, m_pHTD)) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendCreateOpts(
FLMUINT uiTag,
CREATE_OPTS * pCreateOpts)
{
NODE * pRootNd = NULL;
void * pvMark = m_pPool->poolMark();
RCODE rc = FERR_OK;
FLMUINT uiTmp;
// If no create options, goto exit.
if( !pCreateOpts)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_CREATE_OPTS:
{
uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
// Build the root node of the CreateOpts tree.
if( (pRootNd = GedNodeMake( m_pPool, FCS_COPT_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
// Add fields to the tree.
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_BLOCK_SIZE, (void *)&pCreateOpts->uiBlockSize,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_MIN_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMinRflFileSize,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_MAX_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMaxRflFileSize,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
uiTmp = pCreateOpts->bKeepRflFiles ? 1 : 0;
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_KEEP_RFL_FILES, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
uiTmp = pCreateOpts->bLogAbortedTransToRfl ? 1 : 0;
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_LOG_ABORTED_TRANS, (void *)&uiTmp,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_DEFAULT_LANG, (void *)&pCreateOpts->uiDefaultLanguage,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_VERSION, (void *)&pCreateOpts->uiVersionNum,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_APP_MAJOR_VER, (void *)&pCreateOpts->uiAppMajorVer,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
if( RC_BAD( rc = gedAddField( m_pPool, pRootNd,
FCS_COPT_APP_MINOR_VER, (void *)&pCreateOpts->uiAppMinorVer,
0, FLM_NUMBER_TYPE)))
{
goto Exit;
}
// Send the tree.
if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd, NULL,
TRUE, m_bSendGedcom)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
m_pPool->poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc: Sends a value to the client
*****************************************************************************/
RCODE FCS_WIRE::sendNameTable(
FLMUINT uiTag,
F_NameTable * pNameTable)
{
void * pvMark = m_pPool->poolMark();
NODE * pRootNd;
NODE * pNd;
NODE * pItemIdNd;
FLMUINT uiMaxNameChars = 1024;
FLMUNICODE * puzItemName = NULL;
FLMUINT uiId;
FLMUINT uiType;
FLMUINT uiSubType;
FLMUINT uiNextPos;
RCODE rc = FERR_OK;
// If the name table pointer is invalid, goto exit.
if( !pNameTable)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
// Allocate a temporary name buffer
if( RC_BAD( rc = m_pPool->poolAlloc( uiMaxNameChars * sizeof( FLMUNICODE),
(void **)&puzItemName)))
{
goto Exit;
}
// Send the parameter tag and value.
switch( uiTag)
{
case WIRE_VALUE_NAME_TABLE:
{
uiTag |= WIRE_VALUE_TYPE_HTD <<
WIRE_VALUE_TYPE_START_BIT;
if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag)))
{
goto Exit;
}
// Build the root node of the name table tree.
if( (pRootNd = GedNodeMake( m_pPool,
FCS_NAME_TABLE_CONTEXT, &rc)) == NULL)
{
goto Exit;
}
uiNextPos = 0;
while( pNameTable->getNextTagNumOrder( &uiNextPos, puzItemName,
NULL, uiMaxNameChars * sizeof( FLMUNICODE),
&uiId, &uiType, &uiSubType))
{
if( (pItemIdNd = GedNodeMake( m_pPool,
FCS_NAME_TABLE_ITEM_ID, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = GedPutUINT( m_pPool, pItemIdNd, uiId)))
{
goto Exit;
}
if( (pNd = GedNodeMake( m_pPool,
FCS_NAME_TABLE_ITEM_NAME, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = GedPutUNICODE( m_pPool, pNd, puzItemName)))
{
goto Exit;
}
GedChildGraft( pItemIdNd, pNd, GED_LAST);
if( (pNd = GedNodeMake( m_pPool,
FCS_NAME_TABLE_ITEM_TYPE, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiType)))
{
goto Exit;
}
GedChildGraft( pItemIdNd, pNd, GED_LAST);
if( (pNd = GedNodeMake( m_pPool,
FCS_NAME_TABLE_ITEM_SUBTYPE, &rc)) == NULL)
{
goto Exit;
}
if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiSubType)))
{
goto Exit;
}
GedChildGraft( pItemIdNd, pNd, GED_LAST);
// Graft the item into the tree
GedChildGraft( pRootNd, pItemIdNd, GED_LAST);
// Release CPU to prevent CPU hog
f_yieldCPU();
}
// Send the tree.
if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd,
NULL, TRUE, m_bSendGedcom)))
{
goto Exit;
}
break;
}
default:
{
#ifdef FLM_DEBUG
flmAssert( 0);
#else
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
#endif
}
}
Exit:
m_pPool->poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc: Receives a record
*****************************************************************************/
RCODE FCS_WIRE::receiveRecord(
FlmRecord ** ppRecord)
{
FLMBYTE ucDescriptor = 0;
FLMUINT uiIdLen = 0;
FLMUINT32 ui32Container;
FLMUINT32 ui32Drn;
void * pvMark = m_pPool->poolMark();
FLMBOOL bHasId = FALSE;
RCODE rc = FERR_OK;
// Read the record.
if( RC_BAD( rc = m_pDIStream->read( &ucDescriptor, 1, NULL)))
{
goto Exit;
}
uiIdLen = (FLMUINT)(ucDescriptor & RECORD_ID_SIZE_MASK);
if( uiIdLen != RECORD_ID_SIZE)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
else if( uiIdLen)
{
bHasId = TRUE;
}
// Read the record ID.
if( bHasId)
{
if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Container)))
{
goto Exit;
}
if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Drn)))
{
goto Exit;
}
}
// Read the record.
if( (ucDescriptor & RECORD_HAS_HTD_FLAG))
{
if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool,
ui32Container, ui32Drn, NULL, ppRecord)))
{
goto Exit;
}
}
Exit:
if( RC_BAD( rc) && ppRecord && *ppRecord)
{
(*ppRecord)->Release();
*ppRecord = NULL;
}
m_pPool->poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc: Receives a CREATE_OPTS structure as an HTD tree.
*****************************************************************************/
RCODE FCS_WIRE::receiveCreateOpts( void)
{
NODE * pRootNd;
NODE * pTmpNd;
void * pPoolMark;
FLMUINT fieldPath[ 8];
FLMUINT uiTmp;
RCODE rc = FERR_OK;
pPoolMark = m_pPool->poolMark();
// Initialize the CREATE_OPTS structure to its default values.
fcsInitCreateOpts( &m_CreateOpts);
// Receive the tree.
if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool,
0, 0, &pRootNd, NULL)))
{
goto Exit;
}
// Parse the tree and extract the values.
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_BLOCK_SIZE;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiBlockSize);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_MIN_RFL_FILE_SIZE;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMinRflFileSize);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_MAX_RFL_FILE_SIZE;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMaxRflFileSize);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_KEEP_RFL_FILES;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
m_CreateOpts.bKeepRflFiles = (FLMBOOL)((uiTmp)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_LOG_ABORTED_TRANS;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &uiTmp);
m_CreateOpts.bLogAbortedTransToRfl = (FLMBOOL)((uiTmp)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_DEFAULT_LANG;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiDefaultLanguage);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_VERSION;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiVersionNum);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_APP_MAJOR_VER;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMajorVer);
}
fieldPath[ 0] = FCS_COPT_CONTEXT;
fieldPath[ 1] = FCS_COPT_APP_MINOR_VER;
fieldPath[ 2] = 0;
if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL)
{
(void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMinorVer);
}
Exit:
m_pPool->poolReset( pPoolMark);
return( rc);
}
/****************************************************************************
Desc: Receives a name table.
*****************************************************************************/
RCODE FCS_WIRE::receiveNameTable(
F_NameTable ** ppNameTable)
{
NODE * pRootNd;
NODE * pItemIdNd;
NODE * pNd = NULL;
void * pvMark = m_pPool->poolMark();
FLMUINT uiMaxNameChars = 1024;
FLMUNICODE * puzItemName;
FLMUINT uiItemId;
FLMUINT uiItemType;
FLMUINT uiItemSubType;
F_NameTable * pNameTable = NULL;
FLMBOOL bCreatedTable = FALSE;
RCODE rc = FERR_OK;
// Allocate a temporary name buffer
if( RC_BAD( rc = m_pPool->poolAlloc( uiMaxNameChars * sizeof( FLMUNICODE),
(void **)&puzItemName)))
{
goto Exit;
}
// Initialize the name table.
if( (pNameTable = *ppNameTable) == NULL)
{
if( (pNameTable = f_new F_NameTable) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
bCreatedTable = TRUE;
}
else
{
pNameTable->clearTable();
}
// Receive the tree.
if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool,
0, 0, &pRootNd, NULL)))
{
goto Exit;
}
// Parse the tree and extract the values.
pItemIdNd = GedChild( pRootNd);
while( pItemIdNd)
{
if( GedTagNum( pItemIdNd) == FCS_NAME_TABLE_ITEM_ID)
{
if( RC_BAD( rc = GedGetUINT( pItemIdNd, &uiItemId)))
{
goto Exit;
}
uiItemType = 0;
uiItemSubType = 0;
pNd = GedChild( pItemIdNd);
while( pNd)
{
switch( GedTagNum( pNd))
{
case FCS_NAME_TABLE_ITEM_NAME:
{
FLMUINT uiStrLen = uiMaxNameChars * sizeof( FLMUNICODE);
if( RC_BAD( rc = GedGetUNICODE( pNd, puzItemName,
&uiStrLen)))
{
goto Exit;
}
break;
}
case FCS_NAME_TABLE_ITEM_TYPE:
{
if( RC_BAD( rc = GedGetUINT( pNd, &uiItemType)))
{
goto Exit;
}
break;
}
case FCS_NAME_TABLE_ITEM_SUBTYPE:
{
if( RC_BAD( rc = GedGetUINT( pNd, &uiItemSubType)))
{
goto Exit;
}
break;
}
}
pNd = GedSibNext( pNd);
}
if( puzItemName[ 0])
{
if( RC_BAD( rc = pNameTable->addTag( puzItemName, NULL,
uiItemId, uiItemType, uiItemSubType, FALSE)))
{
goto Exit;
}
}
}
pItemIdNd = GedSibNext( pItemIdNd);
// Release CPU to prevent CPU hog
f_yieldCPU();
}
pNameTable->sortTags();
*ppNameTable = pNameTable;
pNameTable = NULL;
Exit:
if( pNameTable && bCreatedTable)
{
pNameTable->Release();
}
m_pPool->poolReset( pvMark);
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
FCL_WIRE::FCL_WIRE( CS_CONTEXT * pCSContext, FDB * pDb) :
FCS_WIRE( pCSContext != NULL ? pCSContext->pIDataStream : NULL,
pCSContext != NULL ? pCSContext->pODataStream : NULL)
{
m_pCSContext = pCSContext;
m_pDb = pDb;
if( m_pCSContext)
{
m_bSendGedcom = m_pCSContext->bGedcomSupport;
}
}
/****************************************************************************
Desc: Sets the CS CONTEXT in FCL_WIRE and the I/O streams in FCS_WIRE
*****************************************************************************/
void FCL_WIRE::setContext(
CS_CONTEXT * pCSContext)
{
m_pCSContext = pCSContext;
m_bSendGedcom = pCSContext->bGedcomSupport;
FCS_WIRE::setDIStream( pCSContext->pIDataStream);
FCS_WIRE::setDOStream( pCSContext->pODataStream);
}
/****************************************************************************
Desc: Send a client/server opcode with session id, and optionally the
database id
****************************************************************************/
RCODE FCL_WIRE::sendOp(
FLMUINT uiClass,
FLMUINT uiOp)
{
RCODE rc = FERR_OK;
if (!m_pCSContext->bConnectionGood)
{
rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
goto Exit;
}
// Send the class and opcode
if (RC_BAD( rc = sendOpcode( (FLMBYTE)uiClass, (FLMBYTE)uiOp)))
{
goto Transmission_Error;
}
// Send session ID
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_SESSION_ID, m_pCSContext->uiSessionId)))
{
goto Transmission_Error;
}
// Send session cookie
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_SESSION_COOKIE, m_pCSContext->uiSessionCookie)))
{
goto Transmission_Error;
}
// Send operation sequence number
m_pCSContext->uiOpSeqNum++;
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_OP_SEQ_NUM, m_pCSContext->uiOpSeqNum)))
{
goto Transmission_Error;
}
Exit:
return( rc);
Transmission_Error:
m_pCSContext->bConnectionGood = FALSE;
goto Exit;
}
/****************************************************************************
Desc: This routine instructs the server to start or end a transaction
****************************************************************************/
RCODE FCL_WIRE::doTransOp(
FLMUINT uiOp,
FLMUINT uiTransType,
FLMUINT uiFlags,
FLMUINT uiMaxLockWait,
FLMBYTE * pszHeader,
FLMBOOL bForceCheckpoint)
{
FLMUINT uiTransFlags = 0;
RCODE rc = FERR_OK;
// Send request to server
if( RC_BAD( rc = sendOp( FCS_OPCLASS_TRANS, uiOp)))
{
goto Exit;
}
if( uiOp == FCS_OP_TRANSACTION_BEGIN)
{
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_TRANSACTION_TYPE, uiTransType)))
{
goto Transmission_Error;
}
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_MAX_LOCK_WAIT, uiMaxLockWait)))
{
goto Transmission_Error;
}
if( pszHeader)
{
uiTransFlags |= FCS_TRANS_FLAG_GET_HEADER;
}
if( uiFlags & FLM_DONT_KILL_TRANS)
{
uiTransFlags |= FCS_TRANS_FLAG_DONT_KILL;
}
if( uiFlags & FLM_DONT_POISON_CACHE)
{
uiTransFlags |= FCS_TRANS_FLAG_DONT_POISON;
}
}
else if( uiOp == FCS_OP_TRANSACTION_COMMIT_EX)
{
if( pszHeader)
{
if( RC_BAD( rc = sendBinary(
WIRE_VALUE_BLOCK, pszHeader, F_TRANS_HEADER_SIZE)))
{
goto Exit;
}
}
if( bForceCheckpoint)
{
uiTransFlags |= FCS_TRANS_FORCE_CHECKPOINT;
}
}
if( uiTransFlags)
{
if (RC_BAD( rc = sendNumber(
WIRE_VALUE_FLAGS, uiTransFlags)))
{
goto Transmission_Error;
}
}
if( RC_BAD( rc = sendTerminate()))
{
goto Transmission_Error;
}
// Read the response
if( RC_BAD( rc = read()))
{
goto Transmission_Error;
}
if (RC_BAD( rc = getRCode()))
{
goto Exit;
}
if( pszHeader)
{
if( getBlockSize())
{
f_memcpy( pszHeader, getBlock(), getBlockSize());
}
else
{
f_memset( pszHeader, 0, 2048);
}
}
if (!m_pDb)
{
m_pCSContext->bTransActive = (FLMBOOL)((uiOp == FCS_OP_TRANSACTION_BEGIN)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE);
}
Exit:
return( rc);
Transmission_Error:
m_pCSContext->bConnectionGood = FALSE;
goto Exit;
}
/****************************************************************************
Desc: Reads a server response for the client.
*****************************************************************************/
RCODE FCL_WIRE::read( void)
{
FLMUINT uiTag;
FLMUINT uiCount = 0;
FLMBOOL bDone = FALSE;
RCODE rc = FERR_OK;
// Read the opcode.
if( RC_BAD( rc = readOpcode()))
{
goto Exit;
}
// Read the request / response values.
for( ;;)
{
if (RC_BAD( rc = readCommon( &uiTag, &bDone)))
{
if( rc == FERR_EOF_HIT && !uiCount)
{
rc = FERR_OK;
}
goto Exit;
}
if( bDone)
{
goto Exit;
}
// uiTag will be non-zero if readCommon did not understand it.
uiCount++;
if( uiTag)
{
switch( (uiTag & WIRE_VALUE_TAG_MASK))
{
case WIRE_VALUE_NAME_TABLE:
{
if( RC_BAD( rc = receiveNameTable( &m_pNameTable)))
{
goto Exit;
}
break;
}
default:
{
if( RC_BAD( rc = skipValue( uiTag)))
{
goto Exit;
}
break;
}
}
}
}
Exit:
if( rc == FERR_EOF_HIT)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
return( rc);
}