364 lines
8.1 KiB
C++
364 lines
8.1 KiB
C++
|
#include "stdafx.h"
|
||
|
//#include <stdio.h>
|
||
|
|
||
|
#define StreamName L"ResetTable"
|
||
|
|
||
|
|
||
|
ULONG CXResetData::BinarySearch(
|
||
|
LPRESETREC pTbl,
|
||
|
ULONG ulStart,
|
||
|
ULONG ulEnd,
|
||
|
ULARGE_INTEGER uliKey
|
||
|
)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
static int cLoop; // BugBug! This will fail in multithreaded situations!
|
||
|
cLoop++;
|
||
|
RonM_ASSERT(cLoop < 20);
|
||
|
#endif
|
||
|
|
||
|
if (ulStart == ulEnd)
|
||
|
{
|
||
|
DEBUGCODE(cLoop = 0;)
|
||
|
return ulStart;
|
||
|
}
|
||
|
else
|
||
|
if (ulStart == (ulEnd -1))
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
cLoop = 0;
|
||
|
#endif
|
||
|
|
||
|
if (CULINT(uliKey) >= CULINT(ulEnd * m_ulBlockSize))
|
||
|
return ulEnd;
|
||
|
else
|
||
|
return ulStart;
|
||
|
}
|
||
|
|
||
|
ULONG ulMid = (ulEnd + ulStart) / 2;
|
||
|
|
||
|
if (CULINT(uliKey) <= CULINT(ulMid * m_ulBlockSize))
|
||
|
{
|
||
|
return BinarySearch(pTbl, ulStart, ulMid, uliKey);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return BinarySearch(pTbl, ulMid, ulEnd, uliKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG CXResetData::FindRecord(
|
||
|
ULARGE_INTEGER uliOffset,
|
||
|
ULARGE_INTEGER *puliXOffset,
|
||
|
BOOL *pfLastRecord
|
||
|
)
|
||
|
{
|
||
|
ULONG ulRecNum;
|
||
|
|
||
|
if (m_cFillRecs)
|
||
|
{
|
||
|
ulRecNum = BinarySearch(m_pSyncTbl, 0, m_cFillRecs - 1, uliOffset);
|
||
|
*puliXOffset = (m_pSyncTbl + ulRecNum)->uliXOffset;
|
||
|
*pfLastRecord = (ulRecNum == (m_cFillRecs - 1));
|
||
|
}
|
||
|
return ulRecNum;
|
||
|
}
|
||
|
|
||
|
BOOL CXResetData::FGetRecord(
|
||
|
ULONG ulRecNum,
|
||
|
ULARGE_INTEGER *puliOffset,
|
||
|
ULARGE_INTEGER *puliXOffset,
|
||
|
BOOL *pfLastRecord
|
||
|
)
|
||
|
{
|
||
|
if (ulRecNum >= m_cFillRecs)
|
||
|
return FALSE;
|
||
|
|
||
|
*puliOffset = CULINT(ulRecNum * m_ulBlockSize).Uli();
|
||
|
*puliXOffset = (m_pSyncTbl + ulRecNum)->uliXOffset;
|
||
|
*pfLastRecord = (ulRecNum == (m_cFillRecs - 1));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::DeleteRecord(ULONG ulRecNum)
|
||
|
{
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
|
||
|
//Verify we are deleting valid record
|
||
|
if (ulRecNum < m_cFillRecs)
|
||
|
{
|
||
|
m_cFillRecs--;
|
||
|
m_cEmptyRecs++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::AddRecord(ULARGE_INTEGER uliOffset, ULARGE_INTEGER uliXOffset)
|
||
|
{
|
||
|
if (m_cEmptyRecs <= 0)
|
||
|
{
|
||
|
//double the size of reset table for future use
|
||
|
LPRESETREC prec = m_pSyncTbl;
|
||
|
|
||
|
ULONG nTotalRecs = (m_cFillRecs ? m_cFillRecs : 64) * 2;
|
||
|
|
||
|
if (m_pSyncTbl = New sResetRec[nTotalRecs])
|
||
|
{
|
||
|
//copy old table to newly created table with bigger size
|
||
|
if (prec)
|
||
|
{
|
||
|
memCpy((LPBYTE)m_pSyncTbl, (LPBYTE)prec, m_cFillRecs * sizeof(sResetRec));
|
||
|
delete prec;
|
||
|
}
|
||
|
m_cEmptyRecs = nTotalRecs - m_cFillRecs;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pSyncTbl = prec;
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LPRESETREC prec = m_pSyncTbl + m_cFillRecs;
|
||
|
prec->uliXOffset = uliXOffset;
|
||
|
|
||
|
m_cFillRecs++;
|
||
|
m_cEmptyRecs--;
|
||
|
|
||
|
m_fDirty = TRUE;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
CXResetData::CXResetData(
|
||
|
/*IStorage *pstg*/
|
||
|
)
|
||
|
{
|
||
|
m_fDirty = FALSE;
|
||
|
m_pStm = NULL;
|
||
|
m_pStg = NULL;
|
||
|
m_cFillRecs = 0;
|
||
|
m_cEmptyRecs =0;
|
||
|
m_pSyncTbl = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
CXResetData::~CXResetData()
|
||
|
{
|
||
|
if (m_pSyncTbl)
|
||
|
{
|
||
|
delete m_pSyncTbl;
|
||
|
m_pSyncTbl = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_pStm)
|
||
|
m_pStm->Release();
|
||
|
|
||
|
if (m_pStg)
|
||
|
m_pStg->Release();
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::InitResetTable(IStorage *pStg,
|
||
|
ULARGE_INTEGER *puliVSpaceSize,
|
||
|
ULARGE_INTEGER *puliTxSpaceSize,
|
||
|
ULONG ulBlockSize)
|
||
|
{
|
||
|
m_pStg = pStg;
|
||
|
m_pStg->AddRef();
|
||
|
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
|
||
|
*puliVSpaceSize = CULINT(0).Uli();
|
||
|
*puliTxSpaceSize = CULINT(0).Uli();
|
||
|
m_ulBlockSize = ulBlockSize;
|
||
|
|
||
|
if (SUCCEEDED(hr = GetResetTblStream(pStg, &m_pStm)))
|
||
|
{
|
||
|
sHeader header;
|
||
|
ULONG cbBytesRead = 0;
|
||
|
|
||
|
int hr = m_pStm->Read((LPVOID)&header, sizeof(sHeader), &cbBytesRead);
|
||
|
|
||
|
if (SUCCEEDED(hr) && (cbBytesRead == sizeof(sHeader)))
|
||
|
{
|
||
|
*puliVSpaceSize = header.uliVSpaceSize;
|
||
|
*puliTxSpaceSize = header.uliTxSpaceSize;
|
||
|
|
||
|
m_cFillRecs = header.cRecs;
|
||
|
if (m_cFillRecs > 0)
|
||
|
{
|
||
|
//allocate reset table with record
|
||
|
//count which is double of m_cFillRecs.
|
||
|
ULONG nTotalRecs = m_cFillRecs * 2;
|
||
|
if (m_pSyncTbl = New sResetRec[nTotalRecs])
|
||
|
{
|
||
|
m_cEmptyRecs = nTotalRecs - m_cFillRecs;
|
||
|
|
||
|
LARGE_INTEGER dliB;
|
||
|
ULARGE_INTEGER dliBFinal;
|
||
|
|
||
|
dliB.HighPart = 0;
|
||
|
dliB. LowPart = header.cbSize;
|
||
|
|
||
|
dliBFinal.HighPart = 0;
|
||
|
dliBFinal. LowPart = 0;
|
||
|
|
||
|
if (SUCCEEDED(hr = m_pStm->Seek(dliB, STREAM_SEEK_SET, &dliBFinal)))
|
||
|
{
|
||
|
if (header.dwVerInfo == 1)
|
||
|
{
|
||
|
sResetRecV1 sRecV1;
|
||
|
ULONG cb;
|
||
|
for (int iRec = 0; SUCCEEDED(hr) && (iRec < m_cFillRecs); iRec++)
|
||
|
{
|
||
|
hr = m_pStm->Read((LPVOID)&sRecV1,
|
||
|
sizeof(sResetRecV1),
|
||
|
&cb);
|
||
|
cbBytesRead += cb;
|
||
|
(m_pSyncTbl + iRec)->uliXOffset = sRecV1.uliXOffset;
|
||
|
}
|
||
|
}
|
||
|
else if (header.dwVerInfo == LZX_Current_Version)
|
||
|
{
|
||
|
hr = m_pStm->Read((LPVOID)(m_pSyncTbl),
|
||
|
m_cFillRecs * sizeof(sResetRec),
|
||
|
&cbBytesRead);
|
||
|
}//read
|
||
|
}//seek
|
||
|
}// new
|
||
|
else
|
||
|
{
|
||
|
hr = STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
}//no. of entries in table > 0
|
||
|
}//read header
|
||
|
}//open reset table stream
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::DumpStream(IStream *pTempStrm, LPSTR pFileName)
|
||
|
{
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
#if 0 //test code
|
||
|
FILE *file = fopen(pFileName, "w" );
|
||
|
|
||
|
if (file != NULL)
|
||
|
{
|
||
|
RonM_ASSERT(pTempStrm != NULL);
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
BYTE lpBuf[2048];
|
||
|
|
||
|
if (SUCCEEDED(hr = pTempStrm->Seek(CLINT(0).Li(), STREAM_SEEK_SET, 0)))
|
||
|
{
|
||
|
ULONG cbToRead = sizeof(lpBuf);
|
||
|
ULONG cbWritten;
|
||
|
ULONG cbRead = cbToRead;
|
||
|
|
||
|
while (SUCCEEDED(hr) && (cbRead == cbToRead))
|
||
|
{
|
||
|
if (SUCCEEDED(hr = pTempStrm->Read(lpBuf, cbToRead, &cbRead)))
|
||
|
{
|
||
|
cbWritten = fwrite(lpBuf, sizeof(BYTE), cbRead, file);
|
||
|
RonM_ASSERT(cbRead == cbWritten);
|
||
|
if (cbRead != cbWritten)
|
||
|
hr = E_FAIL;
|
||
|
}//ReadAt
|
||
|
}//while
|
||
|
|
||
|
}//seek
|
||
|
|
||
|
fclose(file);
|
||
|
}
|
||
|
else
|
||
|
hr = E_FAIL;
|
||
|
|
||
|
#endif //end test code
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::CommitResetTable(ULARGE_INTEGER uliVSpaceSize,
|
||
|
ULARGE_INTEGER uliTxSpaceSize)
|
||
|
{
|
||
|
RonM_ASSERT(m_pStm);
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
|
||
|
if (m_fDirty)
|
||
|
{
|
||
|
sHeader header;
|
||
|
|
||
|
//latest version
|
||
|
header.dwVerInfo = LZX_Current_Version;
|
||
|
header.cRecs = m_cFillRecs;
|
||
|
header.cbSize = sizeof(sHeader);
|
||
|
header.cbRecSize = sizeof(sResetRec);
|
||
|
header.uliVSpaceSize = uliVSpaceSize;
|
||
|
header.uliTxSpaceSize = uliTxSpaceSize;
|
||
|
header.ulBlockSize = m_ulBlockSize;
|
||
|
header.unused = 0;
|
||
|
|
||
|
ULONG cbWritten;
|
||
|
|
||
|
LARGE_INTEGER dliB;
|
||
|
ULARGE_INTEGER dliBFinal;
|
||
|
|
||
|
dliB.HighPart = 0;
|
||
|
dliB. LowPart = 0;
|
||
|
|
||
|
dliBFinal.HighPart = 0;
|
||
|
dliBFinal. LowPart = 0;
|
||
|
|
||
|
if (SUCCEEDED(hr = m_pStm->Seek(dliB, STREAM_SEEK_SET, &dliBFinal)))
|
||
|
{
|
||
|
hr = m_pStm->Write((LPVOID)&header, sizeof(header), &cbWritten);
|
||
|
if (SUCCEEDED(hr) && (cbWritten == sizeof(header)))
|
||
|
{
|
||
|
if (SUCCEEDED(hr = m_pStm->Write((LPVOID)m_pSyncTbl,
|
||
|
sizeof(sResetRec) * m_cFillRecs,
|
||
|
&cbWritten)))
|
||
|
{
|
||
|
if (cbWritten != sizeof(sResetRec) * m_cFillRecs)
|
||
|
hr = E_FAIL;
|
||
|
else
|
||
|
m_fDirty = FALSE;
|
||
|
|
||
|
}//write table
|
||
|
}//write header
|
||
|
}//seek
|
||
|
}//if table dirty
|
||
|
|
||
|
//test code
|
||
|
#ifdef _DEBUG
|
||
|
DumpStream(m_pStm, "c:\\dbg.tbl");
|
||
|
#else
|
||
|
DumpStream(m_pStm, "c:\\rel.tbl");
|
||
|
#endif
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CXResetData::GetResetTblStream(IStorage *pStg, IStream **ppStm)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
if (STG_E_FILENOTFOUND == (hr = pStg->OpenStream(StreamName,
|
||
|
0,
|
||
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE| STGM_DIRECT,
|
||
|
0,
|
||
|
ppStm)))
|
||
|
{
|
||
|
hr = pStg->CreateStream(StreamName,
|
||
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE
|
||
|
| STGM_DIRECT
|
||
|
| STGM_CREATE,
|
||
|
0,
|
||
|
0,
|
||
|
ppStm);
|
||
|
}//open stream
|
||
|
|
||
|
return hr;
|
||
|
}
|