windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/wrdwheel/wwbuild/wwuperst.cpp
2020-09-26 16:20:57 +08:00

490 lines
13 KiB
C++

// wwuperst.cpp: Implementation of wordwheel update persistance interface
#include <mvopsys.h>
#ifdef _DEBUG
static char s_aszModule[] = __FILE__; /* For error report */
#endif
#include <windows.h>
#include <iterror.h>
#include <atlinc.h>
#include <itpropl.h>
#include <ccfiles.h>
#include <itsortid.h>
#include "wwumain.h"
// Type Definitions ***********************************************************
typedef struct
{
DWORD cKeys;
DWORD ilOffset;
} RECKW, FAR * PRECKW;
STDMETHODIMP CITWordWheelUpdate::Save(IStorage *pStgSave, BOOL fSameAsLoad)
{
if (FALSE == m_fInitialized || NULL == m_piitskSortKey)
return SetErrReturn(E_NOTINIT);
// Create the permanent header stream
HRESULT hr;
IStream *pHeaderStream;
if (FAILED(hr = pStgSave->CreateStream
(SZ_BTREE_HEADER, STGM_WRITE, 0, 0, &pHeaderStream)))
return hr;
ResolveGlobalProperties (pHeaderStream);
// Handle occurence/term data
DWORD dwSize = GetFileSize(m_hTempFile, NULL);
CloseHandle(m_hTempFile);
m_hTempFile = NULL;
if (dwSize)
{
if (FAILED(hr = BuildPermanentFiles(pStgSave, pHeaderStream)))
{
pHeaderStream->Release();
return hr;
}
}
DeleteFile(m_szTempFile);
pHeaderStream->Release();
return S_OK;
} /* Save */
/***************************************************************
* @doc INTERNAL
*
* @api HRESULT FAR PASCAL | BuildKeywordFiles | This routine is called
* at the end of compilation to generate the appropriate
* .MVB subfiles to support runtime keyword stuff.
*
****************************************************************/
HRESULT WINAPI CITWordWheelUpdate::BuildPermanentFiles
(IStorage *pIStorage, IStream *pHeaderStream)
{
RECKW reckw;
HBT hbt;
IStream *pDataStream = NULL;
HRESULT hr; // Return code
LKW kwCur, kwNext;
LPSTR pCur, pEnd;
char fEOF;
DWORD dwWritten, dwTemp;
LPSTR pInput; // Input buffer
void * pvNewKey; // Used to resolve duplicate keys
DWORD dwBufferSize = CBMAX_KWENTRY; // Used to resolve duplicate keys
LPBYTE pKeyDataBuffer = NULL, pOccDataBuffer = NULL;
// Allocate temp buffers
pvNewKey = (void *)new BYTE[dwBufferSize];
if(NULL == pvNewKey)
return SetErrReturn(E_OUTOFMEMORY);
pKeyDataBuffer = new BYTE[m_cbMaxKeyData];
if (pKeyDataBuffer == NULL)
{
hr = E_OUTOFMEMORY;
goto exit0;
}
pOccDataBuffer = new BYTE[m_cbMaxOccData];
if (pOccDataBuffer == NULL)
{
hr = E_OUTOFMEMORY;
goto exit0;
}
// Sort the input file using our own sort function
if (S_OK !=(hr = FileSort(NULL,(LPB)m_szTempFile,
NULL, NULL, 0, CompareKeys, m_piitskSortKey, ScanTempFile, NULL)))
{
exit0:
delete pvNewKey;
if(pKeyDataBuffer)
delete pKeyDataBuffer;
if(pOccDataBuffer)
delete pOccDataBuffer;
return hr;
}
m_btParams.hfs = pIStorage;
// *****************************
// Map the input file to memory
// *****************************
pInput = MapSequentialReadFile(m_szTempFile, &dwTemp);
if (!pInput)
{
SetErrCode(&hr, E_FAIL);
goto exit0;
}
pCur = pInput;
pEnd = pInput + dwTemp;
hbt = HbtInitFill(SZ_BTREE_BTREE_A, &m_btParams, &hr);
if (hbt == hNil)
{
exit2:
UnmapViewOfFile(pInput);
goto exit0;
}
BtreeSetExtSort(hbt, m_piitskSortKey);
// **************************************
// CREATE KEYWORD FILE IN MVB FILE SYSTEM
// **************************************
if (FAILED(hr = pIStorage->CreateStream
(SZ_BTREE_DATA, STGM_WRITE, 0, 0, &pDataStream)))
{
exit4:
if (pDataStream)
pDataStream->Release();
RcAbandonHbt(hbt);
goto exit2;
}
// Process keywords until we get to the next set
reckw.ilOffset = dwWritten = 0;
fEOF = 0;
pCur = ParseKeywordLine(pCur, &kwCur); // Load first record
// Process occurence information
while (!fEOF)
{
LARGE_INTEGER liNull = {0};
DWORD cbKeyProp; // Size of the Key data block
reckw.cKeys = 1;
dwWritten = 0;
// Handle properties for the key
BOOL fNotDup = TRUE;
cbKeyProp = 0;
while (!fEOF && kwCur.bPropDest == C_PROPDEST_KEY)
{
if (fNotDup)
{
hr = FWriteData
(pDataStream, &kwCur, &cbKeyProp, pKeyDataBuffer);
if (FAILED(hr))
goto exit4;
fNotDup = FALSE;
}
if (pCur == pEnd)
fEOF = TRUE;
else
pCur = ParseKeywordLine(pCur, &kwCur);
}
// cbKeyProp is an accumulated total for all previous writes
// if we didin't write anything we must at least write a
// record size of zero to the stream.
if (0 == cbKeyProp)
{
dwTemp = 0;
pDataStream->Write (&dwTemp, sizeof (DWORD), &cbKeyProp);
}
// You must have occurrence information -- not just key data
if (fEOF)
{
SetErrCode(&hr, E_FAIL);
goto exit4;
}
if (FAILED(hr = FWriteData
(pDataStream, &kwCur, &dwWritten, pOccDataBuffer)))
goto exit4;
if (pEnd != pCur)
pCur = ParseKeywordLine(pCur, &kwNext);
else
fEOF = 1;
// ********************************************************
// ********* PROCESS ALL IDENTICAL ENTRIES **********
// ********************************************************
while (!fEOF)
{
LONG lResult;
hr = m_piitskSortKey->Compare(kwCur.szKeyword + sizeof(DWORD),
kwNext.szKeyword + sizeof(DWORD), &lResult, NULL);
ITASSERT(SUCCEEDED(hr));
if(lResult)
break;
// These keys are identical, but the user may want to calapse
// them for some reason. Maybe he has custom data embedded in
// the keys.
hr = m_piitskSortKey->ResolveDuplicates(
kwCur.szKeyword + sizeof(DWORD),
kwNext.szKeyword + sizeof(DWORD),
pvNewKey, &dwBufferSize);
if(SUCCEEDED(hr))
{
// Verify that the user didn't alter the sort order!
hr = m_piitskSortKey->Compare(
kwCur.szKeyword + sizeof(DWORD),
pvNewKey, &lResult, NULL);
ITASSERT(SUCCEEDED(hr));
if(lResult)
{
ITASSERT(FALSE);
SetErrCode(&hr, E_UNEXPECTED);
goto exit4;
}
// Copy the key to our local buffer
MEMCPY(kwCur.szKeyword
+ sizeof(DWORD), pvNewKey, CBMAX_KWENTRY);
}
else if(hr != E_NOTIMPL)
{
ITASSERT(FALSE);
goto exit4;
}
if (FAILED(hr = FWriteData
(pDataStream, &kwNext, &dwWritten, pOccDataBuffer)))
goto exit4;
if (pEnd == pCur)
fEOF = 1;
else
pCur = ParseKeywordLine(pCur, &kwNext);
reckw.cKeys++;
}
// Add record into B-Tree
if (FAILED (hr = RcFillHbt(hbt,
(KEY)kwCur.szKeyword + sizeof(DWORD),(QV)&reckw)))
goto exit4;
reckw.ilOffset += dwWritten + cbKeyProp;
LKW kwTemp = kwCur;
kwCur = kwNext;
kwNext = kwTemp;
}
// ***********************************************
// CLOSE THE BTREE FOR THIS KEYWORD SET, CLOSE THE
// .MVB SUBFILE, AND DISPOSE OF THE TEMPORARY FILE
// ***********************************************
pDataStream->Release();
pDataStream = NULL;
hr = RcFiniFillHbt(hbt);
if (FAILED(hr))
goto exit4;
// ***********************************************
// NOW, BUILD THE APPROPRIATE MAP FILE FOR EACH
// KEYWORD SET USED BY THE THUMB ON THE SCROLL BOX
// ***********************************************
if (FAILED (hr = RcCreateBTMapHfs(pIStorage, hbt, SZ_WORDWHEEL_MAP_A)))
goto exit4;
if (FAILED (hr = RcCloseBtreeHbt(hbt)))
goto exit4;
// Write PROPERTY file (contains property headers)
DWORD dwSize;
if (m_lpbKeyHeader)
{
pHeaderStream->Write (&m_cbKeyHeader, sizeof (DWORD), &dwWritten);
pHeaderStream->Write (m_lpbKeyHeader, m_cbKeyHeader, &dwWritten);
}
else
{
dwSize = 0;
pHeaderStream->Write (&dwSize, sizeof (DWORD), &dwWritten);
}
// For now, we have no default data
dwSize = 0;
pHeaderStream->Write (&dwSize, sizeof (DWORD), &dwWritten);
if (m_lpbOccHeader)
{
pHeaderStream->Write (&m_cbOccHeader, sizeof (DWORD), &dwWritten);
pHeaderStream->Write (m_lpbOccHeader, m_cbOccHeader, &dwWritten);
}
else
{
dwSize = 0;
pHeaderStream->Write (&dwSize, sizeof (DWORD), &dwWritten);
}
// For now, we have no default data
dwSize = 0;
pHeaderStream->Write (&dwSize, sizeof (DWORD), &dwWritten);
// *****************
// TIDY UP AND LEAVE
// *****************
hr = S_OK;
goto exit2;
} /* BuildPermanentFiles */
STDMETHODIMP CITWordWheelUpdate::ResolveGlobalProperties
(IStream *pHeaderStream)
{
DWORD dwSize, dwWritten;
CloseHandle(m_hGlobalPropTempFile);
m_hGlobalPropTempFile = NULL;
if (!m_dwGlobalPropSize)
{
dwSize = 0;
pHeaderStream->Write (&dwSize, sizeof (DWORD), &dwWritten);
DeleteFile(m_szGlobalPropTempFile);
return S_OK;
}
HRESULT hr;
IITPropList *plTemp = NULL;
LPSTR pInput = NULL;
ULARGE_INTEGER ulSize;
// Map the temp file to memory
pInput = MapSequentialReadFile(m_szGlobalPropTempFile, &dwSize);
if (NULL == pInput)
{
SetErrCode(&hr, E_FAIL);
GlobalExit0:
if (plTemp)
plTemp->Release();
if (pInput)
UnmapViewOfFile (pInput);
return hr;
}
// Create property list
hr = CoCreateInstance(CLSID_IITPropList, NULL,
CLSCTX_INPROC_SERVER, IID_IITPropList,(LPVOID *)&plTemp);
if (FAILED(hr))
goto GlobalExit0;
// Load list from temp file
if (FAILED (hr = plTemp->LoadFromMem (pInput, dwSize)))
goto GlobalExit0;
// Get list size
plTemp->GetSizeMax(&ulSize);
// Write the property list size
hr = pHeaderStream->Write
(&ulSize.LowPart, sizeof(ulSize.LowPart), &dwSize);
if (FAILED(hr))
goto GlobalExit0;
// Write the property list
if (FAILED(hr = plTemp->Save(pHeaderStream, TRUE)))
goto GlobalExit0;
plTemp->Release();
UnmapViewOfFile (pInput);
DeleteFile(m_szGlobalPropTempFile);
return S_OK;
} /* ResolveGlobalProperties */
STDMETHODIMP CITWordWheelUpdate::GetClassID(CLSID *pClsID)
{
if (NULL == pClsID
|| IsBadWritePtr(pClsID, sizeof(CLSID)))
return SetErrReturn(E_INVALIDARG);
*pClsID = CLSID_IITWordWheelUpdate;
return S_OK;
} /* GetClassID */
STDMETHODIMP CITWordWheelUpdate::IsDirty(void)
{
if (m_fIsDirty)
return S_OK;
return S_FALSE;
} /* IsDirty */
STDMETHODIMP CITWordWheelUpdate::Load(IStorage *pStg)
{
return SetErrReturn(E_NOTIMPL);
} /* Load */
STDMETHODIMP CITWordWheelUpdate::InitNew(IStorage *pStg)
{
if (m_pStorage)
return SetErrReturn(CO_E_ALREADYINITIALIZED);
if (NULL == pStg)
return SetErrReturn(E_INVALIDARG);
m_pStorage = pStg;
pStg->AddRef();
m_fIsDirty = FALSE;
// Create a temp file
char szTempPath [_MAX_PATH + 1];
if (0 == GetTempPath(_MAX_PATH, szTempPath))
return SetErrReturn(E_FILECREATE);
if (0 == GetTempFileName(szTempPath, "WWU", 0, m_szTempFile))
return SetErrReturn(E_FILECREATE);
m_hTempFile = CreateFile
(m_szTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == m_hTempFile)
return SetErrReturn(E_FILECREATE);
if (0 == GetTempFileName(szTempPath, "WWU", 0, m_szGlobalPropTempFile))
return SetErrReturn(E_FILECREATE);
m_hGlobalPropTempFile = CreateFile(m_szGlobalPropTempFile,
GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == m_hGlobalPropTempFile)
return SetErrReturn(E_FILECREATE);
// Reset member variables
m_dwEntryCount = 0;
m_dwGlobalPropSize = 0;
m_lpbKeyHeader = m_lpbOccHeader = NULL;
m_cbMaxKeyData = m_cbMaxOccData = 0;
m_fInitialized = TRUE;
return S_OK;
} /* InitNew */
STDMETHODIMP CITWordWheelUpdate::SaveCompleted(IStorage *pStgNew)
{
if (pStgNew)
{
if (!m_pStorage)
return SetErrReturn(E_UNEXPECTED);
m_pStorage->Release();
(m_pStorage = pStgNew)->AddRef();
}
m_fIsDirty = FALSE;
return S_OK;
} /* SaveCompleted */
STDMETHODIMP CITWordWheelUpdate::HandsOffStorage(void)
{
return S_OK;
} /* HandsOffStorage */