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

1105 lines
33 KiB
C++

/*************************************************************************
* @doc SHROOM EXTERNAL API *
* *
* SVMGR.C *
* *
* Copyright (C) Microsoft Corporation 1995-1997 *
* All Rights reserved. *
* *
* The Service Manager is responsible for reading the object description *
* from the command interpreter, getting object properties and data, and *
* building the objects. *
* *
**************************************************************************
* *
* Written By : John Rush *
* Current Owner: johnrush *
* *
**************************************************************************/
#include <verstamp.h>
SETVERSIONSTAMP(MVSV);
#include <mvopsys.h>
#ifdef _DEBUG
static char s_aszModule[] = __FILE__; /* For error report */
#endif
#include <windows.h>
#ifdef IA64
#include <itdfguid.h>
#endif
#include <iterror.h>
#include <orkin.h>
#include <wrapstor.h>
#include <_mvutil.h>
#include <mvsearch.h>
#include <dynarray.h>
#include <groups.h>
#include <itwbrk.h>
#include <itwbrkid.h>
#include <ccfiles.h>
#include <itdb.h>
#include <itsortid.h>
#include <itgroup.h>
#include "itsvmgr.h"
#include "svutil.h"
#include "svdoc.h"
#include "iterr.h"
extern HINSTANCE _hInstITCC;
CITSvMgr::CITSvMgr(void)
{
m_fInitialized = FALSE;
m_piistmLog = NULL;
}
CITSvMgr::~CITSvMgr(void)
{
if (m_fInitialized)
Dispose();
}
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | Initiate |
* Creates and initiates a structure containing
* data necessary for future service requests.
*
* @parm IStorage * | pStorage |
* Pointer to destination IStorage. In most cases, this
* is the ITSS IStorage file.
*
* @parm IStream * | piistmLog |
* Optional IStream to log error messages.
*
* @rvalue S_OK | The service manager was initialized successfully
* @rvalue E_INVALIDARG | One of the required arguments was NULL or otherwise not valid
* @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
*
* @xref <om.LoadFromStream>
*
* @comm This should be the first method called for the service manager.
********************************************************************/
HRESULT WINAPI CITSvMgr::Initiate
(IStorage *piistgStorage, IStream *piistmLog)
{
HRESULT hResult = S_OK;
if (m_fInitialized)
return SetErrReturn(E_ALREADYINIT);
if (NULL == piistgStorage)
return SetErrReturn(E_INVALIDARG);
if(m_piistmLog = piistmLog)
m_piistmLog->AddRef();
m_pPLDocunent = NULL;
m_pCatHeader = NULL;
m_dwMaxPropSize = 0;
*m_szCatFile = '\0';
m_piitdb = NULL;
m_pipstgDatabase = NULL;
m_dwMaxUID = 0;
hResult = (m_piistgRoot = piistgStorage)->AddRef();
if (SUCCEEDED(hResult))
{
ZeroMemory (&m_dlCLSID, sizeof (DL));
ZeroMemory (&m_dlObjList, sizeof (DL));
// Create database
if (SUCCEEDED(hResult = CoCreateInstance(CLSID_IITDatabaseLocal, NULL,
CLSCTX_INPROC_SERVER, IID_IITDatabase, (void **)&m_piitdb))
&&
SUCCEEDED(hResult = m_piitdb->QueryInterface
(IID_IPersistStorage, (void **)&m_pipstgDatabase)))
{
if (FAILED(hResult = m_pipstgDatabase->InitNew(piistgStorage)))
LogMessage(SVERR_InitNew, "IITDatabase", hResult);
}
}
if (FAILED(hResult))
{
if (m_piistgRoot)
m_piistgRoot->Release();
piistgStorage->Release();
if (m_piitdb)
{
m_piitdb->Release();
m_piitdb = NULL;
}
if (m_pipstgDatabase)
{
m_pipstgDatabase->Release();
m_pipstgDatabase = NULL;
}
} else
m_fInitialized = TRUE;
return (hResult);
} /* SVInitiate */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | Dispose |
*
* Signal that all services are no longer needed, causing any resources
* allocated during use of the service manager to be freed.
*
* @rvalue S_OK | All resources freed successfully
*
* @xref <om.Initiate>
*
* @comm This should be the last method called for the service manager.
********************************************************************/
HRESULT WINAPI CITSvMgr::Dispose ()
{
if (FALSE == m_fInitialized)
return SetErrReturn(E_NOTINIT);
if (m_pPLDocunent)
{
m_pPLDocunent->Release();
m_pPLDocunent = NULL;
}
// Destroy catalog
if (*m_szCatFile)
{
CloseHandle (m_hCatFile);
DeleteFile (m_szCatFile);
}
if (m_pCatHeader)
{
_GLOBALFREE ((HANDLE)m_pCatHeader);
m_pCatHeader = NULL;
*m_szCatFile = '\0';
}
m_piitdb->Release();
m_pipstgDatabase->Release();
m_piistgRoot->Release();
if(m_piistmLog)
m_piistmLog->Release();
if (DynArrayValid (&m_dlCLSID))
{
PCLSIDENTRY pEntry;
for (pEntry = (PCLSIDENTRY)DynArrayGetFirstElt (&m_dlCLSID);
pEntry; pEntry = (PCLSIDENTRY)DynArrayNextElt (&m_dlCLSID))
{
pEntry->pCf->Release();
}
DynArrayFree (&m_dlCLSID);
}
if (DynArrayValid (&m_dlObjList))
{
POBJENTRY pEntry;
for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
{
if (pEntry->piitbc)
{
pEntry->piitbc->Release();
pEntry->piitbc = NULL;
if (pEntry->piistg)
{
pEntry->piistg->Commit(STGC_DEFAULT);
pEntry->piistg->Release();
} else if (pEntry->piistm)
pEntry->piistm->Release();
#ifdef _DEBUG
pEntry->piistg = NULL;
pEntry->piistm = NULL;
#endif
}
delete pEntry->wszStorage;
}
DynArrayFree (&m_dlObjList);
}
m_fInitialized = FALSE;
return S_OK;
} /* Dispose */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | AddDocument |
* Adds the authored properties and indexable content that were added to the
* given document template into the service manager's build process. Once
* AddDocument is called, the data will included in the pending
* Build() operation.
*
* @parm CSvDoc *| pDoc | Pointer to document template containing the
* content and properties for the current document.
*
* @rvalue S_OK | The properties and content were added successfully
* @rvalue E_MISSINGPROP | The document did not have one of the mandatory properties.
* Currently, the only required property is STDPROP_UID.
*
* @rvalue E_INVALIDARG | One of the required arguments was NULL or otherwise not valid
* @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
*
* @xref <om.AddObjectEntry>
* @xref <om.Build>
*
* @comm
********************************************************************/
HRESULT WINAPI CITSvMgr::AddDocument (CSvDoc *lpDoc)
{
WCHAR *lpch;
HRESULT hr;
DWORD cbData;
CSvDocInternal *pDoc = (CSvDocInternal *)lpDoc;
if (FALSE == m_fInitialized)
return SetErrReturn(E_NOTINIT);
if (NULL == pDoc)
return SetErrReturn(E_INVALIDARG);
// Suck in the document properties from the batch buffer
if (!pDoc->m_lpbfDoc)
return SetErrReturn(E_MISSINGPROP);
// Create property list
if (m_pPLDocunent == NULL)
{
hr = CoCreateInstance (CLSID_IITPropList, NULL,
CLSCTX_INPROC_SERVER, IID_IITPropList, (LPVOID *)&m_pPLDocunent);
if (FAILED (hr))
{
LogMessage(SVERR_CoCreateInstance, "IID_IITPropList", hr);
return SetErrReturn(hr);
}
}
else
m_pPLDocunent->Clear();
// Get the property list for the document
cbData = *(LPDWORD)DynBufferPtr (pDoc->m_lpbfDoc);
m_pPLDocunent->LoadFromMem (DynBufferPtr (pDoc->m_lpbfDoc) + sizeof (DWORD), cbData);
// Get the UID for the document
CProperty UidProp;
if (FAILED(hr = m_pPLDocunent->Get(STDPROP_UID, UidProp))
|| TYPE_STRING == UidProp.dwType)
{
LogMessage(SVERR_NoUID);
return SetErrReturn(E_MISSINGPROP);
}
// This could be a pointer to a UID or a DWORD UID
if (TYPE_VALUE == UidProp.dwType)
pDoc->m_dwUID = UidProp.dwValue;
else if (TYPE_POINTER == UidProp.dwType)
pDoc->m_dwUID = *((LPDWORD&)UidProp.lpvData);
if (m_dwMaxUID < pDoc->m_dwUID)
m_dwMaxUID = pDoc->m_dwUID;
if (cbData)
CatalogSetEntry (m_pPLDocunent, 0);
// Now scan through the batch entry buffer. For each object, farm out the
// persisted property values to that object.
if (!pDoc->m_lpbfEntry || !DynBufferLen (pDoc->m_lpbfEntry))
return S_OK;
// Ensure the buffer is terminated with zero marker
cbData = 0;
if (!DynBufferAppend (pDoc->m_lpbfEntry, (LPBYTE)&cbData, sizeof (DWORD)))
return SetErrReturn(E_OUTOFMEMORY);
// Work through all the property lists
for (lpch = (WCHAR *) DynBufferPtr(pDoc->m_lpbfEntry); lpch;)
{
WCHAR szObject[MAX_OBJECT_NAME];
WCHAR szPropDest[MAX_OBJECT_NAME];
m_pPLDocunent->Clear();
// found zero marker instead of name
if (*(LPDWORD)lpch == 0L)
break;
// read the object name
WSTRCPY(szObject, lpch);
lpch += WSTRLEN(szObject) + 1;
// read the property destination
WSTRCPY(szPropDest, lpch);
lpch += WSTRLEN(szPropDest) + 1;
cbData = *(LPDWORD)lpch;
((LPBYTE&)lpch) += sizeof(DWORD);
m_pPLDocunent->LoadFromMem (lpch, cbData);
((LPBYTE&)lpch) += cbData;
// we now have a property list, examine the object type and pass to the
// lower level build routines.
POBJENTRY pEntry;
for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
{
if (!WSTRICMP (szObject, pEntry->wszObjName) && pEntry->piitbc)
{
hr = pEntry->piitbc->SetEntry
(*szPropDest ? szPropDest : NULL, m_pPLDocunent);
if (FAILED (hr))
{
LogMessage(SVERR_SetEntry, pEntry->wszObjName, hr);
pEntry->piitbc->Close();
pEntry->piitbc->Release();
pEntry->piitbc = NULL;
if (pEntry->piistg)
pEntry->piistg->Release();
else if (pEntry->piistm)
pEntry->piistm->Release();
#ifdef _DEBUG
pEntry->piistg = NULL;
pEntry->piistm = NULL;
#endif
m_piistgRoot->DestroyElement (pEntry->wszStorage);
}
break;
}
}
// UNDONE: document catalog build (titles and other custom doc properties)
}
return S_OK;
} /* AddDocument */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | Build |
* Takes the data accumulated during AddDocument calls and completes the
* creation of the objects that were requested in the original command
* interpreter description.
*
* @rvalue S_OK | All requested objects, such as wordwheels, and full-text
* index, were built successfully and added to the output storage.
*
* @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
*
* @xref <om.AddObjectEntry>
* @xref <om.AddDocument>
*
* @comm
********************************************************************/
HRESULT WINAPI CITSvMgr::Build ()
{
HRESULT hr = S_OK;
ITBuildObjectControlInfo itboci = {sizeof (itboci), m_dwMaxUID};
if (FALSE == m_fInitialized)
return SetErrReturn(E_NOTINIT);
// Handle Document Catalog
hr = CatalogCompleteUpdate();
// Save all breaker and sort instance data to the storage
if (SUCCEEDED(hr))
{
if (FAILED(hr = m_pipstgDatabase->Save(m_piistgRoot, TRUE)))
LogMessage(SVERR_DatabaseSave, hr);
}
if (SUCCEEDED(hr) && DynArrayValid (&m_dlObjList))
{
// Build objects
for (POBJENTRY pObj = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
pObj; pObj = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
{
if (NULL == pObj->piitbc)
continue;
hr = pObj->piitbc->SetBuildStats(itboci);
if (FAILED(hr) && hr != E_NOTIMPL)
{
;// LogMessage();
continue;
}
if (pObj->piistg)
{
// Must support IPersistStorage
IPersistStorage *pPersistStorage;
if (FAILED(hr = pObj->piitbc->QueryInterface
(IID_IPersistStorage, (void **)&pPersistStorage)))
{
ITASSERT(0); // We shoulnd't ever hit this condition!
continue;
}
if(FAILED(hr = pPersistStorage->Save(pObj->piistg, TRUE)))
LogMessage(SVERR_IPSTGSave, pObj->wszObjName, hr);
pPersistStorage->Release();
pObj->piistg->Commit(STGC_DEFAULT);
pObj->piistg->Release();
}
else if (pObj->piistm)
{
// Must support IPersistStream then
IPersistStreamInit *pPersistStream;
if (FAILED(hr = pObj->piitbc->QueryInterface
(IID_IPersistStreamInit, (void **)&pPersistStream)))
{
ITASSERT(0); // We shoulnd't ever hit this condition!
continue;
}
if(FAILED(hr = pPersistStream->Save(pObj->piistm, TRUE)))
LogMessage(SVERR_IPSTMSave, pObj->wszObjName, hr);
pPersistStream->Release();
pObj->piistm->Release();
#ifdef _DEBUG
pObj->piistm = NULL;
#endif
}
// What's the deal??? We checked for these earlier!
else ITASSERT(0);
if (FAILED (hr))
m_piistgRoot->DestroyElement (pObj->wszStorage);
pObj->piitbc->Release();
pObj->piitbc = NULL;
}
hr = S_OK; // We don't return componenet build errors
}
LogMessage(SV_BuildComplete);
return hr;
} /* Build */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | CreateDocTemplate |
* Returns a popinter to a CSVDoc class which can be sent to AddDocument.
* Pass this pointer to FreeDocTemplate when you no longer need it.
*
* @rvalue S_OK | The CSvDoc object was succesfully created.
*
* @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
*
* @xref <om.AddObjectEntry>
* @xref <om.AddDocument>
* @xref <om.FreeDocTemplate>
*
*
********************************************************************/
HRESULT WINAPI CITSvMgr::CreateDocTemplate (CSvDoc **pDoc)
{
*pDoc = new CSvDocInternal;
if (*pDoc)
return S_OK;
return SetErrReturn(E_OUTOFMEMORY);
} /* CreateDocTemplate */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | FreeDocTemplate |
* Frees a CSvDoc class returned from CreateDocTemplate.
*
* @rvalue E_INVALIDARG | Thie CSvDoc pointer is NULL.
* @rvalue S_OK | The CSvDoc object was freed.
*
* @xref <om.CreateDocTemplate>
*
*
********************************************************************/
HRESULT WINAPI CITSvMgr::FreeDocTemplate (CSvDoc *pDoc)
{
if (NULL == pDoc)
return SetErrReturn(E_INVALIDARG);
delete (CSvDocInternal *)pDoc;
return S_OK;
} /* FreeDocTemplate */
/********************************************************************
* @method HRESULT WINAPI | IITSvMgr | CreateBuildObject|
* Creates a build object.
*
* @parm LPCWSTR | szObjectName | Name of object to create.
* @parm REFCLSID | clsid |Class ID of object.
*
* @rvalue S_OK | The operation completed successfully.
* @rvalue E_INVALIDARG | The argument was not valid
*
********************************************************************/
HRESULT WINAPI CITSvMgr::CreateBuildObject(LPCWSTR szObjectName, REFCLSID clsid)
{
HRESULT hr;
if (FALSE == m_fInitialized)
return SetErrReturn(E_NOTINIT);
if (NULL == szObjectName)
return SetErrReturn(E_INVALIDARG);
if (!DynArrayValid (&m_dlCLSID))
// This allocates a dynamic array that can hold a
// MAXIMUM of 500 unique classes
if (FALSE == DynArrayInit (&m_dlCLSID,
sizeof (CLSIDENTRY) * 5, 100, sizeof (CLSIDENTRY), 0))
return SetErrReturn(E_OUTOFMEMORY);
// Is this entry already in the list?
PCLSIDENTRY pclsidEntry;
IClassFactory *pCF;
for (pclsidEntry = (PCLSIDENTRY)DynArrayGetFirstElt (&m_dlCLSID);
pclsidEntry; pclsidEntry = (PCLSIDENTRY)DynArrayNextElt (&m_dlCLSID))
{
if (clsid == pclsidEntry->clsid)
{
pCF = pclsidEntry->pCf;
break;
}
}
// Create new class factory
if (NULL == pclsidEntry)
{
hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL,
IID_IClassFactory, (VOID **)&pCF);
if (FAILED (hr))
{
LogMessage(SVERR_ClassFactory, szObjectName, hr);
return hr;
}
pclsidEntry = (PCLSIDENTRY)DynArrayAppendElt (&m_dlCLSID);
if (NULL == pclsidEntry)
return SetErrReturn(E_OUTOFMEMORY);
pclsidEntry->clsid = clsid;
pclsidEntry->pCf = pCF;
}
// Create new class object
IITBuildCollect *pInterface;
if (FAILED (hr = pCF->CreateInstance
(NULL, IID_IITBuildCollect, (VOID **)&pInterface)))
{
LogMessage(SVERR_CreateInstance, szObjectName, hr);
return hr;
}
// Construct Storage/Stream name
WCHAR szStorage [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE + 1];
pInterface->GetTypeString(szStorage, NULL);
WSTRCAT(szStorage, szObjectName);
// Check for IPersistStorage support
IStorage *pSubStorage = NULL;
IStream *pStream = NULL;
IPersistStorage *pPersistStorage;
if (SUCCEEDED(hr = pInterface->QueryInterface
(IID_IPersistStorage, (void **)&pPersistStorage)))
{
// Create sub-storage for object persistance
if (FAILED (hr = m_piistgRoot->CreateStorage
(szStorage, STGM_READWRITE, 0, 0, &pSubStorage)))
{
pPersistStorage->Release();
return hr;
}
hr = pPersistStorage->InitNew(pSubStorage);
pPersistStorage->Release(); // Don't need to hold on to this
if (FAILED(hr))
{
LogMessage(SVERR_CreateInstance, szObjectName, hr);
pSubStorage->Release();
m_piistgRoot->DestroyElement(szStorage);
return hr;
}
}
else
{
IPersistStreamInit *pPersistStream;
if (FAILED(hr = pInterface->QueryInterface
(IID_IPersistStreamInit, (void **)&pPersistStream)))
// No IPersistX interfaces supported!
return hr;
if (FAILED (hr = m_piistgRoot->CreateStream
(szStorage, STGM_READWRITE, 0, 0, &pStream)))
{
pPersistStream->Release();
return hr;
}
hr = pPersistStream->InitNew();
pPersistStream->Release();
if (FAILED(hr))
{
pStream->Release();
m_piistgRoot->DestroyElement(szStorage);
return hr;
}
}
if (!DynArrayValid (&m_dlObjList))
// This allocates a dynamic array that can hold a
// MAXIMUM of 1000 objects
if (FALSE == DynArrayInit (&m_dlObjList,
sizeof (OBJENTRY) * 20, 50, sizeof (OBJENTRY), 0))
return SetErrReturn(E_OUTOFMEMORY);
// Create object node
// TODO: Check for duplicate entries!
POBJENTRY pObj;
pObj = (POBJENTRY)DynArrayAppendElt (&m_dlObjList);
WSTRCPY (pObj->wszObjName, szObjectName);
pObj->piitbc = pInterface;
pObj->piistg = pSubStorage;
pObj->piistm = pStream;
pObj->wszStorage = new WCHAR [WSTRLEN(szStorage) + 1];
WSTRCPY(pObj->wszStorage, szStorage);
return S_OK;
} /* CreateBuildObject */
/***************************************************************
* @method HRESULT WINAPI | IITSvMgr | GetBuildObject |
* Retrieves an object built with CreateBuildObject
*
* @parm LPCWSTR | pwstrObjectName | Name of object
* @parm REFIID | refiid | Identifier for object
* @parm void | **ppInterface | Indirect interface pointer
*
*
***************************************************************/
HRESULT WINAPI CITSvMgr::GetBuildObject
(LPCWSTR pwstrObjectName, REFIID refiid, void **ppInterface)
{
if (NULL == pwstrObjectName || NULL == ppInterface)
return E_INVALIDARG;
if (!*pwstrObjectName && refiid == IID_IITDatabase)
{ // Return the database pointer
(*((IITDatabase **)ppInterface) = m_piitdb)->AddRef();
return S_OK;
}
HRESULT hr = E_NOTEXIST;
POBJENTRY pEntry;
for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
{
if (!WSTRCMP(pEntry->wszObjName, pwstrObjectName))
{
hr = pEntry->piitbc->QueryInterface(refiid, ppInterface);
break;
}
}
return hr;
} /* GetBuildObjectInterface */
HRESULT WINAPI CITSvMgr::SetPropDest
(LPCWSTR szObjectName, LPCWSTR szDestination, IITPropList *pPropList)
{
if (FALSE == m_fInitialized)
return SetErrReturn(E_NOTINIT);
// Remove this once we support prop dest for arbitrary objects
if (szObjectName != NULL)
return SetErrReturn(E_NOTIMPL);
// Handle catalog
if (szObjectName == NULL)
{
DWORD dwSize;
if (szDestination != NULL)
return SetErrReturn(E_INVALIDARG);
if (NULL != m_pCatHeader)
return SetErrReturn(E_ALREADYINIT);
pPropList->SetPersist(STDPROP_UID, FALSE);
pPropList->GetHeaderSize (dwSize);
if (!dwSize)
// There are no document properties
return S_OK;
m_pCatHeader =
(LPBYTE)_GLOBALALLOC (GMEM_FIXED, sizeof (DWORD) + dwSize);
if (NULL == m_pCatHeader)
return SetErrReturn(E_OUTOFMEMORY);
*((LPDWORD&)m_pCatHeader) = dwSize;
pPropList->SaveHeader (m_pCatHeader + sizeof (DWORD), dwSize);
// Don't permenantly change the persist state
pPropList->SetPersist(STDPROP_UID, TRUE);
}
return S_OK;
} /* SetPropDest */
HRESULT WINAPI CITSvMgr::CatalogCompleteUpdate (void)
{
HRESULT hr;
DWORD dwSize, dwUID, dwOffset, dwLastUID;
LPSTR pInput = NULL, pCur, pEnd;
BTREE_PARAMS bp;
HBT hbt = NULL;
IStream *pDataStream = NULL;
IStorage *pStorage = NULL;
LPSTR pBin = NULL;
if (NULL == m_pCatHeader || !*m_szCatFile)
return S_OK;
CloseHandle (m_hCatFile);
m_hCatFile = NULL;
// Create sub-storage
if (FAILED (hr = m_piistgRoot->CreateStorage
(SZ_CATALOG_STORAGE, STGM_READWRITE, 0, 0, &pStorage)))
{
SetErrCode(&hr, E_FAIL);
exit0:
// Release everything
if (pBin)
delete pBin;
if (pStorage)
pStorage->Release();
if (pDataStream)
pDataStream->Release();
if (pInput)
UnmapViewOfFile (pInput);
if (hbt)
RcAbandonHbt(hbt);
DeleteFile (m_szCatFile);
_GLOBALFREE ((HANDLE)m_pCatHeader);
m_pCatHeader = NULL;
*m_szCatFile = '\0';
return hr;
}
// Create Data Stream
hr = pStorage->CreateStream
(SZ_BTREE_DATA, STGM_WRITE, 0, 0, &pDataStream);
if (FAILED(hr))
goto exit0;
if (S_OK !=(hr = FileSort
(NULL, (LPB)m_szCatFile, NULL, NULL, 0, NULL, NULL, NULL, NULL)))
{
SetErrCode(&hr, E_FAIL);
goto exit0;
}
bp.hfs = pStorage;
bp.cbBlock = 2048;
bp.bFlags = fFSReadWrite;
bp.rgchFormat[0] = KT_LONG; // UID
bp.rgchFormat[1] = '4'; // OFFSET
bp.rgchFormat[2] = '\0';
// Create BTREE
hbt = HbtInitFill(SZ_BTREE_BTREE_A, &bp, &hr);
if (hbt == hNil)
goto exit0;
pBin = new char[m_dwMaxPropSize];
// Map the temp file to memory
pInput = MapSequentialReadFile(m_szCatFile, &dwSize);
if (NULL == pInput)
{
SetErrCode(&hr, E_FAIL);
goto exit0;
}
pCur = pInput;
pEnd = pInput + dwSize;
dwOffset = 0;
dwLastUID = 0xFFFFFFFF;
while (pEnd != pCur)
{
char chTemp[9], *pchend;
chTemp[8] = '\0';
// Read in the record
MEMCPY (chTemp, pCur, 8);
dwUID = strtol(chTemp, &pchend, 16);
pCur += 8;
pCur = StringToLong (pCur, &dwSize) + 1;
BinFromHex (pCur, pBin, dwSize);
pCur += dwSize + 2;
dwSize /= 2;
if (dwUID != dwLastUID)
{
if (FAILED (hr = RcFillHbt(hbt,(KEY)&dwUID,(QV)&dwOffset)))
{
delete pBin;
goto exit0;
}
hr = pDataStream->Write (&dwSize, sizeof (DWORD), NULL);
if (FAILED(hr))
goto exit0;
if (FAILED (hr = pDataStream->Write (pBin, dwSize, NULL)))
goto exit0;
dwLastUID = dwUID;
}
else
{ // What to do with duplicates?
// For now, we skip them
}
dwOffset += dwSize + sizeof (DWORD);
}
hr = RcFiniFillHbt(hbt);
if (FAILED(hr))
goto exit0;
if (S_OK !=(hr = RcCloseBtreeHbt(hbt)))
goto exit0;
hbt = NULL;
// Create and write header
IStream *pStream;
hr = pStorage->CreateStream (SZ_BTREE_HEADER, STGM_WRITE, 0, 0, &pStream);
if (FAILED(hr))
goto exit0;
hr = pStream->Write (m_pCatHeader, sizeof (DWORD), NULL);
if (FAILED (hr))
{
pStream->Release();
goto exit0;
}
hr = pStream->Write (m_pCatHeader + sizeof (DWORD),
*((LPDWORD&)m_pCatHeader), NULL);
pStream->Release();
if (FAILED (hr))
goto exit0;
hr = S_OK;
goto exit0;
} /* CatalogCompleteUpdate */
HRESULT WINAPI CITSvMgr::CatalogSetEntry (IITPropList *pPropList, DWORD dwFlags)
{
HRESULT hr;
DWORD dwUID, dwTemp, dwDataSize;
CProperty CProp;
char szTemp[1025];
if (FAILED(hr = pPropList->Get(STDPROP_UID, CProp)))
return SetErrReturn(E_MISSINGPROP);
// This could be a pointer to a UID or a DWORD UID
if (TYPE_VALUE == CProp.dwType)
dwUID = CProp.dwValue;
else if (TYPE_POINTER == CProp.dwType)
dwUID = *((LPDWORD&)CProp.lpvData);
// Allocate memory if we need to
if (NULL == m_pCatHeader)
{
pPropList->SetPersist(STDPROP_UID, FALSE);
pPropList->GetHeaderSize (dwTemp);
if (!dwTemp)
// There are no document properties
return S_OK;
m_pCatHeader =
(LPBYTE)_GLOBALALLOC (GMEM_FIXED, sizeof (DWORD) + dwTemp);
if (NULL == m_pCatHeader)
return SetErrReturn(E_OUTOFMEMORY);
*((LPDWORD&)m_pCatHeader) = dwTemp;
pPropList->SaveHeader (m_pCatHeader + sizeof (DWORD), dwTemp);
// Don't permenantly change the persist state
pPropList->SetPersist(STDPROP_UID, TRUE);
}
hr = pPropList->GetDataSize (m_pCatHeader + sizeof (DWORD),
*((LPDWORD&)m_pCatHeader), dwDataSize);
// Returns S_FALSE if no records to write (still writes empty bit flags)
if (S_FALSE == hr || !dwDataSize)
return S_OK;
if ('\0' == *m_szCatFile)
{
// Create the temp file
char szTempPath[_MAX_PATH + 1];
if (0 == GetTempPath(_MAX_PATH, szTempPath))
return SetErrReturn(E_FILECREATE);
if (0 == GetTempFileName(szTempPath, "CAT", 0, m_szCatFile))
return SetErrReturn(E_FILECREATE);
m_hCatFile = CreateFile
(m_szCatFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == m_hCatFile)
return SetErrReturn(E_FILECREATE);
}
LPBYTE pData;
LPSTR pHex;
pPropList->GetDataSize (m_pCatHeader + sizeof (DWORD),
*((LPDWORD&)m_pCatHeader), dwDataSize);
pData = new BYTE[dwDataSize];
pHex = new char[dwDataSize * 2];
if (dwDataSize > m_dwMaxPropSize)
m_dwMaxPropSize = dwDataSize;
pPropList->SaveData (m_pCatHeader + sizeof (DWORD),
*((LPDWORD&)m_pCatHeader), pData, dwDataSize);
HexFromBin (pHex, pData, dwDataSize);
dwDataSize *= 2;
wsprintf (szTemp, "%08X%u:", dwUID, dwDataSize);
WriteFile (m_hCatFile, szTemp, (DWORD) STRLEN (szTemp), &dwTemp, NULL);
WriteFile (m_hCatFile, pHex, dwDataSize, &dwTemp, NULL);
WriteFile (m_hCatFile, "\r\n", (DWORD) STRLEN ("\r\n"), &dwTemp, NULL);
delete pData;
delete pHex;
return S_OK;
} /* CatalogSetEntry */
/*******************************************************************
*
* @method HRESULT WINAPI | IITSvMgr | HashString |
* Returns a hashed DWORD value for an input string.
* This method is an optional advanced feature, and is
* not necessary to build any object.
*
* @parm LPCWSTR | szKey | String to convert
* @parm DWORD | *pdwHash | Hashed value of string
*
* @rvalue S_OK | The operation completed successfully.
*
* @comm
* This method takes a string, and returns a hashed DWORD value.
* For example, this method allows you to use hashstring values
* as UIDs. It provides a unique value based on a title, for example.
*
* @comm Using the hash value as a UID in groups
* can cause inefficiencies due to memory considerations
* (non-sequential UIDs are more difficult to store).
*
*
********************************************************************/
HRESULT WINAPI CITSvMgr::HashString (LPCWSTR szKey, DWORD *pdwHash)
{
int ich, cch;
DWORD hash = 0L;
const int MAX_CHARS = 43;
*pdwHash = 0L;
cch = (int) WSTRLEN (szKey);
// The following is used to generate a hash value for structured
// "ascii hex" context strings. If a title's context strings use
// the format "0xHHHHHHHH", where H is a valid hex digit, then
// this algorithm replaces the standard hash algorithm. This is so
// title's can determined a context string from a given hash value.
if ( szKey[0] == L'0' && szKey[1] == L'x' && (cch == 10) )
{
WCHAR c;
for( ich = 0; ich < cch; ++ich )
{
c = szKey[ich];
hash <<= 4;
hash += (c & 0x10 ? c : (c + 9)) & 0x0f;
}
*pdwHash = hash;
return S_OK;
}
for ( ich = 0; ich < cch; ++ich )
{
if ( szKey[ich] == L'!' )
hash = (hash * MAX_CHARS) + 11;
else if ( szKey[ich] == L'.' )
hash = (hash * MAX_CHARS) + 12;
else if ( szKey[ich] == L'_' )
hash = (hash * MAX_CHARS) + 13;
else if ( szKey[ich] == L'0' )
hash = (hash * MAX_CHARS) + 10;
else if ( szKey[ich] <= L'Z' )
hash = (hash * MAX_CHARS) + ( szKey[ich] - L'0' );
else
hash = (hash * MAX_CHARS) + ( szKey[ich] - 'L0' - (L'a' - L'A') );
}
/* Since the value hashNil is reserved as a nil value, if any context
* string actually hashes to this value, we just move it.
*/
*pdwHash = (hash == hashNil ? hashNil + 1 : hash);
return S_OK;
} /* CITSvMgr::HashString */
HRESULT WINAPI CITSvMgr::LogMessage(DWORD dwResourceId, ...)
{
if (!m_fInitialized || !m_piistmLog)
return S_FALSE;
char rgchLocalBuf[1024];
char rgchFormatBuf[1024];
if (LoadString (_hInstITCC, dwResourceId,
rgchFormatBuf, 1024 * sizeof (char)))
{
va_list vl;
va_start(vl, dwResourceId);
int arg1 = va_arg(vl, int);
int arg2 = va_arg(vl, int);
int arg3 = va_arg(vl, int);
va_end(vl);
wsprintf (rgchLocalBuf, rgchFormatBuf, arg1, arg2, arg3);
}
else
STRCPY(rgchLocalBuf, "Error string could not be loaded from resource file.");
m_piistmLog->Write(rgchLocalBuf, (DWORD) STRLEN (rgchLocalBuf), NULL);
m_piistmLog->Write (".\r\n", (DWORD) STRLEN (".\r\n"), NULL);
return S_OK;
} /* LogMessage */