Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1104 lines
33 KiB

  1. /*************************************************************************
  2. * @doc SHROOM EXTERNAL API *
  3. * *
  4. * SVMGR.C *
  5. * *
  6. * Copyright (C) Microsoft Corporation 1995-1997 *
  7. * All Rights reserved. *
  8. * *
  9. * The Service Manager is responsible for reading the object description *
  10. * from the command interpreter, getting object properties and data, and *
  11. * building the objects. *
  12. * *
  13. **************************************************************************
  14. * *
  15. * Written By : John Rush *
  16. * Current Owner: johnrush *
  17. * *
  18. **************************************************************************/
  19. #include <verstamp.h>
  20. SETVERSIONSTAMP(MVSV);
  21. #include <mvopsys.h>
  22. #ifdef _DEBUG
  23. static char s_aszModule[] = __FILE__; /* For error report */
  24. #endif
  25. #include <windows.h>
  26. #ifdef IA64
  27. #include <itdfguid.h>
  28. #endif
  29. #include <iterror.h>
  30. #include <orkin.h>
  31. #include <wrapstor.h>
  32. #include <_mvutil.h>
  33. #include <mvsearch.h>
  34. #include <dynarray.h>
  35. #include <groups.h>
  36. #include <itwbrk.h>
  37. #include <itwbrkid.h>
  38. #include <ccfiles.h>
  39. #include <itdb.h>
  40. #include <itsortid.h>
  41. #include <itgroup.h>
  42. #include "itsvmgr.h"
  43. #include "svutil.h"
  44. #include "svdoc.h"
  45. #include "iterr.h"
  46. extern HINSTANCE _hInstITCC;
  47. CITSvMgr::CITSvMgr(void)
  48. {
  49. m_fInitialized = FALSE;
  50. m_piistmLog = NULL;
  51. }
  52. CITSvMgr::~CITSvMgr(void)
  53. {
  54. if (m_fInitialized)
  55. Dispose();
  56. }
  57. /********************************************************************
  58. * @method HRESULT WINAPI | IITSvMgr | Initiate |
  59. * Creates and initiates a structure containing
  60. * data necessary for future service requests.
  61. *
  62. * @parm IStorage * | pStorage |
  63. * Pointer to destination IStorage. In most cases, this
  64. * is the ITSS IStorage file.
  65. *
  66. * @parm IStream * | piistmLog |
  67. * Optional IStream to log error messages.
  68. *
  69. * @rvalue S_OK | The service manager was initialized successfully
  70. * @rvalue E_INVALIDARG | One of the required arguments was NULL or otherwise not valid
  71. * @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
  72. *
  73. * @xref <om.LoadFromStream>
  74. *
  75. * @comm This should be the first method called for the service manager.
  76. ********************************************************************/
  77. HRESULT WINAPI CITSvMgr::Initiate
  78. (IStorage *piistgStorage, IStream *piistmLog)
  79. {
  80. HRESULT hResult = S_OK;
  81. if (m_fInitialized)
  82. return SetErrReturn(E_ALREADYINIT);
  83. if (NULL == piistgStorage)
  84. return SetErrReturn(E_INVALIDARG);
  85. if(m_piistmLog = piistmLog)
  86. m_piistmLog->AddRef();
  87. m_pPLDocunent = NULL;
  88. m_pCatHeader = NULL;
  89. m_dwMaxPropSize = 0;
  90. *m_szCatFile = '\0';
  91. m_piitdb = NULL;
  92. m_pipstgDatabase = NULL;
  93. m_dwMaxUID = 0;
  94. hResult = (m_piistgRoot = piistgStorage)->AddRef();
  95. if (SUCCEEDED(hResult))
  96. {
  97. ZeroMemory (&m_dlCLSID, sizeof (DL));
  98. ZeroMemory (&m_dlObjList, sizeof (DL));
  99. // Create database
  100. if (SUCCEEDED(hResult = CoCreateInstance(CLSID_IITDatabaseLocal, NULL,
  101. CLSCTX_INPROC_SERVER, IID_IITDatabase, (void **)&m_piitdb))
  102. &&
  103. SUCCEEDED(hResult = m_piitdb->QueryInterface
  104. (IID_IPersistStorage, (void **)&m_pipstgDatabase)))
  105. {
  106. if (FAILED(hResult = m_pipstgDatabase->InitNew(piistgStorage)))
  107. LogMessage(SVERR_InitNew, "IITDatabase", hResult);
  108. }
  109. }
  110. if (FAILED(hResult))
  111. {
  112. if (m_piistgRoot)
  113. m_piistgRoot->Release();
  114. piistgStorage->Release();
  115. if (m_piitdb)
  116. {
  117. m_piitdb->Release();
  118. m_piitdb = NULL;
  119. }
  120. if (m_pipstgDatabase)
  121. {
  122. m_pipstgDatabase->Release();
  123. m_pipstgDatabase = NULL;
  124. }
  125. } else
  126. m_fInitialized = TRUE;
  127. return (hResult);
  128. } /* SVInitiate */
  129. /********************************************************************
  130. * @method HRESULT WINAPI | IITSvMgr | Dispose |
  131. *
  132. * Signal that all services are no longer needed, causing any resources
  133. * allocated during use of the service manager to be freed.
  134. *
  135. * @rvalue S_OK | All resources freed successfully
  136. *
  137. * @xref <om.Initiate>
  138. *
  139. * @comm This should be the last method called for the service manager.
  140. ********************************************************************/
  141. HRESULT WINAPI CITSvMgr::Dispose ()
  142. {
  143. if (FALSE == m_fInitialized)
  144. return SetErrReturn(E_NOTINIT);
  145. if (m_pPLDocunent)
  146. {
  147. m_pPLDocunent->Release();
  148. m_pPLDocunent = NULL;
  149. }
  150. // Destroy catalog
  151. if (*m_szCatFile)
  152. {
  153. CloseHandle (m_hCatFile);
  154. DeleteFile (m_szCatFile);
  155. }
  156. if (m_pCatHeader)
  157. {
  158. _GLOBALFREE ((HANDLE)m_pCatHeader);
  159. m_pCatHeader = NULL;
  160. *m_szCatFile = '\0';
  161. }
  162. m_piitdb->Release();
  163. m_pipstgDatabase->Release();
  164. m_piistgRoot->Release();
  165. if(m_piistmLog)
  166. m_piistmLog->Release();
  167. if (DynArrayValid (&m_dlCLSID))
  168. {
  169. PCLSIDENTRY pEntry;
  170. for (pEntry = (PCLSIDENTRY)DynArrayGetFirstElt (&m_dlCLSID);
  171. pEntry; pEntry = (PCLSIDENTRY)DynArrayNextElt (&m_dlCLSID))
  172. {
  173. pEntry->pCf->Release();
  174. }
  175. DynArrayFree (&m_dlCLSID);
  176. }
  177. if (DynArrayValid (&m_dlObjList))
  178. {
  179. POBJENTRY pEntry;
  180. for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
  181. pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
  182. {
  183. if (pEntry->piitbc)
  184. {
  185. pEntry->piitbc->Release();
  186. pEntry->piitbc = NULL;
  187. if (pEntry->piistg)
  188. {
  189. pEntry->piistg->Commit(STGC_DEFAULT);
  190. pEntry->piistg->Release();
  191. } else if (pEntry->piistm)
  192. pEntry->piistm->Release();
  193. #ifdef _DEBUG
  194. pEntry->piistg = NULL;
  195. pEntry->piistm = NULL;
  196. #endif
  197. }
  198. delete pEntry->wszStorage;
  199. }
  200. DynArrayFree (&m_dlObjList);
  201. }
  202. m_fInitialized = FALSE;
  203. return S_OK;
  204. } /* Dispose */
  205. /********************************************************************
  206. * @method HRESULT WINAPI | IITSvMgr | AddDocument |
  207. * Adds the authored properties and indexable content that were added to the
  208. * given document template into the service manager's build process. Once
  209. * AddDocument is called, the data will included in the pending
  210. * Build() operation.
  211. *
  212. * @parm CSvDoc *| pDoc | Pointer to document template containing the
  213. * content and properties for the current document.
  214. *
  215. * @rvalue S_OK | The properties and content were added successfully
  216. * @rvalue E_MISSINGPROP | The document did not have one of the mandatory properties.
  217. * Currently, the only required property is STDPROP_UID.
  218. *
  219. * @rvalue E_INVALIDARG | One of the required arguments was NULL or otherwise not valid
  220. * @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
  221. *
  222. * @xref <om.AddObjectEntry>
  223. * @xref <om.Build>
  224. *
  225. * @comm
  226. ********************************************************************/
  227. HRESULT WINAPI CITSvMgr::AddDocument (CSvDoc *lpDoc)
  228. {
  229. WCHAR *lpch;
  230. HRESULT hr;
  231. DWORD cbData;
  232. CSvDocInternal *pDoc = (CSvDocInternal *)lpDoc;
  233. if (FALSE == m_fInitialized)
  234. return SetErrReturn(E_NOTINIT);
  235. if (NULL == pDoc)
  236. return SetErrReturn(E_INVALIDARG);
  237. // Suck in the document properties from the batch buffer
  238. if (!pDoc->m_lpbfDoc)
  239. return SetErrReturn(E_MISSINGPROP);
  240. // Create property list
  241. if (m_pPLDocunent == NULL)
  242. {
  243. hr = CoCreateInstance (CLSID_IITPropList, NULL,
  244. CLSCTX_INPROC_SERVER, IID_IITPropList, (LPVOID *)&m_pPLDocunent);
  245. if (FAILED (hr))
  246. {
  247. LogMessage(SVERR_CoCreateInstance, "IID_IITPropList", hr);
  248. return SetErrReturn(hr);
  249. }
  250. }
  251. else
  252. m_pPLDocunent->Clear();
  253. // Get the property list for the document
  254. cbData = *(LPDWORD)DynBufferPtr (pDoc->m_lpbfDoc);
  255. m_pPLDocunent->LoadFromMem (DynBufferPtr (pDoc->m_lpbfDoc) + sizeof (DWORD), cbData);
  256. // Get the UID for the document
  257. CProperty UidProp;
  258. if (FAILED(hr = m_pPLDocunent->Get(STDPROP_UID, UidProp))
  259. || TYPE_STRING == UidProp.dwType)
  260. {
  261. LogMessage(SVERR_NoUID);
  262. return SetErrReturn(E_MISSINGPROP);
  263. }
  264. // This could be a pointer to a UID or a DWORD UID
  265. if (TYPE_VALUE == UidProp.dwType)
  266. pDoc->m_dwUID = UidProp.dwValue;
  267. else if (TYPE_POINTER == UidProp.dwType)
  268. pDoc->m_dwUID = *((LPDWORD&)UidProp.lpvData);
  269. if (m_dwMaxUID < pDoc->m_dwUID)
  270. m_dwMaxUID = pDoc->m_dwUID;
  271. if (cbData)
  272. CatalogSetEntry (m_pPLDocunent, 0);
  273. // Now scan through the batch entry buffer. For each object, farm out the
  274. // persisted property values to that object.
  275. if (!pDoc->m_lpbfEntry || !DynBufferLen (pDoc->m_lpbfEntry))
  276. return S_OK;
  277. // Ensure the buffer is terminated with zero marker
  278. cbData = 0;
  279. if (!DynBufferAppend (pDoc->m_lpbfEntry, (LPBYTE)&cbData, sizeof (DWORD)))
  280. return SetErrReturn(E_OUTOFMEMORY);
  281. // Work through all the property lists
  282. for (lpch = (WCHAR *) DynBufferPtr(pDoc->m_lpbfEntry); lpch;)
  283. {
  284. WCHAR szObject[MAX_OBJECT_NAME];
  285. WCHAR szPropDest[MAX_OBJECT_NAME];
  286. m_pPLDocunent->Clear();
  287. // found zero marker instead of name
  288. if (*(LPDWORD)lpch == 0L)
  289. break;
  290. // read the object name
  291. WSTRCPY(szObject, lpch);
  292. lpch += WSTRLEN(szObject) + 1;
  293. // read the property destination
  294. WSTRCPY(szPropDest, lpch);
  295. lpch += WSTRLEN(szPropDest) + 1;
  296. cbData = *(LPDWORD)lpch;
  297. ((LPBYTE&)lpch) += sizeof(DWORD);
  298. m_pPLDocunent->LoadFromMem (lpch, cbData);
  299. ((LPBYTE&)lpch) += cbData;
  300. // we now have a property list, examine the object type and pass to the
  301. // lower level build routines.
  302. POBJENTRY pEntry;
  303. for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
  304. pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
  305. {
  306. if (!WSTRICMP (szObject, pEntry->wszObjName) && pEntry->piitbc)
  307. {
  308. hr = pEntry->piitbc->SetEntry
  309. (*szPropDest ? szPropDest : NULL, m_pPLDocunent);
  310. if (FAILED (hr))
  311. {
  312. LogMessage(SVERR_SetEntry, pEntry->wszObjName, hr);
  313. pEntry->piitbc->Close();
  314. pEntry->piitbc->Release();
  315. pEntry->piitbc = NULL;
  316. if (pEntry->piistg)
  317. pEntry->piistg->Release();
  318. else if (pEntry->piistm)
  319. pEntry->piistm->Release();
  320. #ifdef _DEBUG
  321. pEntry->piistg = NULL;
  322. pEntry->piistm = NULL;
  323. #endif
  324. m_piistgRoot->DestroyElement (pEntry->wszStorage);
  325. }
  326. break;
  327. }
  328. }
  329. // UNDONE: document catalog build (titles and other custom doc properties)
  330. }
  331. return S_OK;
  332. } /* AddDocument */
  333. /********************************************************************
  334. * @method HRESULT WINAPI | IITSvMgr | Build |
  335. * Takes the data accumulated during AddDocument calls and completes the
  336. * creation of the objects that were requested in the original command
  337. * interpreter description.
  338. *
  339. * @rvalue S_OK | All requested objects, such as wordwheels, and full-text
  340. * index, were built successfully and added to the output storage.
  341. *
  342. * @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
  343. *
  344. * @xref <om.AddObjectEntry>
  345. * @xref <om.AddDocument>
  346. *
  347. * @comm
  348. ********************************************************************/
  349. HRESULT WINAPI CITSvMgr::Build ()
  350. {
  351. HRESULT hr = S_OK;
  352. ITBuildObjectControlInfo itboci = {sizeof (itboci), m_dwMaxUID};
  353. if (FALSE == m_fInitialized)
  354. return SetErrReturn(E_NOTINIT);
  355. // Handle Document Catalog
  356. hr = CatalogCompleteUpdate();
  357. // Save all breaker and sort instance data to the storage
  358. if (SUCCEEDED(hr))
  359. {
  360. if (FAILED(hr = m_pipstgDatabase->Save(m_piistgRoot, TRUE)))
  361. LogMessage(SVERR_DatabaseSave, hr);
  362. }
  363. if (SUCCEEDED(hr) && DynArrayValid (&m_dlObjList))
  364. {
  365. // Build objects
  366. for (POBJENTRY pObj = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
  367. pObj; pObj = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
  368. {
  369. if (NULL == pObj->piitbc)
  370. continue;
  371. hr = pObj->piitbc->SetBuildStats(itboci);
  372. if (FAILED(hr) && hr != E_NOTIMPL)
  373. {
  374. ;// LogMessage();
  375. continue;
  376. }
  377. if (pObj->piistg)
  378. {
  379. // Must support IPersistStorage
  380. IPersistStorage *pPersistStorage;
  381. if (FAILED(hr = pObj->piitbc->QueryInterface
  382. (IID_IPersistStorage, (void **)&pPersistStorage)))
  383. {
  384. ITASSERT(0); // We shoulnd't ever hit this condition!
  385. continue;
  386. }
  387. if(FAILED(hr = pPersistStorage->Save(pObj->piistg, TRUE)))
  388. LogMessage(SVERR_IPSTGSave, pObj->wszObjName, hr);
  389. pPersistStorage->Release();
  390. pObj->piistg->Commit(STGC_DEFAULT);
  391. pObj->piistg->Release();
  392. }
  393. else if (pObj->piistm)
  394. {
  395. // Must support IPersistStream then
  396. IPersistStreamInit *pPersistStream;
  397. if (FAILED(hr = pObj->piitbc->QueryInterface
  398. (IID_IPersistStreamInit, (void **)&pPersistStream)))
  399. {
  400. ITASSERT(0); // We shoulnd't ever hit this condition!
  401. continue;
  402. }
  403. if(FAILED(hr = pPersistStream->Save(pObj->piistm, TRUE)))
  404. LogMessage(SVERR_IPSTMSave, pObj->wszObjName, hr);
  405. pPersistStream->Release();
  406. pObj->piistm->Release();
  407. #ifdef _DEBUG
  408. pObj->piistm = NULL;
  409. #endif
  410. }
  411. // What's the deal??? We checked for these earlier!
  412. else ITASSERT(0);
  413. if (FAILED (hr))
  414. m_piistgRoot->DestroyElement (pObj->wszStorage);
  415. pObj->piitbc->Release();
  416. pObj->piitbc = NULL;
  417. }
  418. hr = S_OK; // We don't return componenet build errors
  419. }
  420. LogMessage(SV_BuildComplete);
  421. return hr;
  422. } /* Build */
  423. /********************************************************************
  424. * @method HRESULT WINAPI | IITSvMgr | CreateDocTemplate |
  425. * Returns a popinter to a CSVDoc class which can be sent to AddDocument.
  426. * Pass this pointer to FreeDocTemplate when you no longer need it.
  427. *
  428. * @rvalue S_OK | The CSvDoc object was succesfully created.
  429. *
  430. * @rvalue E_OUTOFMEMORY | Some resources needed by the service manager could not be allocated
  431. *
  432. * @xref <om.AddObjectEntry>
  433. * @xref <om.AddDocument>
  434. * @xref <om.FreeDocTemplate>
  435. *
  436. *
  437. ********************************************************************/
  438. HRESULT WINAPI CITSvMgr::CreateDocTemplate (CSvDoc **pDoc)
  439. {
  440. *pDoc = new CSvDocInternal;
  441. if (*pDoc)
  442. return S_OK;
  443. return SetErrReturn(E_OUTOFMEMORY);
  444. } /* CreateDocTemplate */
  445. /********************************************************************
  446. * @method HRESULT WINAPI | IITSvMgr | FreeDocTemplate |
  447. * Frees a CSvDoc class returned from CreateDocTemplate.
  448. *
  449. * @rvalue E_INVALIDARG | Thie CSvDoc pointer is NULL.
  450. * @rvalue S_OK | The CSvDoc object was freed.
  451. *
  452. * @xref <om.CreateDocTemplate>
  453. *
  454. *
  455. ********************************************************************/
  456. HRESULT WINAPI CITSvMgr::FreeDocTemplate (CSvDoc *pDoc)
  457. {
  458. if (NULL == pDoc)
  459. return SetErrReturn(E_INVALIDARG);
  460. delete (CSvDocInternal *)pDoc;
  461. return S_OK;
  462. } /* FreeDocTemplate */
  463. /********************************************************************
  464. * @method HRESULT WINAPI | IITSvMgr | CreateBuildObject|
  465. * Creates a build object.
  466. *
  467. * @parm LPCWSTR | szObjectName | Name of object to create.
  468. * @parm REFCLSID | clsid |Class ID of object.
  469. *
  470. * @rvalue S_OK | The operation completed successfully.
  471. * @rvalue E_INVALIDARG | The argument was not valid
  472. *
  473. ********************************************************************/
  474. HRESULT WINAPI CITSvMgr::CreateBuildObject(LPCWSTR szObjectName, REFCLSID clsid)
  475. {
  476. HRESULT hr;
  477. if (FALSE == m_fInitialized)
  478. return SetErrReturn(E_NOTINIT);
  479. if (NULL == szObjectName)
  480. return SetErrReturn(E_INVALIDARG);
  481. if (!DynArrayValid (&m_dlCLSID))
  482. // This allocates a dynamic array that can hold a
  483. // MAXIMUM of 500 unique classes
  484. if (FALSE == DynArrayInit (&m_dlCLSID,
  485. sizeof (CLSIDENTRY) * 5, 100, sizeof (CLSIDENTRY), 0))
  486. return SetErrReturn(E_OUTOFMEMORY);
  487. // Is this entry already in the list?
  488. PCLSIDENTRY pclsidEntry;
  489. IClassFactory *pCF;
  490. for (pclsidEntry = (PCLSIDENTRY)DynArrayGetFirstElt (&m_dlCLSID);
  491. pclsidEntry; pclsidEntry = (PCLSIDENTRY)DynArrayNextElt (&m_dlCLSID))
  492. {
  493. if (clsid == pclsidEntry->clsid)
  494. {
  495. pCF = pclsidEntry->pCf;
  496. break;
  497. }
  498. }
  499. // Create new class factory
  500. if (NULL == pclsidEntry)
  501. {
  502. hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL,
  503. IID_IClassFactory, (VOID **)&pCF);
  504. if (FAILED (hr))
  505. {
  506. LogMessage(SVERR_ClassFactory, szObjectName, hr);
  507. return hr;
  508. }
  509. pclsidEntry = (PCLSIDENTRY)DynArrayAppendElt (&m_dlCLSID);
  510. if (NULL == pclsidEntry)
  511. return SetErrReturn(E_OUTOFMEMORY);
  512. pclsidEntry->clsid = clsid;
  513. pclsidEntry->pCf = pCF;
  514. }
  515. // Create new class object
  516. IITBuildCollect *pInterface;
  517. if (FAILED (hr = pCF->CreateInstance
  518. (NULL, IID_IITBuildCollect, (VOID **)&pInterface)))
  519. {
  520. LogMessage(SVERR_CreateInstance, szObjectName, hr);
  521. return hr;
  522. }
  523. // Construct Storage/Stream name
  524. WCHAR szStorage [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE + 1];
  525. pInterface->GetTypeString(szStorage, NULL);
  526. WSTRCAT(szStorage, szObjectName);
  527. // Check for IPersistStorage support
  528. IStorage *pSubStorage = NULL;
  529. IStream *pStream = NULL;
  530. IPersistStorage *pPersistStorage;
  531. if (SUCCEEDED(hr = pInterface->QueryInterface
  532. (IID_IPersistStorage, (void **)&pPersistStorage)))
  533. {
  534. // Create sub-storage for object persistance
  535. if (FAILED (hr = m_piistgRoot->CreateStorage
  536. (szStorage, STGM_READWRITE, 0, 0, &pSubStorage)))
  537. {
  538. pPersistStorage->Release();
  539. return hr;
  540. }
  541. hr = pPersistStorage->InitNew(pSubStorage);
  542. pPersistStorage->Release(); // Don't need to hold on to this
  543. if (FAILED(hr))
  544. {
  545. LogMessage(SVERR_CreateInstance, szObjectName, hr);
  546. pSubStorage->Release();
  547. m_piistgRoot->DestroyElement(szStorage);
  548. return hr;
  549. }
  550. }
  551. else
  552. {
  553. IPersistStreamInit *pPersistStream;
  554. if (FAILED(hr = pInterface->QueryInterface
  555. (IID_IPersistStreamInit, (void **)&pPersistStream)))
  556. // No IPersistX interfaces supported!
  557. return hr;
  558. if (FAILED (hr = m_piistgRoot->CreateStream
  559. (szStorage, STGM_READWRITE, 0, 0, &pStream)))
  560. {
  561. pPersistStream->Release();
  562. return hr;
  563. }
  564. hr = pPersistStream->InitNew();
  565. pPersistStream->Release();
  566. if (FAILED(hr))
  567. {
  568. pStream->Release();
  569. m_piistgRoot->DestroyElement(szStorage);
  570. return hr;
  571. }
  572. }
  573. if (!DynArrayValid (&m_dlObjList))
  574. // This allocates a dynamic array that can hold a
  575. // MAXIMUM of 1000 objects
  576. if (FALSE == DynArrayInit (&m_dlObjList,
  577. sizeof (OBJENTRY) * 20, 50, sizeof (OBJENTRY), 0))
  578. return SetErrReturn(E_OUTOFMEMORY);
  579. // Create object node
  580. // TODO: Check for duplicate entries!
  581. POBJENTRY pObj;
  582. pObj = (POBJENTRY)DynArrayAppendElt (&m_dlObjList);
  583. WSTRCPY (pObj->wszObjName, szObjectName);
  584. pObj->piitbc = pInterface;
  585. pObj->piistg = pSubStorage;
  586. pObj->piistm = pStream;
  587. pObj->wszStorage = new WCHAR [WSTRLEN(szStorage) + 1];
  588. WSTRCPY(pObj->wszStorage, szStorage);
  589. return S_OK;
  590. } /* CreateBuildObject */
  591. /***************************************************************
  592. * @method HRESULT WINAPI | IITSvMgr | GetBuildObject |
  593. * Retrieves an object built with CreateBuildObject
  594. *
  595. * @parm LPCWSTR | pwstrObjectName | Name of object
  596. * @parm REFIID | refiid | Identifier for object
  597. * @parm void | **ppInterface | Indirect interface pointer
  598. *
  599. *
  600. ***************************************************************/
  601. HRESULT WINAPI CITSvMgr::GetBuildObject
  602. (LPCWSTR pwstrObjectName, REFIID refiid, void **ppInterface)
  603. {
  604. if (NULL == pwstrObjectName || NULL == ppInterface)
  605. return E_INVALIDARG;
  606. if (!*pwstrObjectName && refiid == IID_IITDatabase)
  607. { // Return the database pointer
  608. (*((IITDatabase **)ppInterface) = m_piitdb)->AddRef();
  609. return S_OK;
  610. }
  611. HRESULT hr = E_NOTEXIST;
  612. POBJENTRY pEntry;
  613. for (pEntry = (POBJENTRY)DynArrayGetFirstElt (&m_dlObjList);
  614. pEntry; pEntry = (POBJENTRY)DynArrayNextElt (&m_dlObjList))
  615. {
  616. if (!WSTRCMP(pEntry->wszObjName, pwstrObjectName))
  617. {
  618. hr = pEntry->piitbc->QueryInterface(refiid, ppInterface);
  619. break;
  620. }
  621. }
  622. return hr;
  623. } /* GetBuildObjectInterface */
  624. HRESULT WINAPI CITSvMgr::SetPropDest
  625. (LPCWSTR szObjectName, LPCWSTR szDestination, IITPropList *pPropList)
  626. {
  627. if (FALSE == m_fInitialized)
  628. return SetErrReturn(E_NOTINIT);
  629. // Remove this once we support prop dest for arbitrary objects
  630. if (szObjectName != NULL)
  631. return SetErrReturn(E_NOTIMPL);
  632. // Handle catalog
  633. if (szObjectName == NULL)
  634. {
  635. DWORD dwSize;
  636. if (szDestination != NULL)
  637. return SetErrReturn(E_INVALIDARG);
  638. if (NULL != m_pCatHeader)
  639. return SetErrReturn(E_ALREADYINIT);
  640. pPropList->SetPersist(STDPROP_UID, FALSE);
  641. pPropList->GetHeaderSize (dwSize);
  642. if (!dwSize)
  643. // There are no document properties
  644. return S_OK;
  645. m_pCatHeader =
  646. (LPBYTE)_GLOBALALLOC (GMEM_FIXED, sizeof (DWORD) + dwSize);
  647. if (NULL == m_pCatHeader)
  648. return SetErrReturn(E_OUTOFMEMORY);
  649. *((LPDWORD&)m_pCatHeader) = dwSize;
  650. pPropList->SaveHeader (m_pCatHeader + sizeof (DWORD), dwSize);
  651. // Don't permenantly change the persist state
  652. pPropList->SetPersist(STDPROP_UID, TRUE);
  653. }
  654. return S_OK;
  655. } /* SetPropDest */
  656. HRESULT WINAPI CITSvMgr::CatalogCompleteUpdate (void)
  657. {
  658. HRESULT hr;
  659. DWORD dwSize, dwUID, dwOffset, dwLastUID;
  660. LPSTR pInput = NULL, pCur, pEnd;
  661. BTREE_PARAMS bp;
  662. HBT hbt = NULL;
  663. IStream *pDataStream = NULL;
  664. IStorage *pStorage = NULL;
  665. LPSTR pBin = NULL;
  666. if (NULL == m_pCatHeader || !*m_szCatFile)
  667. return S_OK;
  668. CloseHandle (m_hCatFile);
  669. m_hCatFile = NULL;
  670. // Create sub-storage
  671. if (FAILED (hr = m_piistgRoot->CreateStorage
  672. (SZ_CATALOG_STORAGE, STGM_READWRITE, 0, 0, &pStorage)))
  673. {
  674. SetErrCode(&hr, E_FAIL);
  675. exit0:
  676. // Release everything
  677. if (pBin)
  678. delete pBin;
  679. if (pStorage)
  680. pStorage->Release();
  681. if (pDataStream)
  682. pDataStream->Release();
  683. if (pInput)
  684. UnmapViewOfFile (pInput);
  685. if (hbt)
  686. RcAbandonHbt(hbt);
  687. DeleteFile (m_szCatFile);
  688. _GLOBALFREE ((HANDLE)m_pCatHeader);
  689. m_pCatHeader = NULL;
  690. *m_szCatFile = '\0';
  691. return hr;
  692. }
  693. // Create Data Stream
  694. hr = pStorage->CreateStream
  695. (SZ_BTREE_DATA, STGM_WRITE, 0, 0, &pDataStream);
  696. if (FAILED(hr))
  697. goto exit0;
  698. if (S_OK !=(hr = FileSort
  699. (NULL, (LPB)m_szCatFile, NULL, NULL, 0, NULL, NULL, NULL, NULL)))
  700. {
  701. SetErrCode(&hr, E_FAIL);
  702. goto exit0;
  703. }
  704. bp.hfs = pStorage;
  705. bp.cbBlock = 2048;
  706. bp.bFlags = fFSReadWrite;
  707. bp.rgchFormat[0] = KT_LONG; // UID
  708. bp.rgchFormat[1] = '4'; // OFFSET
  709. bp.rgchFormat[2] = '\0';
  710. // Create BTREE
  711. hbt = HbtInitFill(SZ_BTREE_BTREE_A, &bp, &hr);
  712. if (hbt == hNil)
  713. goto exit0;
  714. pBin = new char[m_dwMaxPropSize];
  715. // Map the temp file to memory
  716. pInput = MapSequentialReadFile(m_szCatFile, &dwSize);
  717. if (NULL == pInput)
  718. {
  719. SetErrCode(&hr, E_FAIL);
  720. goto exit0;
  721. }
  722. pCur = pInput;
  723. pEnd = pInput + dwSize;
  724. dwOffset = 0;
  725. dwLastUID = 0xFFFFFFFF;
  726. while (pEnd != pCur)
  727. {
  728. char chTemp[9], *pchend;
  729. chTemp[8] = '\0';
  730. // Read in the record
  731. MEMCPY (chTemp, pCur, 8);
  732. dwUID = strtol(chTemp, &pchend, 16);
  733. pCur += 8;
  734. pCur = StringToLong (pCur, &dwSize) + 1;
  735. BinFromHex (pCur, pBin, dwSize);
  736. pCur += dwSize + 2;
  737. dwSize /= 2;
  738. if (dwUID != dwLastUID)
  739. {
  740. if (FAILED (hr = RcFillHbt(hbt,(KEY)&dwUID,(QV)&dwOffset)))
  741. {
  742. delete pBin;
  743. goto exit0;
  744. }
  745. hr = pDataStream->Write (&dwSize, sizeof (DWORD), NULL);
  746. if (FAILED(hr))
  747. goto exit0;
  748. if (FAILED (hr = pDataStream->Write (pBin, dwSize, NULL)))
  749. goto exit0;
  750. dwLastUID = dwUID;
  751. }
  752. else
  753. { // What to do with duplicates?
  754. // For now, we skip them
  755. }
  756. dwOffset += dwSize + sizeof (DWORD);
  757. }
  758. hr = RcFiniFillHbt(hbt);
  759. if (FAILED(hr))
  760. goto exit0;
  761. if (S_OK !=(hr = RcCloseBtreeHbt(hbt)))
  762. goto exit0;
  763. hbt = NULL;
  764. // Create and write header
  765. IStream *pStream;
  766. hr = pStorage->CreateStream (SZ_BTREE_HEADER, STGM_WRITE, 0, 0, &pStream);
  767. if (FAILED(hr))
  768. goto exit0;
  769. hr = pStream->Write (m_pCatHeader, sizeof (DWORD), NULL);
  770. if (FAILED (hr))
  771. {
  772. pStream->Release();
  773. goto exit0;
  774. }
  775. hr = pStream->Write (m_pCatHeader + sizeof (DWORD),
  776. *((LPDWORD&)m_pCatHeader), NULL);
  777. pStream->Release();
  778. if (FAILED (hr))
  779. goto exit0;
  780. hr = S_OK;
  781. goto exit0;
  782. } /* CatalogCompleteUpdate */
  783. HRESULT WINAPI CITSvMgr::CatalogSetEntry (IITPropList *pPropList, DWORD dwFlags)
  784. {
  785. HRESULT hr;
  786. DWORD dwUID, dwTemp, dwDataSize;
  787. CProperty CProp;
  788. char szTemp[1025];
  789. if (FAILED(hr = pPropList->Get(STDPROP_UID, CProp)))
  790. return SetErrReturn(E_MISSINGPROP);
  791. // This could be a pointer to a UID or a DWORD UID
  792. if (TYPE_VALUE == CProp.dwType)
  793. dwUID = CProp.dwValue;
  794. else if (TYPE_POINTER == CProp.dwType)
  795. dwUID = *((LPDWORD&)CProp.lpvData);
  796. // Allocate memory if we need to
  797. if (NULL == m_pCatHeader)
  798. {
  799. pPropList->SetPersist(STDPROP_UID, FALSE);
  800. pPropList->GetHeaderSize (dwTemp);
  801. if (!dwTemp)
  802. // There are no document properties
  803. return S_OK;
  804. m_pCatHeader =
  805. (LPBYTE)_GLOBALALLOC (GMEM_FIXED, sizeof (DWORD) + dwTemp);
  806. if (NULL == m_pCatHeader)
  807. return SetErrReturn(E_OUTOFMEMORY);
  808. *((LPDWORD&)m_pCatHeader) = dwTemp;
  809. pPropList->SaveHeader (m_pCatHeader + sizeof (DWORD), dwTemp);
  810. // Don't permenantly change the persist state
  811. pPropList->SetPersist(STDPROP_UID, TRUE);
  812. }
  813. hr = pPropList->GetDataSize (m_pCatHeader + sizeof (DWORD),
  814. *((LPDWORD&)m_pCatHeader), dwDataSize);
  815. // Returns S_FALSE if no records to write (still writes empty bit flags)
  816. if (S_FALSE == hr || !dwDataSize)
  817. return S_OK;
  818. if ('\0' == *m_szCatFile)
  819. {
  820. // Create the temp file
  821. char szTempPath[_MAX_PATH + 1];
  822. if (0 == GetTempPath(_MAX_PATH, szTempPath))
  823. return SetErrReturn(E_FILECREATE);
  824. if (0 == GetTempFileName(szTempPath, "CAT", 0, m_szCatFile))
  825. return SetErrReturn(E_FILECREATE);
  826. m_hCatFile = CreateFile
  827. (m_szCatFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
  828. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  829. if (INVALID_HANDLE_VALUE == m_hCatFile)
  830. return SetErrReturn(E_FILECREATE);
  831. }
  832. LPBYTE pData;
  833. LPSTR pHex;
  834. pPropList->GetDataSize (m_pCatHeader + sizeof (DWORD),
  835. *((LPDWORD&)m_pCatHeader), dwDataSize);
  836. pData = new BYTE[dwDataSize];
  837. pHex = new char[dwDataSize * 2];
  838. if (dwDataSize > m_dwMaxPropSize)
  839. m_dwMaxPropSize = dwDataSize;
  840. pPropList->SaveData (m_pCatHeader + sizeof (DWORD),
  841. *((LPDWORD&)m_pCatHeader), pData, dwDataSize);
  842. HexFromBin (pHex, pData, dwDataSize);
  843. dwDataSize *= 2;
  844. wsprintf (szTemp, "%08X%u:", dwUID, dwDataSize);
  845. WriteFile (m_hCatFile, szTemp, (DWORD) STRLEN (szTemp), &dwTemp, NULL);
  846. WriteFile (m_hCatFile, pHex, dwDataSize, &dwTemp, NULL);
  847. WriteFile (m_hCatFile, "\r\n", (DWORD) STRLEN ("\r\n"), &dwTemp, NULL);
  848. delete pData;
  849. delete pHex;
  850. return S_OK;
  851. } /* CatalogSetEntry */
  852. /*******************************************************************
  853. *
  854. * @method HRESULT WINAPI | IITSvMgr | HashString |
  855. * Returns a hashed DWORD value for an input string.
  856. * This method is an optional advanced feature, and is
  857. * not necessary to build any object.
  858. *
  859. * @parm LPCWSTR | szKey | String to convert
  860. * @parm DWORD | *pdwHash | Hashed value of string
  861. *
  862. * @rvalue S_OK | The operation completed successfully.
  863. *
  864. * @comm
  865. * This method takes a string, and returns a hashed DWORD value.
  866. * For example, this method allows you to use hashstring values
  867. * as UIDs. It provides a unique value based on a title, for example.
  868. *
  869. * @comm Using the hash value as a UID in groups
  870. * can cause inefficiencies due to memory considerations
  871. * (non-sequential UIDs are more difficult to store).
  872. *
  873. *
  874. ********************************************************************/
  875. HRESULT WINAPI CITSvMgr::HashString (LPCWSTR szKey, DWORD *pdwHash)
  876. {
  877. int ich, cch;
  878. DWORD hash = 0L;
  879. const int MAX_CHARS = 43;
  880. *pdwHash = 0L;
  881. cch = (int) WSTRLEN (szKey);
  882. // The following is used to generate a hash value for structured
  883. // "ascii hex" context strings. If a title's context strings use
  884. // the format "0xHHHHHHHH", where H is a valid hex digit, then
  885. // this algorithm replaces the standard hash algorithm. This is so
  886. // title's can determined a context string from a given hash value.
  887. if ( szKey[0] == L'0' && szKey[1] == L'x' && (cch == 10) )
  888. {
  889. WCHAR c;
  890. for( ich = 0; ich < cch; ++ich )
  891. {
  892. c = szKey[ich];
  893. hash <<= 4;
  894. hash += (c & 0x10 ? c : (c + 9)) & 0x0f;
  895. }
  896. *pdwHash = hash;
  897. return S_OK;
  898. }
  899. for ( ich = 0; ich < cch; ++ich )
  900. {
  901. if ( szKey[ich] == L'!' )
  902. hash = (hash * MAX_CHARS) + 11;
  903. else if ( szKey[ich] == L'.' )
  904. hash = (hash * MAX_CHARS) + 12;
  905. else if ( szKey[ich] == L'_' )
  906. hash = (hash * MAX_CHARS) + 13;
  907. else if ( szKey[ich] == L'0' )
  908. hash = (hash * MAX_CHARS) + 10;
  909. else if ( szKey[ich] <= L'Z' )
  910. hash = (hash * MAX_CHARS) + ( szKey[ich] - L'0' );
  911. else
  912. hash = (hash * MAX_CHARS) + ( szKey[ich] - 'L0' - (L'a' - L'A') );
  913. }
  914. /* Since the value hashNil is reserved as a nil value, if any context
  915. * string actually hashes to this value, we just move it.
  916. */
  917. *pdwHash = (hash == hashNil ? hashNil + 1 : hash);
  918. return S_OK;
  919. } /* CITSvMgr::HashString */
  920. HRESULT WINAPI CITSvMgr::LogMessage(DWORD dwResourceId, ...)
  921. {
  922. if (!m_fInitialized || !m_piistmLog)
  923. return S_FALSE;
  924. char rgchLocalBuf[1024];
  925. char rgchFormatBuf[1024];
  926. if (LoadString (_hInstITCC, dwResourceId,
  927. rgchFormatBuf, 1024 * sizeof (char)))
  928. {
  929. va_list vl;
  930. va_start(vl, dwResourceId);
  931. int arg1 = va_arg(vl, int);
  932. int arg2 = va_arg(vl, int);
  933. int arg3 = va_arg(vl, int);
  934. va_end(vl);
  935. wsprintf (rgchLocalBuf, rgchFormatBuf, arg1, arg2, arg3);
  936. }
  937. else
  938. STRCPY(rgchLocalBuf, "Error string could not be loaded from resource file.");
  939. m_piistmLog->Write(rgchLocalBuf, (DWORD) STRLEN (rgchLocalBuf), NULL);
  940. m_piistmLog->Write (".\r\n", (DWORD) STRLEN (".\r\n"), NULL);
  941. return S_OK;
  942. } /* LogMessage */