|
|
// 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 */
|