//------------------------------------------------------------------------- // Desc: FLAIM C/S client interface // Tabs: 3 // // Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com // // $Id: fcs_bios.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ //------------------------------------------------------------------------- #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); }