// wwuperst.cpp: Implementation of wordwheel update persistance interface #include #ifdef _DEBUG static char s_aszModule[] = __FILE__; /* For error report */ #endif #include #include #include #include #include #include #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 */