672 lines
19 KiB
C++
672 lines
19 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
|
//
|
|
// File: RCSTRMIT.HXX
|
|
//
|
|
// Contents: Persistent Recoverable Stream Iterators for fixed
|
|
// size records.
|
|
//
|
|
// Classes: CRcovStrmReadIter
|
|
// CRcovStrmWriteIter
|
|
// CRcovStrmAppendIter
|
|
//
|
|
// History: 25-Jan-94 SrikantS Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include <rcstxact.hxx>
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CRcovStrmIter
|
|
//
|
|
// Purpose: Iterator for the recoverable stream class assuming fixed
|
|
// size records are stored in the stream.
|
|
//
|
|
// History: 1-25-94 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CRcovStrmIter
|
|
{
|
|
|
|
public:
|
|
|
|
inline CRcovStrmIter( CRcovStrmTrans & trans , USHORT cbRec );
|
|
|
|
inline BOOL GetRec( void *pvRec, ULONG iRec );
|
|
inline void GetRec( void *pvRec );
|
|
inline ULONG GetVariableRecSize();
|
|
inline void GetVariableRecData( void * pvRec, ULONG cbRec );
|
|
|
|
BOOL AtEnd() const { return _trans.AtEnd(); }
|
|
|
|
inline void Advance();
|
|
inline void Seek( ULONG iRec );
|
|
|
|
ULONG UserDataSize( ULONG cRec ) { return cRec * (_cbRec + _CHECKSUM_SIZE); }
|
|
ULONG UserRecordCount( ULONG cbUserData ) { return cbUserData / (_cbRec + _CHECKSUM_SIZE); }
|
|
|
|
static unsigned SizeofChecksum() { return _CHECKSUM_SIZE; }
|
|
|
|
protected:
|
|
|
|
enum { _CHECKSUM_SIZE = sizeof(ULONG) };
|
|
|
|
inline ULONG CheckSum( void const * pvRec ) const;
|
|
inline ULONG CheckSum( void const * pvRec, unsigned cbRec ) const;
|
|
|
|
CRcovStrmTrans & _trans; // Transaction context
|
|
const USHORT _cbRec; // Size of user record, sans checksum
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmIter::CRcovStrmIter, public
|
|
//
|
|
// Synopsis: Constructor. Just squirrels away member variables.
|
|
//
|
|
// Arguments: [trans] -- Transaction context to iterate
|
|
// [cbRec] -- Size of 'records' to be written.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline CRcovStrmIter::CRcovStrmIter( CRcovStrmTrans & trans , USHORT cbRec )
|
|
: _trans( trans ),
|
|
_cbRec(cbRec)
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmIter::Advance, public
|
|
//
|
|
// Synopsis: Moves to next record
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmIter::Advance()
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
_trans.Advance( _cbRec + _CHECKSUM_SIZE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmIter::Seek, public
|
|
//
|
|
// Synopsis: Moves to specified record
|
|
//
|
|
// Arguments: [iRec] -- Record to position to.
|
|
//
|
|
// History: 27-May-1998 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmIter::Seek( ULONG iRec )
|
|
{
|
|
_trans.Seek( iRec * (_cbRec + _CHECKSUM_SIZE) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmIter::CheckSum, protected
|
|
//
|
|
// Synopsis: Computes checksum for record
|
|
//
|
|
// Arguments: [pvRec] -- Record to examine
|
|
//
|
|
// Returns: Checksum
|
|
//
|
|
// History: 27-May-1998 KyleP Created
|
|
//
|
|
// Notes: Checksum is never 0. This is to avoid a common failed write
|
|
// scenario where zeros are written (or nothing is ever written)
|
|
// to a persistent data structure.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline ULONG CRcovStrmIter::CheckSum( void const * pvRec ) const
|
|
{
|
|
return CheckSum( pvRec, _cbRec );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmIter::CheckSum, protected
|
|
//
|
|
// Synopsis: Computes checksum for variable size records
|
|
//
|
|
// Arguments: [pvRec] -- Record to examine
|
|
// [cbRec] -- Size of record
|
|
//
|
|
// Returns: Checksum
|
|
//
|
|
// History: 1-Jun-1998 VikasMan Created
|
|
//
|
|
// Notes: Checksum is never 0. This is to avoid a common failed write
|
|
// scenario where zeros are written (or nothing is ever written)
|
|
// to a persistent data structure.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline ULONG CRcovStrmIter::CheckSum( void const * pvRec, unsigned cbRec ) const
|
|
{
|
|
BYTE * pb = (BYTE *)pvRec;
|
|
ULONG ulCheckSum = 0;
|
|
|
|
//
|
|
// First, the DWORD granular portion
|
|
//
|
|
unsigned cbEnd = cbRec - _CHECKSUM_SIZE;
|
|
for ( unsigned i = 0; i <= cbEnd; i += _CHECKSUM_SIZE )
|
|
{
|
|
ulCheckSum += *(ULONG UNALIGNED *)pb;
|
|
pb += _CHECKSUM_SIZE;
|
|
}
|
|
|
|
//
|
|
// Then whatever is left.
|
|
//
|
|
|
|
ULONG ul = 0;
|
|
for ( ; i < cbRec; i++ )
|
|
{
|
|
ul = (ul << 8) + *pb;
|
|
pb++;
|
|
}
|
|
ulCheckSum += ul;
|
|
|
|
//
|
|
// Make sure the checksum is never zero. Just to avoid an obvious case
|
|
// of error where a whole section has been zero-ed (including checksum).
|
|
//
|
|
|
|
if ( 0 == ulCheckSum )
|
|
ulCheckSum = 1;
|
|
|
|
return ulCheckSum;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CRcovStrmIter::GetRec, public
|
|
//
|
|
// Synopsis: Gets the specified record.
|
|
//
|
|
// Effects: Positions the current pointer after the current read.
|
|
//
|
|
// Arguments: [pvRec] -- Buffer to read the contents into.
|
|
// [iRec] -- Number of the record, starting at 0.
|
|
//
|
|
// Returns: TRUE if a record was successfully read. FALSE if iRec
|
|
// is beyond the end of stream.
|
|
//
|
|
// History: 2-10-94 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline BOOL CRcovStrmIter::GetRec( void * pvRec , ULONG iRec )
|
|
{
|
|
if ( !_trans.Seek(iRec * (_cbRec + _CHECKSUM_SIZE) ) || AtEnd() ) {
|
|
return FALSE;
|
|
}
|
|
|
|
ULONG cbRead = _trans.Read( pvRec, _cbRec );
|
|
Win4Assert( cbRead == _cbRec );
|
|
|
|
ULONG ulCheckSum;
|
|
|
|
if ( _CHECKSUM_SIZE != _trans.Read( &ulCheckSum, sizeof(ulCheckSum) ) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error reading checksum for record %u (cbRec = %u).\n",
|
|
iRec, _cbRec ));
|
|
Win4Assert( !"Bad checksum" );
|
|
THROW( CException(CI_CORRUPT_CATALOG) );
|
|
}
|
|
|
|
if ( ulCheckSum != CheckSum( pvRec ) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"Incorrect checksum 0x%x (should be 0x%x) for record %u (cbRec = %u). pvRec = 0x%x\n",
|
|
CheckSum( pvRec ), ulCheckSum, iRec, _cbRec, pvRec ));
|
|
Win4Assert( !"Bad checksum" );
|
|
|
|
THROW( CException(CI_CORRUPT_CATALOG) );
|
|
}
|
|
|
|
return cbRead == _cbRec;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CRcovStrmIter::GetRec, public
|
|
//
|
|
// Synopsis: Gets the current record.
|
|
//
|
|
// Effects: Positions the current pointer after the current read.
|
|
//
|
|
// Arguments: [pvRec] -- Buffer to read the contents into.
|
|
//
|
|
// History: 27-May-1998 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmIter::GetRec( void *pvRec )
|
|
{
|
|
GetVariableRecData( pvRec, _cbRec );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CRcovStrmIter::GetVariableRecSize, public
|
|
//
|
|
// Synopsis: Gets the size of the current variable record.
|
|
//
|
|
// Effects: Positions the current pointer after the current read.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: The size in bytes of the records
|
|
//
|
|
// History: 1-Jun-1998 VikasMan Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline ULONG CRcovStrmIter::GetVariableRecSize()
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
|
|
ULONG cbRec;
|
|
ULONG cbRead;
|
|
|
|
// Read Size
|
|
cbRead = _trans.Read( &cbRec, sizeof( cbRec ) );
|
|
Win4Assert( sizeof( cbRec ) == cbRead );
|
|
Win4Assert( cbRec );
|
|
|
|
return cbRec;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CRcovStrmIter::GetVariableRecData, public
|
|
//
|
|
// Synopsis: Gets the current variable record.
|
|
//
|
|
// Effects: Positions the current pointer after the current read.
|
|
//
|
|
// Arguments: [pvRec] -- Pointer to buffer to read the contents into.
|
|
// [cbRec] -- Size in bytes of pvRec
|
|
//
|
|
//
|
|
// History: 1-Jun-1998 VikasMan Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmIter::GetVariableRecData( void * pvRec, ULONG cbRec )
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
ULONG cbRead = _trans.Read( pvRec, cbRec );
|
|
Win4Assert( cbRead == cbRec );
|
|
|
|
ULONG ulCheckSum;
|
|
|
|
if ( _CHECKSUM_SIZE != _trans.Read( &ulCheckSum, sizeof(ulCheckSum) ) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error reading checksum.\n" ));
|
|
Win4Assert( !"Bad checksum" );
|
|
THROW( CException(CI_CORRUPT_CATALOG) );
|
|
}
|
|
|
|
if ( ulCheckSum != CheckSum( pvRec, cbRec ) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"Incorrect checksum 0x%x (should be 0x%x). pvRec = 0x%x\n",
|
|
CheckSum( pvRec ), ulCheckSum, pvRec ));
|
|
Win4Assert( !"Bad checksum" );
|
|
|
|
THROW( CException(CI_CORRUPT_CATALOG) );
|
|
}
|
|
}
|
|
|
|
|
|
#if 0 // untested unsused new function
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CRcovStrmIter::GetVariableRec, public
|
|
//
|
|
// Synopsis: Gets the current variable record. In the process would also
|
|
// allocate memory for it
|
|
//
|
|
// Effects: Positions the current pointer after the current read.
|
|
//
|
|
// Arguments: [ppvRec] -- Pointer to buffer to read the contents into.
|
|
//
|
|
// Returns: The size in bytes of *ppvRec
|
|
//
|
|
// History: 1-Jun-1998 VikasMan Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline ULONG CRcovStrmIter::GetVariableRec( void ** ppvRec )
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
*ppvRec = NULL;
|
|
|
|
ULONG cbRec;
|
|
|
|
// Read Size
|
|
cbRec = GetVariableRecSize();
|
|
|
|
// Now allocate and read data
|
|
*ppvRec = (void*) new BYTE[cbRec];
|
|
XPtrST<BYTE> xRec((BYTE*)*ppvRec);
|
|
|
|
GetVariableRecData( *ppvRec, cbRec );
|
|
|
|
xRec.Acquire();
|
|
|
|
return cbRec;
|
|
}
|
|
#endif
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CRcovStrmReadIter
|
|
//
|
|
// Purpose: Read-only version of recoverable stream iterator.
|
|
//
|
|
// History: 1-25-94 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CRcovStrmReadIter : public CRcovStrmIter
|
|
{
|
|
|
|
public:
|
|
|
|
inline CRcovStrmReadIter( CRcovStrmReadTrans &readTrans, USHORT cbRec );
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmReadIter::CRcovStrmReadIter, public
|
|
//
|
|
// Synopsis: Constructor. Just squirrels away member variables.
|
|
//
|
|
// Arguments: [trans] -- Transaction context to iterate
|
|
// [cbRec] -- Size of 'records' to be written.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline CRcovStrmReadIter::CRcovStrmReadIter( CRcovStrmReadTrans & readTrans , USHORT cbRec )
|
|
: CRcovStrmIter( readTrans, cbRec )
|
|
{
|
|
_trans.Seek(0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CRcovStrmAppendIter
|
|
//
|
|
// Purpose: Iterator to append fixed size records to the recoverable
|
|
// streams. This is just an optimized case of a write iterator.
|
|
//
|
|
// History: 2-10-94 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CRcovStrmAppendIter : public CRcovStrmIter
|
|
{
|
|
|
|
public:
|
|
|
|
inline CRcovStrmAppendIter( CRcovStrmAppendTrans &appendTrans, USHORT cbRec );
|
|
|
|
inline void AppendRec( const void *pvRec );
|
|
|
|
inline void AppendVariableRec( const void *pvRec, ULONG cbRec );
|
|
|
|
private:
|
|
|
|
CRcovStrmAppendTrans & _appendTrans;
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmAppendIter::CRcovStrmAppendIter, public
|
|
//
|
|
// Synopsis: Constructor. Just squirrels away member variables.
|
|
//
|
|
// Arguments: [trans] -- Transaction context to iterate
|
|
// [cbRec] -- Size of 'records' to be written.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline CRcovStrmAppendIter::CRcovStrmAppendIter( CRcovStrmAppendTrans & trans, USHORT cbRec )
|
|
: CRcovStrmIter( trans, cbRec ),
|
|
_appendTrans( trans )
|
|
{
|
|
_appendTrans.Seek( ENDOFSTRM );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmAppendIter::AppendRec, public
|
|
//
|
|
// Synopsis: Appends record to end of stream.
|
|
//
|
|
// Arguments: [pvRec] -- Record to append.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmAppendIter::AppendRec( const void *pvRec )
|
|
{
|
|
_appendTrans.Append( pvRec, _cbRec );
|
|
|
|
ULONG ulCheckSum = CheckSum( pvRec );
|
|
_appendTrans.Append( &ulCheckSum, sizeof(ulCheckSum), FALSE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmAppendIter::AppendVariableRec, public
|
|
//
|
|
// Synopsis: Appends variable size record to end of stream
|
|
//
|
|
// Arguments: [pvRec] -- Record to append.
|
|
// [cbRec] -- Count in bytes of pvRec
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: 01-Jun-1998 VikasMan Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline void CRcovStrmAppendIter::AppendVariableRec( const void *pvRec,
|
|
ULONG cbRec )
|
|
{
|
|
ULONG ulCheckSum;
|
|
|
|
Win4Assert( cbRec != 0 && pvRec != 0 );
|
|
|
|
// first write the size
|
|
_appendTrans.Append( &cbRec, sizeof( cbRec ), FALSE );
|
|
|
|
// next write the data
|
|
_appendTrans.Append( pvRec, cbRec );
|
|
ulCheckSum = CheckSum( pvRec, cbRec );
|
|
_appendTrans.Append( &ulCheckSum, sizeof(ulCheckSum), FALSE );
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CRcovStrmWriteIter
|
|
//
|
|
// Purpose: Iterator for writing fixed size anywhere in the
|
|
// recoverable stream.
|
|
//
|
|
// History: 2-10-94 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CRcovStrmWriteIter : public CRcovStrmIter
|
|
{
|
|
public:
|
|
|
|
inline CRcovStrmWriteIter( CRcovStrmWriteTrans & writeTrans, USHORT cbRec );
|
|
|
|
inline BOOL SetRec( const void *pvBuf, ULONG iRec );
|
|
inline void SetRec( const void *pvBuf );
|
|
|
|
inline void AppendRec( const void *pvBuf );
|
|
|
|
#if 0 // untested unused new function
|
|
inline void SetVariableRec( const void *pvRec,
|
|
ULONG cbRec,
|
|
BOOL fAppend = FALSE );
|
|
#endif
|
|
|
|
private:
|
|
|
|
CRcovStrmWriteTrans & _writeTrans;
|
|
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmWriteIter::CRcovStrmWriteIter, public
|
|
//
|
|
// Synopsis: Constructor. Just squirrels away member variables.
|
|
//
|
|
// Arguments: [trans] -- Transaction context to iterate
|
|
// [cbRec] -- Size of 'records' to be written.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline CRcovStrmWriteIter::CRcovStrmWriteIter( CRcovStrmWriteTrans & writeTrans, USHORT cbRec )
|
|
: CRcovStrmIter( writeTrans, cbRec ),
|
|
_writeTrans(writeTrans)
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmWriteIter::SetRec, public
|
|
//
|
|
// Synopsis: Writes specified record to stream.
|
|
//
|
|
// Arguments: [pvRec] -- Record data
|
|
// [iRec] -- Location at which write should occur
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline BOOL CRcovStrmWriteIter::SetRec( const void * pvRec, ULONG iRec )
|
|
{
|
|
if (! _writeTrans.Seek( (_cbRec + _CHECKSUM_SIZE) * iRec ) || AtEnd() )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
SetRec( pvRec );
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmWriteIter::SetRec, public
|
|
//
|
|
// Synopsis: Writes specified record to current location in stream.
|
|
//
|
|
// Arguments: [pvRec] -- Record data
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmWriteIter::SetRec( const void * pvRec )
|
|
{
|
|
_writeTrans.Write( pvRec, _cbRec );
|
|
|
|
ULONG ulCheckSum = CheckSum( pvRec );
|
|
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmWriteIter::AppendRec, public
|
|
//
|
|
// Synopsis: Appends record to end of stream.
|
|
//
|
|
// Arguments: [pvRec] -- Record to append.
|
|
//
|
|
// History: 27-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CRcovStrmWriteIter::AppendRec( const void *pvRec )
|
|
{
|
|
_writeTrans.Append( pvRec, _cbRec );
|
|
|
|
ULONG ulCheckSum = CheckSum( pvRec );
|
|
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
|
|
}
|
|
|
|
|
|
#if 0 // untested unused new function
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CRcovStrmWriteIter::SetVariableRec, public
|
|
//
|
|
// Synopsis: Writes/Appends variable size record to end of stream
|
|
//
|
|
// Arguments: [pvRec] -- Record to append.
|
|
// [cbRec] -- Count in bytes of pvRec
|
|
// [fAppend] -- If TRUE, then record is appended
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: 01-Jun-1998 VikasMan Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
inline void CRcovStrmWriteIter::SetVariableRec( const void *pvRec,
|
|
ULONG cbRec,
|
|
BOOL fAppend /* = FALSE */ )
|
|
{
|
|
ULONG ulCheckSum;
|
|
|
|
Win4Assert( cbRec != 0 && pvRec != 0 );
|
|
|
|
// first write the size
|
|
if ( fAppend )
|
|
_writeTrans.Append( &cbRec, sizeof( cbRec ) );
|
|
else
|
|
_writeTrans.Write( &cbRec, sizeof( cbRec ) );
|
|
|
|
// next write the data
|
|
_writeTrans.Write( pvRec, cbRec );
|
|
ulCheckSum = CheckSum( pvRec, cbRec );
|
|
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
|
|
}
|
|
#endif
|
|
|